summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp68
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h36
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp93
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h61
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp123
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h69
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp171
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h33
-rw-r--r--editor/plugins/animation_library_editor.cpp687
-rw-r--r--editor/plugins/animation_library_editor.h119
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp684
-rw-r--r--editor/plugins/animation_player_editor_plugin.h93
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp1530
-rw-r--r--editor/plugins/animation_state_machine_editor.h153
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp42
-rw-r--r--editor/plugins/animation_tree_editor_plugin.h22
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp302
-rw-r--r--editor/plugins/asset_library_editor_plugin.h132
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp63
-rw-r--r--editor/plugins/audio_stream_editor_plugin.h10
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.cpp121
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.h54
-rw-r--r--editor/plugins/bit_map_editor_plugin.cpp86
-rw-r--r--editor/plugins/bit_map_editor_plugin.h64
-rw-r--r--editor/plugins/camera_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/camera_3d_editor_plugin.h14
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp1657
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h348
-rw-r--r--editor/plugins/collision_polygon_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/collision_polygon_2d_editor_plugin.h10
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp32
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h20
-rw-r--r--editor/plugins/control_editor_plugin.cpp1013
-rw-r--r--editor/plugins/control_editor_plugin.h250
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp21
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.h31
-rw-r--r--editor/plugins/cpu_particles_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/cpu_particles_3d_editor_plugin.h11
-rw-r--r--editor/plugins/curve_editor_plugin.cpp58
-rw-r--r--editor/plugins/curve_editor_plugin.h11
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp39
-rw-r--r--editor/plugins/debugger_editor_plugin.h13
-rw-r--r--editor/plugins/editor_debugger_plugin.cpp4
-rw-r--r--editor/plugins/editor_debugger_plugin.h4
-rw-r--r--editor/plugins/editor_preview_plugins.cpp147
-rw-r--r--editor/plugins/editor_preview_plugins.h70
-rw-r--r--editor/plugins/font_editor_plugin.cpp24
-rw-r--r--editor/plugins/font_editor_plugin.h7
-rw-r--r--editor/plugins/gdextension_export_plugin.h138
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp52
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.h36
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp35
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.h36
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp116
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.h28
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp59
-rw-r--r--editor/plugins/gradient_editor_plugin.h23
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp284
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.h112
-rw-r--r--editor/plugins/input_event_editor_plugin.cpp44
-rw-r--r--editor/plugins/input_event_editor_plugin.h20
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp15
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.h10
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp30
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.h19
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/line_2d_editor_plugin.h10
-rw-r--r--editor/plugins/material_editor_plugin.cpp137
-rw-r--r--editor/plugins/material_editor_plugin.h42
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp34
-rw-r--r--editor/plugins/mesh_editor_plugin.h23
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp26
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.h24
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp37
-rw-r--r--editor/plugins/mesh_library_editor_plugin.h32
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp27
-rw-r--r--editor/plugins/multimesh_editor_plugin.h45
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.cpp15
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.h10
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp658
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h183
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp2696
-rw-r--r--editor/plugins/node_3d_editor_plugin.h248
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.cpp24
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.h16
-rw-r--r--editor/plugins/ot_features_plugin.cpp94
-rw-r--r--editor/plugins/ot_features_plugin.h19
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp15
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.h8
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp52
-rw-r--r--editor/plugins/path_2d_editor_plugin.h44
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp93
-rw-r--r--editor/plugins/path_3d_editor_plugin.h35
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.cpp14
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.h19
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp102
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h68
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp (renamed from editor/plugins/collision_polygon_3d_editor_plugin.cpp)143
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.h (renamed from editor/plugins/collision_polygon_3d_editor_plugin.h)58
-rw-r--r--editor/plugins/ray_cast_2d_editor_plugin.cpp151
-rw-r--r--editor/plugins/ray_cast_2d_editor_plugin.h79
-rw-r--r--editor/plugins/replication_editor_plugin.cpp396
-rw-r--r--editor/plugins/replication_editor_plugin.h105
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp53
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.h29
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp29
-rw-r--r--editor/plugins/root_motion_editor_plugin.h14
-rw-r--r--editor/plugins/script_editor_plugin.cpp689
-rw-r--r--editor/plugins/script_editor_plugin.h147
-rw-r--r--editor/plugins/script_text_editor.cpp285
-rw-r--r--editor/plugins/script_text_editor.h66
-rw-r--r--editor/plugins/shader_editor_plugin.cpp125
-rw-r--r--editor/plugins/shader_editor_plugin.h39
-rw-r--r--editor/plugins/shader_file_editor_plugin.cpp37
-rw-r--r--editor/plugins/shader_file_editor_plugin.h21
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp30
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.h18
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp89
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h44
-rw-r--r--editor/plugins/skeleton_ik_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/skeleton_ik_3d_editor_plugin.h12
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp46
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.h31
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp398
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h110
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp13
-rw-r--r--editor/plugins/style_box_editor_plugin.h12
-rw-r--r--editor/plugins/sub_viewport_preview_editor_plugin.cpp6
-rw-r--r--editor/plugins/sub_viewport_preview_editor_plugin.h7
-rw-r--r--editor/plugins/text_control_editor_plugin.cpp660
-rw-r--r--editor/plugins/text_control_editor_plugin.h115
-rw-r--r--editor/plugins/text_editor.cpp49
-rw-r--r--editor/plugins/text_editor.h10
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp31
-rw-r--r--editor/plugins/texture_3d_editor_plugin.h14
-rw-r--r--editor/plugins/texture_editor_plugin.cpp18
-rw-r--r--editor/plugins/texture_editor_plugin.h7
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp33
-rw-r--r--editor/plugins/texture_layered_editor_plugin.h14
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp88
-rw-r--r--editor/plugins/texture_region_editor_plugin.h68
-rw-r--r--editor/plugins/theme_editor_plugin.cpp791
-rw-r--r--editor/plugins/theme_editor_plugin.h256
-rw-r--r--editor/plugins/theme_editor_preview.cpp36
-rw-r--r--editor/plugins/theme_editor_preview.h35
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp18
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.h24
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp94
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h49
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp300
-rw-r--r--editor/plugins/tiles/tile_data_editors.h72
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp288
-rw-r--r--editor/plugins/tiles/tile_map_editor.h124
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp9
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.h28
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp254
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h109
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp82
-rw-r--r--editor/plugins/tiles/tile_set_editor.h37
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp33
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.h32
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp153
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.h45
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp55
-rw-r--r--editor/plugins/version_control_editor_plugin.h83
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2892
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h157
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp81
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.h20
169 files changed, 16661 insertions, 8456 deletions
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 36a814c30a..ad6d8e6379 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,6 +33,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const {
@@ -147,12 +148,16 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) {
void AbstractPolygon2DEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ button_create->set_icon(get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
+ button_edit->set_icon(get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
+ button_delete->set_icon(get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
+ } break;
+
case NOTIFICATION_READY: {
disable_polygon_editing(false, String());
- button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
- button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
- button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
button_edit->set_pressed(true);
get_tree()->connect("node_removed", callable_mp(this, &AbstractPolygon2DEditor::_node_removed));
@@ -242,14 +247,18 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return false;
}
+ if (!_get_node()->is_visible_in_tree()) {
+ return false;
+ }
+
Ref<InputEventMouseButton> mb = p_event;
if (!_has_resource()) {
- if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
create_resource->set_text(String("No polygon resource on this node.\nCreate and assign one?"));
create_resource->popup_centered();
}
- return (mb.is_valid() && mb->get_button_index() == 1);
+ return (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT);
}
CanvasItemEditor::Tool tool = CanvasItemEditor::get_singleton()->get_current_tool();
@@ -264,7 +273,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Vector2 cpoint = _get_node()->to_local(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (mb->is_ctrl_pressed() || mb->is_shift_pressed() || mb->is_alt_pressed()) {
return false;
@@ -283,15 +292,14 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
_commit_action();
return true;
} else {
- Vector<Vector2> vertices2 = _get_polygon(insert.polygon);
- pre_move_edit = vertices2;
+ pre_move_edit = vertices;
edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos));
- vertices2.insert(edited_point.vertex, edited_point.pos);
+ vertices.insert(edited_point.vertex, edited_point.pos);
selected_point = Vertex(edited_point.polygon, edited_point.vertex);
edge_point = PosVertex();
undo_redo->create_action(TTR("Insert Point"));
- _action_set_polygon(insert.polygon, vertices2);
+ _action_set_polygon(insert.polygon, vertices);
_commit_action();
return true;
}
@@ -326,7 +334,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && !edited_point.valid()) {
const PosVertex closest = closest_point(gpoint);
if (closest.valid()) {
@@ -335,7 +343,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
}
} else if (mode == MODE_DELETE) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
const PosVertex closest = closest_point(gpoint);
if (closest.valid()) {
@@ -346,7 +354,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
if (mode == MODE_CREATE) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
if (_is_line()) {
// for lines, we don't have a wip mode, and we can undo each single add point.
Vector<Vector2> vertices = _get_polygon(0);
@@ -384,7 +392,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && wip_active) {
_wip_cancel();
}
}
@@ -395,7 +403,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (mm.is_valid()) {
Vector2 gpoint = mm->get_position();
- if (edited_point.valid() && (wip_active || (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT))) {
+ if (edited_point.valid() && (wip_active || (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE)) {
Vector2 cpoint = _get_node()->to_local(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)));
//Move the point in a single axis. Should only work when editing a polygon and while holding shift.
@@ -443,10 +451,10 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed()) {
- if (k->get_keycode() == KEY_DELETE || k->get_keycode() == KEY_BACKSPACE) {
+ if (k->get_keycode() == Key::KEY_DELETE || k->get_keycode() == Key::BACKSPACE) {
if (wip_active && selected_point.polygon == -1) {
if (wip.size() > selected_point.vertex) {
- wip.remove(selected_point.vertex);
+ wip.remove_at(selected_point.vertex);
_wip_changed();
selected_point = wip.size() - 1;
canvas_item_editor->update_viewport();
@@ -460,9 +468,9 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
- } else if (wip_active && k->get_keycode() == KEY_ENTER) {
+ } else if (wip_active && k->get_keycode() == Key::ENTER) {
_wip_close();
- } else if (wip_active && k->get_keycode() == KEY_ESCAPE) {
+ } else if (wip_active && k->get_keycode() == Key::ESCAPE) {
_wip_cancel();
}
}
@@ -475,6 +483,10 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
return;
}
+ if (!_get_node()->is_visible_in_tree()) {
+ return;
+ }
+
Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform();
// All polygon points are sharp, so use the sharp handle icon
const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorPathSharpHandle"), SNAME("EditorIcons"));
@@ -554,7 +566,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
String num = String::num(vertex.vertex);
Size2 num_size = font->get_string_size(num, font_size);
- p_overlay->draw_string(font, point - num_size * 0.5, num, HALIGN_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5));
+ p_overlay->draw_string(font, point - num_size * 0.5, num, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5));
}
}
}
@@ -599,7 +611,7 @@ void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) {
Vector<Vector2> vertices = _get_polygon(p_vertex.polygon);
if (vertices.size() > (_is_line() ? 2 : 3)) {
- vertices.remove(p_vertex.vertex);
+ vertices.remove_at(p_vertex.vertex);
undo_redo->create_action(TTR("Edit Polygon (Remove Point)"));
_action_set_polygon(p_vertex.polygon, vertices);
@@ -690,12 +702,9 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(c
return closest;
}
-AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive) {
- canvas_item_editor = nullptr;
- editor = p_editor;
+AbstractPolygon2DEditor::AbstractPolygon2DEditor(bool p_wip_destructive) {
undo_redo = EditorNode::get_undo_redo();
- wip_active = false;
edited_point = PosVertex();
wip_destructive = p_wip_destructive;
@@ -725,8 +734,6 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi
create_resource = memnew(ConfirmationDialog);
add_child(create_resource);
create_resource->get_ok_button()->set_text(TTR("Create"));
-
- mode = MODE_EDIT;
}
void AbstractPolygon2DEditorPlugin::edit(Object *p_object) {
@@ -746,9 +753,8 @@ void AbstractPolygon2DEditorPlugin::make_visible(bool p_visible) {
}
}
-AbstractPolygon2DEditorPlugin::AbstractPolygon2DEditorPlugin(EditorNode *p_node, AbstractPolygon2DEditor *p_polygon_editor, String p_class) :
+AbstractPolygon2DEditorPlugin::AbstractPolygon2DEditorPlugin(AbstractPolygon2DEditor *p_polygon_editor, String p_class) :
polygon_editor(p_polygon_editor),
- editor(p_node),
klass(p_class) {
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(polygon_editor);
polygon_editor->hide();
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index 5fea8b75d6..696fd7b637 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,18 +31,18 @@
#ifndef ABSTRACT_POLYGON_2D_EDITOR_H
#define ABSTRACT_POLYGON_2D_EDITOR_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/polygon_2d.h"
+#include "scene/gui/box_container.h"
class CanvasItemEditor;
class AbstractPolygon2DEditor : public HBoxContainer {
GDCLASS(AbstractPolygon2DEditor, HBoxContainer);
- Button *button_create;
- Button *button_edit;
- Button *button_delete;
+ Button *button_create = nullptr;
+ Button *button_edit = nullptr;
+ Button *button_delete = nullptr;
struct Vertex {
Vertex() {}
@@ -80,15 +80,14 @@ class AbstractPolygon2DEditor : public HBoxContainer {
Vector<Vector2> pre_move_edit;
Vector<Vector2> wip;
- bool wip_active;
- bool wip_destructive;
+ bool wip_active = false;
+ bool wip_destructive = false;
- bool _polygon_editing_enabled;
+ bool _polygon_editing_enabled = false;
- CanvasItemEditor *canvas_item_editor;
- EditorNode *editor;
- Panel *panel;
- ConfirmationDialog *create_resource;
+ CanvasItemEditor *canvas_item_editor = nullptr;
+ Panel *panel = nullptr;
+ ConfirmationDialog *create_resource = nullptr;
protected:
enum {
@@ -98,9 +97,9 @@ protected:
MODE_CONT,
};
- int mode;
+ int mode = MODE_EDIT;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
virtual void _menu_option(int p_option);
void _wip_changed();
@@ -144,14 +143,13 @@ public:
void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(Node *p_polygon);
- AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive = true);
+ AbstractPolygon2DEditor(bool p_wip_destructive = true);
};
class AbstractPolygon2DEditorPlugin : public EditorPlugin {
GDCLASS(AbstractPolygon2DEditorPlugin, EditorPlugin);
- AbstractPolygon2DEditor *polygon_editor;
- EditorNode *editor;
+ AbstractPolygon2DEditor *polygon_editor = nullptr;
String klass;
public:
@@ -164,7 +162,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- AbstractPolygon2DEditorPlugin(EditorNode *p_node, AbstractPolygon2DEditor *p_polygon_editor, String p_class);
+ AbstractPolygon2DEditorPlugin(AbstractPolygon2DEditor *p_polygon_editor, String p_class);
~AbstractPolygon2DEditorPlugin();
};
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index ad2d9866fa..ae4482155c 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,6 +31,8 @@
#include "animation_blend_space_1d_editor.h"
#include "core/os/keyboard.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/animation/animation_blend_tree.h"
@@ -42,7 +44,7 @@ StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && !k->is_echo()) {
+ if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1) {
_erase_selected();
accept_event();
@@ -51,7 +53,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && tool_create->is_pressed()))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -86,7 +88,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
int idx = menu->get_item_count();
- menu->add_item(vformat("Add %s", name), idx);
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
menu->set_item_metadata(idx, E);
}
@@ -98,7 +100,8 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
menu->add_separator();
menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_position(blend_space_draw->get_screen_transform().xform(mb->get_position()));
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
menu->popup();
add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
@@ -110,7 +113,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
blend_space_draw->update(); // why not
// try to see if a point can be selected
@@ -132,7 +135,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
if (dragging_selected) {
// move
float point = blend_space->get_blend_point_position(selected_point);
@@ -161,7 +164,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
// *set* the blend
- if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
float blend_pos = mb->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
@@ -184,7 +187,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
_update_edited_point_pos();
}
- if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && tool_blend->is_pressed() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
float blend_pos = mm->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
@@ -222,7 +225,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
float x = point;
blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor);
- blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HALIGN_LEFT, -1, font_size, linecolor);
+ blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor);
blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft);
}
@@ -528,39 +531,42 @@ void AnimationNodeBlendSpace1DEditor::_open_editor() {
}
void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- tool_blend->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
- tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
- tool_create->set_icon(get_theme_icon(SNAME("EditKey"), SNAME("EditorIcons")));
- tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
- open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- }
-
- if (p_what == NOTIFICATION_PROCESS) {
- String error;
-
- if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
- error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
- error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
- }
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ tool_blend->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
+ tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
+ tool_create->set_icon(get_theme_icon(SNAME("EditKey"), SNAME("EditorIcons")));
+ tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
+ open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ } break;
+
+ case NOTIFICATION_PROCESS: {
+ String error;
+
+ if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
+ error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
+ }
- if (error != error_label->get_text()) {
- error_label->set_text(error);
- if (error != String()) {
- error_panel->show();
- } else {
- error_panel->hide();
+ if (error != error_label->get_text()) {
+ error_label->set_text(error);
+ if (!error.is_empty()) {
+ error_panel->show();
+ } else {
+ error_panel->hide();
+ }
}
- }
- }
+ } break;
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- set_process(is_visible_in_tree());
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ set_process(is_visible_in_tree());
+ } break;
}
}
@@ -588,7 +594,6 @@ AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nu
AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
singleton = this;
- updating = false;
HBoxContainer *top_hb = memnew(HBoxContainer);
add_child(top_hb);
@@ -739,9 +744,5 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_file_opened));
undo_redo = EditorNode::get_undo_redo();
- selected_point = -1;
- dragging_selected = false;
- dragging_selected_attempt = false;
-
set_custom_minimum_size(Size2(0, 150 * EDSCALE));
}
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index 503e066894..2f7dee65fc 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef ANIMATION_BLEND_SPACE_1D_EDITOR_H
#define ANIMATION_BLEND_SPACE_1D_EDITOR_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
@@ -46,36 +45,36 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeBlendSpace1D> blend_space;
- HBoxContainer *goto_parent_hb;
- Button *goto_parent;
+ HBoxContainer *goto_parent_hb = nullptr;
+ Button *goto_parent = nullptr;
- PanelContainer *panel;
- Button *tool_blend;
- Button *tool_select;
- Button *tool_create;
- VSeparator *tool_erase_sep;
- Button *tool_erase;
- Button *snap;
- SpinBox *snap_value;
+ PanelContainer *panel = nullptr;
+ Button *tool_blend = nullptr;
+ Button *tool_select = nullptr;
+ Button *tool_create = nullptr;
+ VSeparator *tool_erase_sep = nullptr;
+ Button *tool_erase = nullptr;
+ Button *snap = nullptr;
+ SpinBox *snap_value = nullptr;
- LineEdit *label_value;
- SpinBox *max_value;
- SpinBox *min_value;
+ LineEdit *label_value = nullptr;
+ SpinBox *max_value = nullptr;
+ SpinBox *min_value = nullptr;
- HBoxContainer *edit_hb;
- SpinBox *edit_value;
- Button *open_editor;
+ HBoxContainer *edit_hb = nullptr;
+ SpinBox *edit_value = nullptr;
+ Button *open_editor = nullptr;
- int selected_point;
+ int selected_point = -1;
- Control *blend_space_draw;
+ Control *blend_space_draw = nullptr;
- PanelContainer *error_panel;
- Label *error_label;
+ PanelContainer *error_panel = nullptr;
+ Label *error_label = nullptr;
- bool updating;
+ bool updating = false;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
static AnimationNodeBlendSpace1DEditor *singleton;
@@ -88,14 +87,14 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
void _labels_changed(String);
void _snap_toggled();
- PopupMenu *menu;
- PopupMenu *animations_menu;
+ PopupMenu *menu = nullptr;
+ PopupMenu *animations_menu = nullptr;
Vector<String> animations_to_add;
- float add_point_pos;
+ float add_point_pos = 0.0f;
Vector<real_t> points;
- bool dragging_selected_attempt;
- bool dragging_selected;
+ bool dragging_selected_attempt = false;
+ bool dragging_selected = false;
Vector2 drag_from;
Vector2 drag_ofs;
@@ -109,7 +108,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
void _edit_point_pos(double);
void _open_editor();
- EditorFileDialog *open_file;
+ EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 686a35e442..4b7df75aec 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -35,6 +35,8 @@
#include "core/io/resource_loader.h"
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
@@ -70,7 +72,7 @@ StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && !k->is_echo()) {
+ if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1 || selected_triangle != -1) {
_erase_selected();
accept_event();
@@ -79,7 +81,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && tool_create->is_pressed()))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -109,7 +111,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
continue; // nope
}
int idx = menu->get_item_count();
- menu->add_item(vformat("Add %s", name), idx);
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
menu->set_item_metadata(idx, E);
}
@@ -121,7 +123,8 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
menu->add_separator();
menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_position(blend_space_draw->get_screen_transform().xform(mb->get_position()));
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
menu->popup();
add_point_pos = (mb->get_position() / blend_space_draw->get_size());
add_point_pos.y = 1.0 - add_point_pos.y;
@@ -133,7 +136,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
blend_space_draw->update(); //update anyway
//try to see if a point can be selected
selected_point = -1;
@@ -173,13 +176,13 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
blend_space_draw->update(); //update anyway
//try to see if a point can be selected
selected_point = -1;
for (int i = 0; i < points.size(); i++) {
- if (making_triangle.find(i) != -1) {
+ if (making_triangle.has(i)) {
continue;
}
@@ -208,7 +211,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
if (dragging_selected) {
//move
Vector2 point = blend_space->get_blend_point_position(selected_point);
@@ -234,7 +237,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_space_draw->update();
}
- if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Vector2 blend_pos = (mb->get_position() / blend_space_draw->get_size());
blend_pos.y = 1.0 - blend_pos.y;
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
@@ -268,7 +271,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_space_draw->update();
}
- if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && tool_blend->is_pressed() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
Vector2 blend_pos = (mm->get_position() / blend_space_draw->get_size());
blend_pos.y = 1.0 - blend_pos.y;
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
@@ -411,14 +414,14 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
if (blend_space->get_min_space().y < 0) {
int y = (blend_space->get_max_space().y / (blend_space->get_max_space().y - blend_space->get_min_space().y)) * s.height;
blend_space_draw->draw_line(Point2(0, y), Point2(5 * EDSCALE, y), linecolor);
- blend_space_draw->draw_string(font, Point2(2 * EDSCALE, y - font->get_height(font_size) + font->get_ascent(font_size)), "0", HALIGN_LEFT, -1, font_size, linecolor);
+ blend_space_draw->draw_string(font, Point2(2 * EDSCALE, y - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor);
blend_space_draw->draw_line(Point2(5 * EDSCALE, y), Point2(s.width, y), linecolor_soft);
}
if (blend_space->get_min_space().x < 0) {
int x = (-blend_space->get_min_space().x / (blend_space->get_max_space().x - blend_space->get_min_space().x)) * s.width;
blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor);
- blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HALIGN_LEFT, -1, font_size, linecolor);
+ blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor);
blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft);
}
@@ -487,10 +490,11 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
color.a *= 0.2;
}
- Vector<Color> colors;
- colors.push_back(color);
- colors.push_back(color);
- colors.push_back(color);
+ Vector<Color> colors = {
+ color,
+ color,
+ color
+ };
blend_space_draw->draw_primitive(points, colors, Vector<Vector2>());
}
@@ -727,49 +731,52 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
}
void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- tool_blend->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
- tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
- tool_create->set_icon(get_theme_icon(SNAME("EditKey"), SNAME("EditorIcons")));
- tool_triangle->set_icon(get_theme_icon(SNAME("ToolTriangle"), SNAME("EditorIcons")));
- tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
- open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- auto_triangles->set_icon(get_theme_icon(SNAME("AutoTriangle"), SNAME("EditorIcons")));
- interpolation->clear();
- interpolation->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), "", 0);
- interpolation->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), "", 1);
- interpolation->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), "", 2);
- }
-
- if (p_what == NOTIFICATION_PROCESS) {
- String error;
-
- if (!AnimationTreeEditor::get_singleton()->get_tree()) {
- error = TTR("BlendSpace2D does not belong to an AnimationTree node.");
- } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
- error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
- error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
- } else if (blend_space->get_triangle_count() == 0) {
- error = TTR("No triangles exist, so no blending can take place.");
- }
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ tool_blend->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
+ tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
+ tool_create->set_icon(get_theme_icon(SNAME("EditKey"), SNAME("EditorIcons")));
+ tool_triangle->set_icon(get_theme_icon(SNAME("ToolTriangle"), SNAME("EditorIcons")));
+ tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
+ open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ auto_triangles->set_icon(get_theme_icon(SNAME("AutoTriangle"), SNAME("EditorIcons")));
+ interpolation->clear();
+ interpolation->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), "", 0);
+ interpolation->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), "", 1);
+ interpolation->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), "", 2);
+ } break;
+
+ case NOTIFICATION_PROCESS: {
+ String error;
+
+ if (!AnimationTreeEditor::get_singleton()->get_tree()) {
+ error = TTR("BlendSpace2D does not belong to an AnimationTree node.");
+ } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
+ error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
+ } else if (blend_space->get_triangle_count() == 0) {
+ error = TTR("No triangles exist, so no blending can take place.");
+ }
- if (error != error_label->get_text()) {
- error_label->set_text(error);
- if (error != String()) {
- error_panel->show();
- } else {
- error_panel->hide();
+ if (error != error_label->get_text()) {
+ error_label->set_text(error);
+ if (!error.is_empty()) {
+ error_panel->show();
+ } else {
+ error_panel->hide();
+ }
}
- }
- }
+ } break;
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- set_process(is_visible_in_tree());
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ set_process(is_visible_in_tree());
+ } break;
}
}
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index 3b8b78b2b5..db54e84254 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef ANIMATION_BLEND_SPACE_2D_EDITOR_H
#define ANIMATION_BLEND_SPACE_2D_EDITOR_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
@@ -46,43 +45,43 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeBlendSpace2D> blend_space;
- PanelContainer *panel;
- Button *tool_blend;
- Button *tool_select;
- Button *tool_create;
- Button *tool_triangle;
- VSeparator *tool_erase_sep;
- Button *tool_erase;
- Button *snap;
- SpinBox *snap_x;
- SpinBox *snap_y;
- OptionButton *interpolation;
-
- Button *auto_triangles;
-
- LineEdit *label_x;
- LineEdit *label_y;
- SpinBox *max_x_value;
- SpinBox *min_x_value;
- SpinBox *max_y_value;
- SpinBox *min_y_value;
-
- HBoxContainer *edit_hb;
- SpinBox *edit_x;
- SpinBox *edit_y;
- Button *open_editor;
+ PanelContainer *panel = nullptr;
+ Button *tool_blend = nullptr;
+ Button *tool_select = nullptr;
+ Button *tool_create = nullptr;
+ Button *tool_triangle = nullptr;
+ VSeparator *tool_erase_sep = nullptr;
+ Button *tool_erase = nullptr;
+ Button *snap = nullptr;
+ SpinBox *snap_x = nullptr;
+ SpinBox *snap_y = nullptr;
+ OptionButton *interpolation = nullptr;
+
+ Button *auto_triangles = nullptr;
+
+ LineEdit *label_x = nullptr;
+ LineEdit *label_y = nullptr;
+ SpinBox *max_x_value = nullptr;
+ SpinBox *min_x_value = nullptr;
+ SpinBox *max_y_value = nullptr;
+ SpinBox *min_y_value = nullptr;
+
+ HBoxContainer *edit_hb = nullptr;
+ SpinBox *edit_x = nullptr;
+ SpinBox *edit_y = nullptr;
+ Button *open_editor = nullptr;
int selected_point;
int selected_triangle;
- Control *blend_space_draw;
+ Control *blend_space_draw = nullptr;
- PanelContainer *error_panel;
- Label *error_label;
+ PanelContainer *error_panel = nullptr;
+ Label *error_label = nullptr;
bool updating;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
static AnimationNodeBlendSpace2DEditor *singleton;
@@ -95,8 +94,8 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
void _labels_changed(String);
void _snap_toggled();
- PopupMenu *menu;
- PopupMenu *animations_menu;
+ PopupMenu *menu = nullptr;
+ PopupMenu *animations_menu = nullptr;
Vector<String> animations_to_add;
Vector2 add_point_pos;
Vector<Vector2> points;
@@ -124,7 +123,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
StringName get_blend_position_path() const;
- EditorFileDialog *open_file;
+ EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 55ffbf9477..0b3164aada 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -34,12 +34,15 @@
#include "core/input/input.h"
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
+#include "editor/editor_file_dialog.h"
#include "editor/editor_inspector.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/gui/progress_bar.h"
+#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) {
@@ -58,7 +61,7 @@ void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const R
void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_script) {
for (int i = 0; i < add_options.size(); i++) {
if (add_options[i].script == p_script) {
- add_options.remove(i);
+ add_options.remove_at(i);
return;
}
}
@@ -68,7 +71,7 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip
void AnimationNodeBlendTreeEditor::_update_options_menu(bool p_has_input_ports) {
add_node->get_popup()->clear();
- add_node->get_popup()->set_size(Size2i(-1, -1));
+ add_node->get_popup()->reset_size();
for (int i = 0; i < add_options.size(); i++) {
if (p_has_input_ports && add_options[i].input_port_count == 0) {
continue;
@@ -83,7 +86,7 @@ void AnimationNodeBlendTreeEditor::_update_options_menu(bool p_has_input_ports)
}
add_node->get_popup()->add_separator();
add_node->get_popup()->add_item(TTR("Load..."), MENU_LOAD_FILE);
- use_popup_menu_position = false;
+ use_position_from_popup_menu = false;
}
Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
@@ -103,7 +106,7 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert
}
void AnimationNodeBlendTreeEditor::_update_graph() {
- if (updating) {
+ if (updating || blend_tree.is_null()) {
return;
}
@@ -292,14 +295,14 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
anode = EditorSettings::get_singleton()->get_resource_clipboard();
ERR_FAIL_COND(!anode.is_valid());
base_name = anode->get_class();
- } else if (add_options[p_idx].type != String()) {
+ } else if (!add_options[p_idx].type.is_empty()) {
AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(add_options[p_idx].type));
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
base_name = add_options[p_idx].name;
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
- String base_type = add_options[p_idx].script->get_instance_base_type();
+ StringName base_type = add_options[p_idx].script->get_instance_base_type();
AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(base_type));
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
@@ -319,8 +322,8 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
}
Point2 instance_pos = graph->get_scroll_ofs();
- if (use_popup_menu_position) {
- instance_pos += popup_menu_position;
+ if (use_position_from_popup_menu) {
+ instance_pos += position_from_popup_menu;
} else {
instance_pos += graph->get_size() * 0.5;
}
@@ -355,14 +358,15 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2 &p_popup_position, const Vector2 &p_node_position) {
_update_options_menu(p_has_input_ports);
- use_popup_menu_position = true;
- popup_menu_position = p_popup_position;
- add_node->get_popup()->set_position(p_node_position);
+ use_position_from_popup_menu = true;
+ position_from_popup_menu = p_node_position;
+ add_node->get_popup()->set_position(p_popup_position);
+ add_node->get_popup()->reset_size();
add_node->get_popup()->popup();
}
void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
- _popup(false, graph->get_local_mouse_position(), p_position);
+ _popup(false, graph->get_screen_position() + graph->get_local_mouse_position(), p_position);
}
void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
@@ -599,7 +603,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
String accum;
for (int i = 0; i < path.get_name_count(); i++) {
String name = path.get_name(i);
- if (accum != String()) {
+ if (!accum.is_empty()) {
accum += "/";
}
accum += name;
@@ -730,75 +734,95 @@ void AnimationNodeBlendTreeEditor::_removed_from_graph() {
}
}
+void AnimationNodeBlendTreeEditor::_update_editor_settings() {
+ graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
+}
+
+void AnimationNodeBlendTreeEditor::_update_theme() {
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+}
+
void AnimationNodeBlendTreeEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_editor_settings();
+ _update_theme();
+ } break;
- if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) {
- _update_graph();
- }
- }
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ _update_editor_settings();
+ } break;
- if (p_what == NOTIFICATION_PROCESS) {
- String error;
+ case NOTIFICATION_THEME_CHANGED: {
+ _update_theme();
- if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
- error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
- error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
- }
+ if (is_visible_in_tree()) {
+ _update_graph();
+ }
+ } break;
- if (error != error_label->get_text()) {
- error_label->set_text(error);
- if (error != String()) {
- error_panel->show();
- } else {
- error_panel->hide();
+ case NOTIFICATION_PROCESS: {
+ String error;
+
+ if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
+ error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
}
- }
- List<AnimationNodeBlendTree::NodeConnection> conns;
- blend_tree->get_node_connections(&conns);
- for (const AnimationNodeBlendTree::NodeConnection &E : conns) {
- float activity = 0;
- StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node;
- if (AnimationTreeEditor::get_singleton()->get_tree() && !AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
- activity = AnimationTreeEditor::get_singleton()->get_tree()->get_connection_activity(path, E.input_index);
+ if (error != error_label->get_text()) {
+ error_label->set_text(error);
+ if (!error.is_empty()) {
+ error_panel->show();
+ } else {
+ error_panel->hide();
+ }
}
- graph->set_connection_activity(E.output_node, 0, E.input_node, E.input_index, activity);
- }
- AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree();
- AnimationPlayer *player = nullptr;
- if (graph_player->has_node(graph_player->get_animation_player())) {
- player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player()));
- }
+ List<AnimationNodeBlendTree::NodeConnection> conns;
+ blend_tree->get_node_connections(&conns);
+ for (const AnimationNodeBlendTree::NodeConnection &E : conns) {
+ float activity = 0;
+ StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node;
+ if (AnimationTreeEditor::get_singleton()->get_tree() && !AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ activity = AnimationTreeEditor::get_singleton()->get_tree()->get_connection_activity(path, E.input_index);
+ }
+ graph->set_connection_activity(E.output_node, 0, E.input_node, E.input_index, activity);
+ }
+
+ AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree();
+ AnimationPlayer *player = nullptr;
+ if (graph_player->has_node(graph_player->get_animation_player())) {
+ player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player()));
+ }
- if (player) {
- for (const KeyValue<StringName, ProgressBar *> &E : animations) {
- Ref<AnimationNodeAnimation> an = blend_tree->get_node(E.key);
- if (an.is_valid()) {
- if (player->has_animation(an->get_animation())) {
- Ref<Animation> anim = player->get_animation(an->get_animation());
- if (anim.is_valid()) {
- E.value->set_max(anim->get_length());
- //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node;
- StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/time";
- E.value->set_value(AnimationTreeEditor::get_singleton()->get_tree()->get(time_path));
+ if (player) {
+ for (const KeyValue<StringName, ProgressBar *> &E : animations) {
+ Ref<AnimationNodeAnimation> an = blend_tree->get_node(E.key);
+ if (an.is_valid()) {
+ if (player->has_animation(an->get_animation())) {
+ Ref<Animation> anim = player->get_animation(an->get_animation());
+ if (anim.is_valid()) {
+ E.value->set_max(anim->get_length());
+ //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node;
+ StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/time";
+ E.value->set_value(AnimationTreeEditor::get_singleton()->get_tree()->get(time_path));
+ }
}
}
}
}
- }
- for (int i = 0; i < visible_properties.size(); i++) {
- visible_properties[i]->update_property();
- }
- }
+ for (int i = 0; i < visible_properties.size(); i++) {
+ visible_properties[i]->update_property();
+ }
+ } break;
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- set_process(is_visible_in_tree());
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ set_process(is_visible_in_tree());
+ } break;
}
}
@@ -820,13 +844,13 @@ AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = nullptr;
void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<AnimationNode> p_node) {
String prev_name = blend_tree->get_node_name(p_node);
- ERR_FAIL_COND(prev_name == String());
+ ERR_FAIL_COND(prev_name.is_empty());
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(prev_name));
ERR_FAIL_COND(!gn);
const String &new_name = p_text;
- ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1);
+ ERR_FAIL_COND(new_name.is_empty() || new_name.contains(".") || new_name.contains("/"));
if (new_name == prev_name) {
return; //nothing to do
@@ -891,6 +915,9 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
}
void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) {
+ if (le == nullptr) {
+ return; // The text_submitted signal triggered the graph update and freed the LineEdit.
+ }
_node_renamed(le->call("get_text"), p_node);
}
@@ -918,7 +945,7 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
singleton = this;
updating = false;
- use_popup_menu_position = false;
+ use_position_from_popup_menu = false;
graph = memnew(GraphEdit);
add_child(graph);
@@ -945,7 +972,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
add_node->set_text(TTR("Add Node..."));
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node));
- add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu));
+ add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu), varray(false));
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot", 2));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 0fcafad40e..cacf8379f9 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H
#define ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
@@ -42,24 +41,25 @@
#include "scene/gui/tree.h"
class ProgressBar;
+class EditorFileDialog;
class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
- GraphEdit *graph;
- MenuButton *add_node;
- Vector2 popup_menu_position;
- bool use_popup_menu_position;
+ GraphEdit *graph = nullptr;
+ MenuButton *add_node = nullptr;
+ Vector2 position_from_popup_menu;
+ bool use_position_from_popup_menu;
- PanelContainer *error_panel;
- Label *error_label;
+ PanelContainer *error_panel = nullptr;
+ Label *error_label = nullptr;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
- AcceptDialog *filter_dialog;
- Tree *filters;
- CheckBox *filter_enabled;
+ AcceptDialog *filter_dialog = nullptr;
+ Tree *filters = nullptr;
+ CheckBox *filter_enabled = nullptr;
Map<StringName, ProgressBar *> animations;
Vector<EditorProperty *> visible_properties;
@@ -75,7 +75,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
String type;
Ref<Script> script;
int input_port_count;
- AddOption(const String &p_name = String(), const String &p_type = String(), bool p_input_port_count = 0) :
+ AddOption(const String &p_name = String(), const String &p_type = String(), int p_input_port_count = 0) :
name(p_name),
type(p_type),
input_port_count(p_input_port_count) {
@@ -119,7 +119,10 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
void _removed_from_graph();
- EditorFileDialog *open_file;
+ void _update_editor_settings();
+ void _update_theme();
+
+ EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
new file mode 100644
index 0000000000..581c3c05a5
--- /dev/null
+++ b/editor/plugins/animation_library_editor.cpp
@@ -0,0 +1,687 @@
+/*************************************************************************/
+/* animation_library_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "animation_library_editor.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+
+void AnimationLibraryEditor::set_animation_player(Object *p_player) {
+ player = p_player;
+}
+
+void AnimationLibraryEditor::_add_library() {
+ add_library_dialog->set_title(TTR("Library Name:"));
+ add_library_name->set_text("");
+ add_library_dialog->popup_centered();
+ add_library_name->grab_focus();
+ adding_animation = false;
+ adding_animation_to_library = StringName();
+ _add_library_validate("");
+}
+
+void AnimationLibraryEditor::_add_library_validate(const String &p_name) {
+ String error;
+
+ if (adding_animation) {
+ Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
+ ERR_FAIL_COND(al.is_null());
+ if (p_name == "") {
+ error = TTR("Animation name can't be empty.");
+ } else if (!AnimationLibrary::is_valid_name(p_name)) {
+ error = TTR("Animation name contains invalid characters: '/', ':', ',' or '['.");
+ } else if (al->has_animation(p_name)) {
+ error = TTR("Animation with the same name already exists.");
+ }
+ } else {
+ if (p_name == "" && bool(player->call("has_animation_library", ""))) {
+ error = TTR("Enter a library name.");
+ } else if (!AnimationLibrary::is_valid_name(p_name)) {
+ error = TTR("Library name contains invalid characters: '/', ':', ',' or '['.");
+ } else if (bool(player->call("has_animation_library", p_name))) {
+ error = TTR("Library with the same name already exists.");
+ }
+ }
+
+ if (error != "") {
+ add_library_validate->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ add_library_validate->set_text(error);
+ add_library_dialog->get_ok_button()->set_disabled(true);
+ } else {
+ add_library_validate->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
+ if (p_name == "") {
+ add_library_validate->set_text(TTR("Global library will be created."));
+ } else {
+ add_library_validate->set_text(TTR("Library name is valid."));
+ }
+ add_library_dialog->get_ok_button()->set_disabled(false);
+ }
+}
+
+void AnimationLibraryEditor::_add_library_confirm() {
+ if (adding_animation) {
+ String anim_name = add_library_name->get_text();
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
+ ERR_FAIL_COND(!al.is_valid());
+
+ Ref<Animation> anim;
+ anim.instantiate();
+
+ undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), anim_name));
+ undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, anim);
+ undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+
+ } else {
+ String lib_name = add_library_name->get_text();
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ Ref<AnimationLibrary> al;
+ al.instantiate();
+
+ undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), lib_name));
+ undo_redo->add_do_method(player, "add_animation_library", lib_name, al);
+ undo_redo->add_undo_method(player, "remove_animation_library", lib_name);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ }
+}
+
+void AnimationLibraryEditor::_load_library() {
+ List<String> extensions;
+ ResourceLoader::get_recognized_extensions_for_type("AnimationLibrary", &extensions);
+
+ file_dialog->set_title(TTR("Load Animation"));
+ file_dialog->clear_filters();
+ for (const String &K : extensions) {
+ file_dialog->add_filter("*." + K);
+ }
+
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ file_dialog->set_current_file("");
+ file_dialog->popup_centered_ratio();
+
+ file_dialog_action = FILE_DIALOG_ACTION_OPEN_LIBRARY;
+}
+
+void AnimationLibraryEditor::_file_popup_selected(int p_id) {
+ Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
+ Ref<Animation> anim;
+ if (file_dialog_animation != StringName()) {
+ anim = al->get_animation(file_dialog_animation);
+ ERR_FAIL_COND(anim.is_null());
+ }
+ switch (p_id) {
+ case FILE_MENU_SAVE_LIBRARY: {
+ if (al->get_path().is_resource_file()) {
+ EditorNode::get_singleton()->save_resource(al);
+ break;
+ }
+ [[fallthrough]];
+ }
+ case FILE_MENU_SAVE_AS_LIBRARY: {
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ file_dialog->set_title(TTR("Save Library"));
+ if (al->get_path().is_resource_file()) {
+ file_dialog->set_current_path(al->get_path());
+ } else {
+ file_dialog->set_current_file(String(file_dialog_library) + ".res");
+ }
+ file_dialog->clear_filters();
+ List<String> exts;
+ ResourceLoader::get_recognized_extensions_for_type("AnimationLibrary", &exts);
+ for (const String &K : exts) {
+ file_dialog->add_filter("*." + K);
+ }
+
+ file_dialog->popup_centered_ratio();
+ file_dialog_action = FILE_DIALOG_ACTION_SAVE_LIBRARY;
+ } break;
+ case FILE_MENU_MAKE_LIBRARY_UNIQUE: {
+ StringName lib_name = file_dialog_library;
+
+ Ref<AnimationLibrary> ald = al->duplicate();
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name));
+ undo_redo->add_do_method(player, "remove_animation_library", lib_name);
+ undo_redo->add_do_method(player, "add_animation_library", lib_name, ald);
+ undo_redo->add_undo_method(player, "remove_animation_library", lib_name);
+ undo_redo->add_undo_method(player, "add_animation_library", lib_name, al);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+
+ } break;
+ case FILE_MENU_EDIT_LIBRARY: {
+ EditorNode::get_singleton()->push_item(al.ptr());
+ } break;
+
+ case FILE_MENU_SAVE_ANIMATION: {
+ if (anim->get_path().is_resource_file()) {
+ EditorNode::get_singleton()->save_resource(anim);
+ break;
+ }
+ [[fallthrough]];
+ }
+ case FILE_MENU_SAVE_AS_ANIMATION: {
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ file_dialog->set_title(TTR("Save Animation"));
+ if (anim->get_path().is_resource_file()) {
+ file_dialog->set_current_path(anim->get_path());
+ } else {
+ file_dialog->set_current_file(String(file_dialog_animation) + ".res");
+ }
+ file_dialog->clear_filters();
+ List<String> exts;
+ ResourceLoader::get_recognized_extensions_for_type("Animation", &exts);
+ for (const String &K : exts) {
+ file_dialog->add_filter("*." + K);
+ }
+
+ file_dialog->popup_centered_ratio();
+ file_dialog_action = FILE_DIALOG_ACTION_SAVE_ANIMATION;
+ } break;
+ case FILE_MENU_MAKE_ANIMATION_UNIQUE: {
+ StringName anim_name = file_dialog_animation;
+
+ Ref<Animation> animd = anim->duplicate();
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name));
+ undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
+ undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd);
+ undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name);
+ undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ } break;
+ case FILE_MENU_EDIT_ANIMATION: {
+ EditorNode::get_singleton()->push_item(anim.ptr());
+ } break;
+ }
+}
+void AnimationLibraryEditor::_load_file(String p_path) {
+ switch (file_dialog_action) {
+ case FILE_DIALOG_ACTION_OPEN_LIBRARY: {
+ Ref<AnimationLibrary> al = ResourceLoader::load(p_path);
+ if (al.is_null()) {
+ error_dialog->set_text(TTR("Invalid AnimationLibrary file."));
+ error_dialog->popup_centered();
+ return;
+ }
+
+ TypedArray<StringName> libs = player->call("get_animation_library_list");
+ for (int i = 0; i < libs.size(); i++) {
+ const StringName K = libs[i];
+ Ref<AnimationLibrary> al2 = player->call("get_animation_library", K);
+ if (al2 == al) {
+ error_dialog->set_text(TTR("This library is already added to the player."));
+ error_dialog->popup_centered();
+
+ return;
+ }
+ }
+
+ String name = AnimationLibrary::validate_name(p_path.get_file().get_basename());
+
+ int attempt = 1;
+
+ while (bool(player->call("has_animation_library", name))) {
+ attempt++;
+ name = p_path.get_file().get_basename() + " " + itos(attempt);
+ }
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name));
+ undo_redo->add_do_method(player, "add_animation_library", name, al);
+ undo_redo->add_undo_method(player, "remove_animation_library", name);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ } break;
+ case FILE_DIALOG_ACTION_OPEN_ANIMATION: {
+ Ref<Animation> anim = ResourceLoader::load(p_path);
+ if (anim.is_null()) {
+ error_dialog->set_text(TTR("Invalid Animation file."));
+ error_dialog->popup_centered();
+ return;
+ }
+
+ Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
+ List<StringName> anims;
+ al->get_animation_list(&anims);
+ for (const StringName &K : anims) {
+ Ref<Animation> a2 = al->get_animation(K);
+ if (a2 == anim) {
+ error_dialog->set_text(TTR("This animation is already added to the library."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+
+ String name = p_path.get_file().get_basename();
+
+ int attempt = 1;
+
+ while (al->has_animation(name)) {
+ attempt++;
+ name = p_path.get_file().get_basename() + " " + itos(attempt);
+ }
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name));
+ undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
+ undo_redo->add_undo_method(al.ptr(), "remove_animation", name);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ } break;
+
+ case FILE_DIALOG_ACTION_SAVE_LIBRARY: {
+ Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
+ String prev_path = al->get_path();
+ EditorNode::get_singleton()->save_resource_in_path(al, p_path);
+
+ if (al->get_path() != prev_path) { // Save successful.
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library));
+ undo_redo->add_do_method(al.ptr(), "set_path", al->get_path());
+ undo_redo->add_undo_method(al.ptr(), "set_path", prev_path);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ }
+
+ } break;
+ case FILE_DIALOG_ACTION_SAVE_ANIMATION: {
+ Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
+ Ref<Animation> anim;
+ if (file_dialog_animation != StringName()) {
+ anim = al->get_animation(file_dialog_animation);
+ ERR_FAIL_COND(anim.is_null());
+ }
+ String prev_path = anim->get_path();
+ EditorNode::get_singleton()->save_resource_in_path(anim, p_path);
+ if (anim->get_path() != prev_path) { // Save successful.
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation));
+ undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path());
+ undo_redo->add_undo_method(anim.ptr(), "set_path", prev_path);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ }
+ } break;
+ }
+}
+
+void AnimationLibraryEditor::_item_renamed() {
+ TreeItem *ti = tree->get_edited();
+ String text = ti->get_text(0);
+ String old_text = ti->get_metadata(0);
+ bool restore_text = false;
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) {
+ restore_text = true;
+ } else {
+ if (ti->get_parent() == tree->get_root()) {
+ // Renamed library
+
+ if (player->call("has_animation_library", text)) {
+ restore_text = true;
+ } else {
+ undo_redo->create_action(vformat(TTR("Rename Animation Library: %s"), text));
+ undo_redo->add_do_method(player, "rename_animation_library", old_text, text);
+ undo_redo->add_undo_method(player, "rename_animation_library", text, old_text);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ updating = true;
+ undo_redo->commit_action();
+ updating = false;
+ ti->set_metadata(0, text);
+ if (text == "") {
+ ti->set_suffix(0, TTR("[Global]"));
+ } else {
+ ti->set_suffix(0, "");
+ }
+ }
+ } else {
+ // Renamed anim
+ StringName library = ti->get_parent()->get_metadata(0);
+ Ref<AnimationLibrary> al = player->call("get_animation_library", library);
+
+ if (al.is_valid()) {
+ if (al->has_animation(text)) {
+ restore_text = true;
+ } else {
+ undo_redo->create_action(vformat(TTR("Rename Animation: %s"), text));
+ undo_redo->add_do_method(al.ptr(), "rename_animation", old_text, text);
+ undo_redo->add_undo_method(al.ptr(), "rename_animation", text, old_text);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ updating = true;
+ undo_redo->commit_action();
+ updating = false;
+
+ ti->set_metadata(0, text);
+ }
+ } else {
+ restore_text = true;
+ }
+ }
+ }
+
+ if (restore_text) {
+ ti->set_text(0, old_text);
+ }
+}
+
+void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int p_button) {
+ if (p_item->get_parent() == tree->get_root()) {
+ // Library
+ StringName lib_name = p_item->get_metadata(0);
+ Ref<AnimationLibrary> al = player->call("get_animation_library", lib_name);
+ switch (p_button) {
+ case LIB_BUTTON_ADD: {
+ add_library_dialog->set_title(TTR("Animation Name:"));
+ add_library_name->set_text("");
+ add_library_dialog->popup_centered();
+ add_library_name->grab_focus();
+ adding_animation = true;
+ adding_animation_to_library = p_item->get_metadata(0);
+ _add_library_validate("");
+ } break;
+ case LIB_BUTTON_LOAD: {
+ adding_animation_to_library = p_item->get_metadata(0);
+ List<String> extensions;
+ ResourceLoader::get_recognized_extensions_for_type("Animation", &extensions);
+
+ file_dialog->clear_filters();
+ for (const String &K : extensions) {
+ file_dialog->add_filter("*." + K);
+ }
+
+ file_dialog->set_title(TTR("Load Animation"));
+ file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ file_dialog->set_current_file("");
+ file_dialog->popup_centered_ratio();
+
+ file_dialog_action = FILE_DIALOG_ACTION_OPEN_ANIMATION;
+
+ } break;
+ case LIB_BUTTON_PASTE: {
+ Ref<Animation> anim = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (!anim.is_valid()) {
+ error_dialog->set_text(TTR("No animation resource in clipboard!"));
+ error_dialog->popup_centered();
+ return;
+ }
+
+ anim = anim->duplicate(); // Users simply dont care about referencing, so making a copy works better here.
+
+ String base_name;
+ if (anim->get_name() != "") {
+ base_name = anim->get_name();
+ } else {
+ base_name = TTR("Pasted Animation");
+ }
+
+ String name = base_name;
+ int attempt = 1;
+ while (al->has_animation(name)) {
+ attempt++;
+ name = base_name + " " + itos(attempt);
+ }
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name));
+ undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
+ undo_redo->add_undo_method(al.ptr(), "remove_animation", name);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+
+ } break;
+ case LIB_BUTTON_FILE: {
+ file_popup->clear();
+ file_popup->add_item(TTR("Save"), FILE_MENU_SAVE_LIBRARY);
+ file_popup->add_item(TTR("Save As"), FILE_MENU_SAVE_AS_LIBRARY);
+ file_popup->add_separator();
+ file_popup->add_item(TTR("Make Unique"), FILE_MENU_MAKE_LIBRARY_UNIQUE);
+ file_popup->add_separator();
+ file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_LIBRARY);
+ Rect2 pos = tree->get_item_rect(p_item, 1, 0);
+ Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height);
+ file_popup->popup(Rect2(popup_pos, Size2()));
+
+ file_dialog_animation = StringName();
+ file_dialog_library = lib_name;
+ } break;
+ case LIB_BUTTON_DELETE: {
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name));
+ undo_redo->add_do_method(player, "remove_animation_library", lib_name);
+ undo_redo->add_undo_method(player, "add_animation_library", lib_name, al);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ } break;
+ }
+
+ } else {
+ // Animation
+ StringName lib_name = p_item->get_parent()->get_metadata(0);
+ StringName anim_name = p_item->get_metadata(0);
+ Ref<AnimationLibrary> al = player->call("get_animation_library", lib_name);
+ Ref<Animation> anim = al->get_animation(anim_name);
+ ERR_FAIL_COND(!anim.is_valid());
+ switch (p_button) {
+ case ANIM_BUTTON_COPY: {
+ if (anim->get_name() == "") {
+ anim->set_name(anim_name); // Keep the name around
+ }
+ EditorSettings::get_singleton()->set_resource_clipboard(anim);
+ } break;
+ case ANIM_BUTTON_FILE: {
+ file_popup->clear();
+ file_popup->add_item(TTR("Save"), FILE_MENU_SAVE_ANIMATION);
+ file_popup->add_item(TTR("Save As"), FILE_MENU_SAVE_AS_ANIMATION);
+ file_popup->add_separator();
+ file_popup->add_item(TTR("Make Unique"), FILE_MENU_MAKE_ANIMATION_UNIQUE);
+ file_popup->add_separator();
+ file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_ANIMATION);
+ Rect2 pos = tree->get_item_rect(p_item, 1, 0);
+ Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height);
+ file_popup->popup(Rect2(popup_pos, Size2()));
+
+ file_dialog_animation = anim_name;
+ file_dialog_library = lib_name;
+
+ } break;
+ case ANIM_BUTTON_DELETE: {
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name));
+ undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
+ undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim);
+ undo_redo->add_do_method(this, "_update_editor", player);
+ undo_redo->add_undo_method(this, "_update_editor", player);
+ undo_redo->commit_action();
+ } break;
+ }
+ }
+}
+
+void AnimationLibraryEditor::update_tree() {
+ if (updating) {
+ return;
+ }
+
+ tree->clear();
+ ERR_FAIL_COND(!player);
+
+ Color ss_color = get_theme_color(SNAME("prop_subsection"), SNAME("Editor"));
+
+ TreeItem *root = tree->create_item();
+ TypedArray<StringName> libs = player->call("get_animation_library_list");
+
+ for (int i = 0; i < libs.size(); i++) {
+ const StringName K = libs[i];
+ TreeItem *libitem = tree->create_item(root);
+ libitem->set_text(0, K);
+ if (K == StringName()) {
+ libitem->set_suffix(0, TTR("[Global]"));
+ } else {
+ libitem->set_suffix(0, "");
+ }
+ libitem->set_editable(0, true);
+ libitem->set_metadata(0, K);
+ libitem->set_icon(0, get_theme_icon("AnimationLibrary", "EditorIcons"));
+ libitem->add_button(0, get_theme_icon("Add", "EditorIcons"), LIB_BUTTON_ADD, false, TTR("Add Animation to Library"));
+ libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, false, TTR("Load animation from file and add to library"));
+ libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, false, TTR("Paste Animation to Library from clipboard"));
+ Ref<AnimationLibrary> al = player->call("get_animation_library", K);
+ if (al->get_path().is_resource_file()) {
+ libitem->set_text(1, al->get_path().get_file());
+ libitem->set_tooltip(1, al->get_path());
+ } else {
+ libitem->set_text(1, TTR("[built-in]"));
+ }
+ libitem->add_button(1, get_theme_icon("Save", "EditorIcons"), LIB_BUTTON_FILE, false, TTR("Save animation library to resource on disk"));
+ libitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), LIB_BUTTON_DELETE, false, TTR("Remove animation library"));
+
+ libitem->set_custom_bg_color(0, ss_color);
+
+ List<StringName> animations;
+ al->get_animation_list(&animations);
+ for (const StringName &L : animations) {
+ TreeItem *anitem = tree->create_item(libitem);
+ anitem->set_text(0, L);
+ anitem->set_editable(0, true);
+ anitem->set_metadata(0, L);
+ anitem->set_icon(0, get_theme_icon("Animation", "EditorIcons"));
+ anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, false, TTR("Copy animation to clipboard"));
+ Ref<Animation> anim = al->get_animation(L);
+
+ if (anim->get_path().is_resource_file()) {
+ anitem->set_text(1, anim->get_path().get_file());
+ anitem->set_tooltip(1, anim->get_path());
+ } else {
+ anitem->set_text(1, TTR("[built-in]"));
+ }
+ anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, false, TTR("Save animation to resource on disk"));
+ anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, false, TTR("Remove animation from Library"));
+ }
+ }
+}
+
+void AnimationLibraryEditor::show_dialog() {
+ update_tree();
+ popup_centered_ratio(0.5);
+}
+
+void AnimationLibraryEditor::_update_editor(Object *p_player) {
+ emit_signal("update_editor", p_player);
+}
+
+void AnimationLibraryEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_editor", "player"), &AnimationLibraryEditor::_update_editor);
+ ADD_SIGNAL(MethodInfo("update_editor"));
+}
+
+AnimationLibraryEditor::AnimationLibraryEditor() {
+ set_title(TTR("Edit Animation Libraries"));
+
+ file_dialog = memnew(EditorFileDialog);
+ add_child(file_dialog);
+ file_dialog->connect("file_selected", callable_mp(this, &AnimationLibraryEditor::_load_file));
+
+ add_library_dialog = memnew(ConfirmationDialog);
+ VBoxContainer *dialog_vb = memnew(VBoxContainer);
+ add_library_name = memnew(LineEdit);
+ dialog_vb->add_child(add_library_name);
+ add_library_name->connect("text_changed", callable_mp(this, &AnimationLibraryEditor::_add_library_validate));
+ add_child(add_library_dialog);
+
+ add_library_validate = memnew(Label);
+ dialog_vb->add_child(add_library_validate);
+ add_library_dialog->add_child(dialog_vb);
+ add_library_dialog->connect("confirmed", callable_mp(this, &AnimationLibraryEditor::_add_library_confirm));
+ add_library_dialog->register_text_enter(add_library_name);
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->add_spacer(true);
+ Button *b = memnew(Button(TTR("Add Library")));
+ b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_add_library));
+ hb->add_child(b);
+ b = memnew(Button(TTR("Load Library")));
+ b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_load_library));
+ hb->add_child(b);
+ vb->add_child(hb);
+ tree = memnew(Tree);
+ vb->add_child(tree);
+
+ tree->set_columns(2);
+ tree->set_column_titles_visible(true);
+ tree->set_column_title(0, TTR("Resource"));
+ tree->set_column_title(1, TTR("Storage"));
+ tree->set_column_expand(0, true);
+ tree->set_column_custom_minimum_width(1, EDSCALE * 250);
+ tree->set_column_expand(1, false);
+ tree->set_hide_root(true);
+ tree->set_hide_folding(true);
+ tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ tree->connect("item_edited", callable_mp(this, &AnimationLibraryEditor::_item_renamed));
+ tree->connect("button_pressed", callable_mp(this, &AnimationLibraryEditor::_button_pressed));
+
+ file_popup = memnew(PopupMenu);
+ add_child(file_popup);
+ file_popup->connect("id_pressed", callable_mp(this, &AnimationLibraryEditor::_file_popup_selected));
+
+ add_child(vb);
+
+ error_dialog = memnew(AcceptDialog);
+ error_dialog->set_title(TTR("Error:"));
+ add_child(error_dialog);
+}
diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h
new file mode 100644
index 0000000000..5bd4e8d9e2
--- /dev/null
+++ b/editor/plugins/animation_library_editor.h
@@ -0,0 +1,119 @@
+/*************************************************************************/
+/* animation_library_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 ANIMATION_LIBRARY_EDITOR_H
+#define ANIMATION_LIBRARY_EDITOR_H
+
+#include "editor/animation_track_editor.h"
+#include "editor/editor_plugin.h"
+#include "scene/animation/animation_player.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/tree.h"
+
+class EditorFileDialog;
+
+class AnimationLibraryEditor : public AcceptDialog {
+ GDCLASS(AnimationLibraryEditor, AcceptDialog)
+
+ enum {
+ LIB_BUTTON_ADD,
+ LIB_BUTTON_LOAD,
+ LIB_BUTTON_PASTE,
+ LIB_BUTTON_FILE,
+ LIB_BUTTON_DELETE,
+ };
+ enum {
+ ANIM_BUTTON_COPY,
+ ANIM_BUTTON_FILE,
+ ANIM_BUTTON_DELETE,
+ };
+
+ enum FileMenuAction {
+ FILE_MENU_SAVE_LIBRARY,
+ FILE_MENU_SAVE_AS_LIBRARY,
+ FILE_MENU_MAKE_LIBRARY_UNIQUE,
+ FILE_MENU_EDIT_LIBRARY,
+
+ FILE_MENU_SAVE_ANIMATION,
+ FILE_MENU_SAVE_AS_ANIMATION,
+ FILE_MENU_MAKE_ANIMATION_UNIQUE,
+ FILE_MENU_EDIT_ANIMATION,
+ };
+
+ enum FileDialogAction {
+ FILE_DIALOG_ACTION_OPEN_LIBRARY,
+ FILE_DIALOG_ACTION_SAVE_LIBRARY,
+ FILE_DIALOG_ACTION_OPEN_ANIMATION,
+ FILE_DIALOG_ACTION_SAVE_ANIMATION,
+ };
+
+ FileDialogAction file_dialog_action = FILE_DIALOG_ACTION_OPEN_ANIMATION;
+
+ StringName file_dialog_animation;
+ StringName file_dialog_library;
+
+ AcceptDialog *error_dialog = nullptr;
+ bool adding_animation = false;
+ StringName adding_animation_to_library;
+ EditorFileDialog *file_dialog = nullptr;
+ ConfirmationDialog *add_library_dialog = nullptr;
+ LineEdit *add_library_name = nullptr;
+ Label *add_library_validate = nullptr;
+ PopupMenu *file_popup = nullptr;
+
+ Tree *tree = nullptr;
+
+ Object *player = nullptr;
+
+ void _add_library();
+ void _add_library_validate(const String &p_name);
+ void _add_library_confirm();
+ void _load_library();
+ void _load_file(String p_path);
+
+ void _item_renamed();
+ void _button_pressed(TreeItem *p_item, int p_column, int p_button);
+
+ void _file_popup_selected(int p_id);
+
+ bool updating = false;
+
+protected:
+ void _update_editor(Object *p_player);
+ static void _bind_methods();
+
+public:
+ void set_animation_player(Object *p_player);
+ void show_dialog();
+ void update_tree();
+ AnimationLibraryEditor();
+};
+
+#endif // ANIMATIONPLAYERLIBRARYEDITOR_H
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index ea025dad3e..67d6c66c89 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -35,14 +35,20 @@
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/keyboard.h"
-#include "editor/animation_track_editor.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning.
#include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning.
+#include "editor/scene_tree_dock.h"
#include "scene/main/window.h"
+#include "scene/resources/animation.h"
+#include "scene/scene_string_names.h"
#include "servers/rendering_server.h"
+///////////////////////////////////
+
void AnimationPlayerEditor::_node_removed(Node *p_node) {
if (player && player == p_node) {
player = nullptr;
@@ -72,7 +78,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
if (player->has_animation(animname)) {
Ref<Animation> anim = player->get_animation(animname);
if (!anim.is_null()) {
- frame->set_max(anim->get_length());
+ frame->set_max((double)anim->get_length());
}
}
}
@@ -90,6 +96,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
last_active = player->is_playing();
updating = false;
} break;
+
case NOTIFICATION_ENTER_TREE: {
tool_anim->get_popup()->connect("id_pressed", callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu));
@@ -99,11 +106,13 @@ void AnimationPlayerEditor::_notification(int p_what) {
get_tree()->connect("node_removed", callable_mp(this, &AnimationPlayerEditor::_node_removed));
- add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
+ add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
} break;
+
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
+ add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
} break;
+
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
@@ -141,14 +150,14 @@ void AnimationPlayerEditor::_notification(int p_what) {
#define ITEM_ICON(m_item, m_icon) tool_anim->get_popup()->set_item_icon(tool_anim->get_popup()->get_item_index(m_item), get_theme_icon(SNAME(m_icon), SNAME("EditorIcons")))
ITEM_ICON(TOOL_NEW_ANIM, "New");
- ITEM_ICON(TOOL_LOAD_ANIM, "Load");
- ITEM_ICON(TOOL_SAVE_ANIM, "Save");
- ITEM_ICON(TOOL_SAVE_AS_ANIM, "Save");
+ ITEM_ICON(TOOL_ANIM_LIBRARY, "AnimationLibrary");
ITEM_ICON(TOOL_DUPLICATE_ANIM, "Duplicate");
ITEM_ICON(TOOL_RENAME_ANIM, "Rename");
ITEM_ICON(TOOL_EDIT_TRANSITIONS, "Blend");
ITEM_ICON(TOOL_EDIT_RESOURCE, "Edit");
ITEM_ICON(TOOL_REMOVE_ANIM, "Remove");
+
+ _update_animation_list_icons();
} break;
}
}
@@ -157,7 +166,7 @@ void AnimationPlayerEditor::_autoplay_pressed() {
if (updating) {
return;
}
- if (animation->get_item_count() == 0) {
+ if (animation->has_selectable_items() == 0) {
return;
}
@@ -183,12 +192,9 @@ void AnimationPlayerEditor::_autoplay_pressed() {
}
void AnimationPlayerEditor::_play_pressed() {
- String current;
- if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) {
- current = animation->get_item_text(animation->get_selected());
- }
+ String current = _get_current();
- if (current != "") {
+ if (!current.is_empty()) {
if (current == player->get_assigned_animation()) {
player->stop(); //so it won't blend with itself
}
@@ -200,12 +206,9 @@ void AnimationPlayerEditor::_play_pressed() {
}
void AnimationPlayerEditor::_play_from_pressed() {
- String current;
- if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) {
- current = animation->get_item_text(animation->get_selected());
- }
+ String current = _get_current();
- if (current != "") {
+ if (!current.is_empty()) {
float time = player->get_current_animation_position();
if (current == player->get_assigned_animation() && player->is_playing()) {
@@ -220,13 +223,16 @@ void AnimationPlayerEditor::_play_from_pressed() {
stop->set_pressed(false);
}
-void AnimationPlayerEditor::_play_bw_pressed() {
+String AnimationPlayerEditor::_get_current() const {
String current;
- if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) {
+ if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count() && !animation->is_item_separator(animation->get_selected())) {
current = animation->get_item_text(animation->get_selected());
}
-
- if (current != "") {
+ return current;
+}
+void AnimationPlayerEditor::_play_bw_pressed() {
+ String current = _get_current();
+ if (!current.is_empty()) {
if (current == player->get_assigned_animation()) {
player->stop(); //so it won't blend with itself
}
@@ -238,12 +244,9 @@ void AnimationPlayerEditor::_play_bw_pressed() {
}
void AnimationPlayerEditor::_play_bw_from_pressed() {
- String current;
- if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) {
- current = animation->get_item_text(animation->get_selected());
- }
+ String current = _get_current();
- if (current != "") {
+ if (!current.is_empty()) {
float time = player->get_current_animation_position();
if (current == player->get_assigned_animation()) {
player->stop(); //so it won't blend with itself
@@ -273,12 +276,9 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
}
// when selecting an animation, the idea is that the only interesting behavior
// ui-wise is that it should play/blend the next one if currently playing
- String current;
- if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) {
- current = animation->get_item_text(animation->get_selected());
- }
+ String current = _get_current();
- if (current != "") {
+ if (!current.is_empty()) {
player->set_assigned_animation(current);
Ref<Animation> anim = player->get_animation(current);
@@ -289,7 +289,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
track_editor->set_root(root);
}
}
- frame->set_max(anim->get_length());
+ frame->set_max((double)anim->get_length());
} else {
track_editor->set_animation(Ref<Animation>());
@@ -299,12 +299,11 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
autoplay->set_pressed(current == player->get_autoplay());
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
- EditorNode::get_singleton()->update_keying();
_animation_key_editor_seek(timeline_position, false);
}
void AnimationPlayerEditor::_animation_new() {
- renaming = false;
+ name_dialog_op = TOOL_NEW_ANIM;
name_title->set_text(TTR("New Animation Name:"));
int count = 1;
@@ -322,6 +321,20 @@ void AnimationPlayerEditor::_animation_new() {
break;
}
+ List<StringName> libraries;
+ player->get_animation_library_list(&libraries);
+ library->clear();
+ for (const StringName &K : libraries) {
+ library->add_item((K == StringName()) ? String(TTR("[Global]")) : String(K));
+ library->set_item_metadata(0, String(K));
+ }
+
+ if (libraries.size() > 1) {
+ library->show();
+ } else {
+ library->hide();
+ }
+
name->set_text(base);
name_dialog->popup_centered(Size2(300, 90));
name->select_all();
@@ -329,7 +342,7 @@ void AnimationPlayerEditor::_animation_new() {
}
void AnimationPlayerEditor::_animation_rename() {
- if (animation->get_item_count() == 0) {
+ if (!animation->has_selectable_items()) {
return;
}
int selected = animation->get_selected();
@@ -337,88 +350,15 @@ void AnimationPlayerEditor::_animation_rename() {
name_title->set_text(TTR("Change Animation Name:"));
name->set_text(selected_name);
- renaming = true;
+ name_dialog_op = TOOL_RENAME_ANIM;
name_dialog->popup_centered(Size2(300, 90));
name->select_all();
name->grab_focus();
-}
-
-void AnimationPlayerEditor::_animation_load() {
- ERR_FAIL_COND(!player);
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);
- file->clear_filters();
- List<String> extensions;
-
- ResourceLoader::get_recognized_extensions_for_type("Animation", &extensions);
- for (const String &E : extensions) {
- file->add_filter("*." + E + " ; " + E.to_upper());
- }
-
- file->popup_file_dialog();
-}
-
-void AnimationPlayerEditor::_animation_save_in_path(const Ref<Resource> &p_resource, const String &p_path) {
- int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
- flg |= ResourceSaver::FLAG_COMPRESS;
- }
-
- String path = ProjectSettings::get_singleton()->localize_path(p_path);
- Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS);
-
- if (err != OK) {
- EditorNode::get_singleton()->show_warning(TTR("Error saving resource!"));
- return;
- }
-
- ((Resource *)p_resource.ptr())->set_path(path);
- editor->emit_signal(SNAME("resource_saved"), p_resource);
-}
-
-void AnimationPlayerEditor::_animation_save(const Ref<Resource> &p_resource) {
- if (p_resource->get_path().is_resource_file()) {
- _animation_save_in_path(p_resource, p_resource->get_path());
- } else {
- _animation_save_as(p_resource);
- }
-}
-
-void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource) {
- file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
-
- List<String> extensions;
- ResourceSaver::get_recognized_extensions(p_resource, &extensions);
- file->clear_filters();
- for (int i = 0; i < extensions.size(); i++) {
- file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
- }
-
- String path;
- //file->set_current_path(current_path);
- if (p_resource->get_path() != "") {
- path = p_resource->get_path();
- if (extensions.size()) {
- if (extensions.find(p_resource->get_path().get_extension().to_lower()) == nullptr) {
- path = p_resource->get_path().get_base_dir() + p_resource->get_name() + "." + extensions.front()->get();
- }
- }
- } else {
- if (extensions.size()) {
- if (p_resource->get_name() != "") {
- path = p_resource->get_name() + "." + extensions.front()->get().to_lower();
- } else {
- String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
- path = "new_" + resource_name_snake_case + "." + extensions.front()->get().to_lower();
- }
- }
- }
- file->set_current_path(path);
- file->set_title(TTR("Save Resource As..."));
- file->popup_file_dialog();
+ library->hide();
}
void AnimationPlayerEditor::_animation_remove() {
- if (animation->get_item_count() == 0) {
+ if (!animation->has_selectable_items()) {
return;
}
@@ -432,6 +372,9 @@ void AnimationPlayerEditor::_animation_remove_confirmed() {
String current = animation->get_item_text(animation->get_selected());
Ref<Animation> anim = player->get_animation(current);
+ Ref<AnimationLibrary> al = player->get_animation_library(player->find_animation_library(anim));
+ ERR_FAIL_COND(al.is_null());
+
undo_redo->create_action(TTR("Remove Animation"));
if (player->get_autoplay() == current) {
undo_redo->add_do_method(player, "set_autoplay", "");
@@ -439,11 +382,11 @@ void AnimationPlayerEditor::_animation_remove_confirmed() {
// Avoid having the autoplay icon linger around if there is only one animation in the player.
undo_redo->add_do_method(this, "_animation_player_changed", player);
}
- undo_redo->add_do_method(player, "remove_animation", current);
- undo_redo->add_undo_method(player, "add_animation", current, anim);
+ undo_redo->add_do_method(al.ptr(), "remove_animation", current);
+ undo_redo->add_undo_method(al.ptr(), "add_animation", current, anim);
undo_redo->add_do_method(this, "_animation_player_changed", player);
undo_redo->add_undo_method(this, "_animation_player_changed", player);
- if (animation->get_item_count() == 1) {
+ if (animation->has_selectable_items() && animation->get_selectable_item(false) == animation->get_selectable_item(true)) { // Last item remaining.
undo_redo->add_do_method(this, "_stop_onion_skinning");
undo_redo->add_undo_method(this, "_start_onion_skinning");
}
@@ -474,7 +417,7 @@ double AnimationPlayerEditor::_get_editor_step() const {
ERR_FAIL_COND_V(!anim.is_valid(), 0.0);
// Use more precise snapping when holding Shift
- return Input::get_singleton()->is_key_pressed(KEY_SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
+ return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
}
return 0.0;
@@ -484,13 +427,13 @@ void AnimationPlayerEditor::_animation_name_edited() {
player->stop();
String new_name = name->get_text();
- if (new_name == "" || new_name.find(":") != -1 || new_name.find("/") != -1) {
+ if (!AnimationLibrary::is_valid_name(new_name)) {
error_dialog->set_text(TTR("Invalid animation name!"));
error_dialog->popup_centered();
return;
}
- if (renaming && animation->get_item_count() > 0 && animation->get_item_text(animation->get_selected()) == new_name) {
+ if (name_dialog_op == TOOL_RENAME_ANIM && animation->has_selectable_items() && animation->get_item_text(animation->get_selected()) == new_name) {
name_dialog->hide();
return;
}
@@ -501,44 +444,90 @@ void AnimationPlayerEditor::_animation_name_edited() {
return;
}
- if (renaming) {
- String current = animation->get_item_text(animation->get_selected());
- Ref<Animation> anim = player->get_animation(current);
+ switch (name_dialog_op) {
+ case TOOL_RENAME_ANIM: {
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
- undo_redo->create_action(TTR("Rename Animation"));
- undo_redo->add_do_method(player, "rename_animation", current, new_name);
- undo_redo->add_do_method(anim.ptr(), "set_name", new_name);
- undo_redo->add_undo_method(player, "rename_animation", new_name, current);
- undo_redo->add_undo_method(anim.ptr(), "set_name", current);
- undo_redo->add_do_method(this, "_animation_player_changed", player);
- undo_redo->add_undo_method(this, "_animation_player_changed", player);
- undo_redo->commit_action();
+ Ref<AnimationLibrary> al = player->get_animation_library(player->find_animation_library(anim));
+ ERR_FAIL_COND(al.is_null());
- _select_anim_by_name(new_name);
+ undo_redo->create_action(TTR("Rename Animation"));
+ undo_redo->add_do_method(al.ptr(), "rename_animation", current, new_name);
+ undo_redo->add_do_method(anim.ptr(), "set_name", new_name);
+ undo_redo->add_undo_method(al.ptr(), "rename_animation", new_name, current);
+ undo_redo->add_undo_method(anim.ptr(), "set_name", current);
+ undo_redo->add_do_method(this, "_animation_player_changed", player);
+ undo_redo->add_undo_method(this, "_animation_player_changed", player);
+ undo_redo->commit_action();
- } else {
- Ref<Animation> new_anim = Ref<Animation>(memnew(Animation));
- new_anim->set_name(new_name);
+ _select_anim_by_name(new_name);
+ } break;
- undo_redo->create_action(TTR("Add Animation"));
- undo_redo->add_do_method(player, "add_animation", new_name, new_anim);
- undo_redo->add_undo_method(player, "remove_animation", new_name);
- undo_redo->add_do_method(this, "_animation_player_changed", player);
- undo_redo->add_undo_method(this, "_animation_player_changed", player);
- if (animation->get_item_count() == 0) {
- undo_redo->add_do_method(this, "_start_onion_skinning");
- undo_redo->add_undo_method(this, "_stop_onion_skinning");
- }
- undo_redo->commit_action();
+ case TOOL_NEW_ANIM: {
+ Ref<Animation> new_anim = Ref<Animation>(memnew(Animation));
+ new_anim->set_name(new_name);
+
+ Ref<AnimationLibrary> al;
+ if (library->is_visible()) {
+ al = player->get_animation_library(library->get_item_metadata(library->get_selected()));
+ } else {
+ if (player->has_animation_library("")) {
+ al = player->get_animation_library("");
+ }
+ }
+
+ undo_redo->create_action(TTR("Add Animation"));
+
+ bool lib_added = false;
+ if (al.is_null()) {
+ al.instantiate();
+ lib_added = true;
+ undo_redo->add_do_method(player, "add_animation_library", "", al);
+ }
+
+ undo_redo->add_do_method(al.ptr(), "add_animation", new_name, new_anim);
+ undo_redo->add_undo_method(al.ptr(), "remove_animation", new_name);
+ undo_redo->add_do_method(this, "_animation_player_changed", player);
+ undo_redo->add_undo_method(this, "_animation_player_changed", player);
+ if (!animation->has_selectable_items()) {
+ undo_redo->add_do_method(this, "_start_onion_skinning");
+ undo_redo->add_undo_method(this, "_stop_onion_skinning");
+ }
+ if (lib_added) {
+ undo_redo->add_undo_method(player, "remove_animation_library", "");
+ }
+ undo_redo->commit_action();
+
+ _select_anim_by_name(new_name);
+ } break;
+
+ case TOOL_DUPLICATE_ANIM: {
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
- _select_anim_by_name(new_name);
+ Ref<Animation> new_anim = _animation_clone(anim);
+ new_anim->set_name(new_name);
+
+ Ref<AnimationLibrary> library = player->get_animation_library(player->find_animation_library(anim));
+
+ undo_redo->create_action(TTR("Duplicate Animation"));
+ undo_redo->add_do_method(library.ptr(), "add_animation", new_name, new_anim);
+ undo_redo->add_undo_method(library.ptr(), "remove_animation", new_name);
+ undo_redo->add_do_method(player, "animation_set_next", new_name, player->animation_get_next(current));
+ undo_redo->add_do_method(this, "_animation_player_changed", player);
+ undo_redo->add_undo_method(this, "_animation_player_changed", player);
+ undo_redo->commit_action();
+
+ _select_anim_by_name(new_name);
+ } break;
}
name_dialog->hide();
}
void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) {
- if (animation->get_item_count() == 0) {
+ if (!animation->has_selectable_items()) {
return;
}
@@ -559,7 +548,7 @@ void AnimationPlayerEditor::_animation_blend() {
blend_editor.tree->clear();
- if (animation->get_item_count() == 0) {
+ if (!animation->has_selectable_items()) {
return;
}
@@ -614,7 +603,7 @@ void AnimationPlayerEditor::_blend_edited() {
return;
}
- if (animation->get_item_count() == 0) {
+ if (!animation->has_selectable_items()) {
return;
}
@@ -673,7 +662,7 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) {
if (Object::cast_to<AnimationPlayer>(n) && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) {
player = Object::cast_to<AnimationPlayer>(n);
_update_player();
- editor->make_bottom_panel_item_visible(this);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
set_process(true);
ensure_visibility();
@@ -693,16 +682,16 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) {
}
void AnimationPlayerEditor::_animation_resource_edit() {
- if (animation->get_item_count()) {
- String current = animation->get_item_text(animation->get_selected());
+ String current = _get_current();
+ if (current != String()) {
Ref<Animation> anim = player->get_animation(current);
- editor->edit_resource(anim);
+ EditorNode::get_singleton()->edit_resource(anim);
}
}
void AnimationPlayerEditor::_animation_edit() {
- if (animation->get_item_count()) {
- String current = animation->get_item_text(animation->get_selected());
+ String current = _get_current();
+ if (current != String()) {
Ref<Animation> anim = player->get_animation(current);
track_editor->set_animation(anim);
@@ -716,51 +705,6 @@ void AnimationPlayerEditor::_animation_edit() {
}
}
-void AnimationPlayerEditor::_save_animation(String p_file) {
- String current = animation->get_item_text(animation->get_selected());
- if (current != "") {
- Ref<Animation> anim = player->get_animation(current);
-
- ERR_FAIL_COND(!Object::cast_to<Resource>(*anim));
-
- RES current_res = RES(Object::cast_to<Resource>(*anim));
-
- _animation_save_in_path(current_res, p_file);
- }
-}
-
-void AnimationPlayerEditor::_load_animations(Vector<String> p_files) {
- ERR_FAIL_COND(!player);
-
- for (int i = 0; i < p_files.size(); i++) {
- String file = p_files[i];
-
- Ref<Resource> res = ResourceLoader::load(file, "Animation");
- ERR_FAIL_COND_MSG(res.is_null(), "Cannot load Animation from file '" + file + "'.");
- ERR_FAIL_COND_MSG(!res->is_class("Animation"), "Loaded resource from file '" + file + "' is not Animation.");
- if (file.rfind("/") != -1) {
- file = file.substr(file.rfind("/") + 1, file.length());
- }
- if (file.rfind("\\") != -1) {
- file = file.substr(file.rfind("\\") + 1, file.length());
- }
-
- if (file.find(".") != -1) {
- file = file.substr(0, file.find("."));
- }
-
- undo_redo->create_action(TTR("Load Animation"));
- undo_redo->add_do_method(player, "add_animation", file, res);
- undo_redo->add_undo_method(player, "remove_animation", file);
- if (player->has_animation(file)) {
- undo_redo->add_undo_method(player, "add_animation", file, player->get_animation(file));
- }
- undo_redo->add_do_method(this, "_animation_player_changed", player);
- undo_redo->add_undo_method(this, "_animation_player_changed", player);
- undo_redo->commit_action();
- }
-}
-
void AnimationPlayerEditor::_scale_changed(const String &p_scale) {
player->set_speed_scale(p_scale.to_float());
}
@@ -795,76 +739,84 @@ void AnimationPlayerEditor::_update_animation() {
void AnimationPlayerEditor::_update_player() {
updating = true;
- List<StringName> animlist;
- if (player) {
- player->get_animation_list(&animlist);
- }
animation->clear();
-#define ITEM_DISABLED(m_item, m_disabled) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), m_disabled)
-
- ITEM_DISABLED(TOOL_SAVE_ANIM, animlist.size() == 0);
- ITEM_DISABLED(TOOL_SAVE_AS_ANIM, animlist.size() == 0);
- ITEM_DISABLED(TOOL_DUPLICATE_ANIM, animlist.size() == 0);
- ITEM_DISABLED(TOOL_RENAME_ANIM, animlist.size() == 0);
- ITEM_DISABLED(TOOL_EDIT_TRANSITIONS, animlist.size() == 0);
- ITEM_DISABLED(TOOL_COPY_ANIM, animlist.size() == 0);
- ITEM_DISABLED(TOOL_REMOVE_ANIM, animlist.size() == 0);
-
- stop->set_disabled(animlist.size() == 0);
- play->set_disabled(animlist.size() == 0);
- play_bw->set_disabled(animlist.size() == 0);
- play_bw_from->set_disabled(animlist.size() == 0);
- play_from->set_disabled(animlist.size() == 0);
- frame->set_editable(animlist.size() != 0);
- animation->set_disabled(animlist.size() == 0);
- autoplay->set_disabled(animlist.size() == 0);
- tool_anim->set_disabled(player == nullptr);
- onion_toggle->set_disabled(animlist.size() == 0);
- onion_skinning->set_disabled(animlist.size() == 0);
- pin->set_disabled(player == nullptr);
-
if (!player) {
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
- EditorNode::get_singleton()->update_keying();
return;
}
+ List<StringName> libraries;
+ if (player) {
+ player->get_animation_library_list(&libraries);
+ }
+
int active_idx = -1;
- for (const StringName &E : animlist) {
- Ref<Texture2D> icon;
- if (E == player->get_autoplay()) {
- if (E == "RESET") {
- icon = autoplay_reset_icon;
- } else {
- icon = autoplay_icon;
- }
- } else if (E == "RESET") {
- icon = reset_icon;
+ bool no_anims_found = true;
+
+ for (const StringName &K : libraries) {
+ if (K != StringName()) {
+ animation->add_separator(K);
}
- animation->add_icon_item(icon, E);
- if (player->get_assigned_animation() == E) {
- active_idx = animation->get_item_count() - 1;
+ Ref<AnimationLibrary> library = player->get_animation_library(K);
+ List<StringName> animlist;
+ library->get_animation_list(&animlist);
+
+ for (const StringName &E : animlist) {
+ String path = K;
+ if (path != "") {
+ path += "/";
+ }
+ path += E;
+ animation->add_item(path);
+ if (player->get_assigned_animation() == path) {
+ active_idx = animation->get_selectable_item(true);
+ }
+ no_anims_found = false;
}
}
+#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), no_anims_found)
+
+ ITEM_CHECK_DISABLED(TOOL_DUPLICATE_ANIM);
+ ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM);
+ ITEM_CHECK_DISABLED(TOOL_EDIT_TRANSITIONS);
+ ITEM_CHECK_DISABLED(TOOL_REMOVE_ANIM);
+ ITEM_CHECK_DISABLED(TOOL_EDIT_RESOURCE);
+
+#undef ITEM_CHECK_DISABLED
+
+ stop->set_disabled(no_anims_found);
+ play->set_disabled(no_anims_found);
+ play_bw->set_disabled(no_anims_found);
+ play_bw_from->set_disabled(no_anims_found);
+ play_from->set_disabled(no_anims_found);
+ frame->set_editable(!no_anims_found);
+ animation->set_disabled(no_anims_found);
+ autoplay->set_disabled(no_anims_found);
+ tool_anim->set_disabled(player == nullptr);
+ onion_toggle->set_disabled(no_anims_found);
+ onion_skinning->set_disabled(no_anims_found);
+ pin->set_disabled(player == nullptr);
+
+ _update_animation_list_icons();
updating = false;
if (active_idx != -1) {
animation->select(active_idx);
autoplay->set_pressed(animation->get_item_text(active_idx) == player->get_autoplay());
_animation_selected(active_idx);
-
- } else if (animation->get_item_count() > 0) {
- animation->select(0);
- autoplay->set_pressed(animation->get_item_text(0) == player->get_autoplay());
- _animation_selected(0);
+ } else if (animation->has_selectable_items()) {
+ int item = animation->get_selectable_item();
+ animation->select(item);
+ autoplay->set_pressed(animation->get_item_text(item) == player->get_autoplay());
+ _animation_selected(item);
} else {
_animation_selected(0);
}
- if (animation->get_item_count()) {
+ if (!no_anims_found) {
String current = animation->get_item_text(animation->get_selected());
Ref<Animation> anim = player->get_animation(current);
track_editor->set_animation(anim);
@@ -877,6 +829,28 @@ void AnimationPlayerEditor::_update_player() {
_update_animation();
}
+void AnimationPlayerEditor::_update_animation_list_icons() {
+ for (int i = 0; i < animation->get_item_count(); i++) {
+ String name = animation->get_item_text(i);
+ if (animation->is_item_disabled(i) || animation->is_item_separator(i)) {
+ continue;
+ }
+
+ Ref<Texture2D> icon;
+ if (name == player->get_autoplay()) {
+ if (name == SceneStringNames::get_singleton()->RESET) {
+ icon = autoplay_reset_icon;
+ } else {
+ icon = autoplay_icon;
+ }
+ } else if (name == SceneStringNames::get_singleton()->RESET) {
+ icon = reset_icon;
+ }
+
+ animation->set_item_icon(i, icon);
+ }
+}
+
void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
if (player && pin->is_pressed()) {
return; // Ignore, pinned.
@@ -887,7 +861,7 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
_update_player();
if (onion.enabled) {
- if (animation->get_item_count() > 0) {
+ if (animation->has_selectable_items()) {
_start_onion_skinning();
} else {
_stop_onion_skinning();
@@ -902,6 +876,8 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
track_editor->show_select_node_warning(true);
}
+
+ library_editor->set_animation_player(player);
}
void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) {
@@ -955,7 +931,7 @@ void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay)
}
void AnimationPlayerEditor::_animation_duplicate() {
- if (!animation->get_item_count()) {
+ if (!animation->has_selectable_items()) {
return;
}
@@ -965,37 +941,32 @@ void AnimationPlayerEditor::_animation_duplicate() {
return;
}
- Ref<Animation> new_anim = memnew(Animation);
- List<PropertyInfo> plist;
- anim->get_property_list(&plist);
- for (const PropertyInfo &E : plist) {
- if (E.usage & PROPERTY_USAGE_STORAGE) {
- new_anim->set(E.name, anim->get(E.name));
- }
- }
- new_anim->set_path("");
-
String new_name = current;
while (player->has_animation(new_name)) {
new_name = new_name + " (copy)";
}
- new_anim->set_name(new_name);
- undo_redo->create_action(TTR("Duplicate Animation"));
- undo_redo->add_do_method(player, "add_animation", new_name, new_anim);
- undo_redo->add_undo_method(player, "remove_animation", new_name);
- undo_redo->add_do_method(player, "animation_set_next", new_name, player->animation_get_next(current));
- undo_redo->add_do_method(this, "_animation_player_changed", player);
- undo_redo->add_undo_method(this, "_animation_player_changed", player);
- undo_redo->commit_action();
+ name_title->set_text(TTR("New Animation Name:"));
+ name->set_text(new_name);
+ name_dialog_op = TOOL_DUPLICATE_ANIM;
+ name_dialog->popup_centered(Size2(300, 90));
+ name->select_all();
+ name->grab_focus();
+}
- for (int i = 0; i < animation->get_item_count(); i++) {
- if (animation->get_item_text(i) == new_name) {
- animation->select(i);
- _animation_selected(i);
- return;
+Ref<Animation> AnimationPlayerEditor::_animation_clone(Ref<Animation> p_anim) {
+ Ref<Animation> new_anim = memnew(Animation);
+ List<PropertyInfo> plist;
+ p_anim->get_property_list(&plist);
+
+ for (const PropertyInfo &E : plist) {
+ if (E.usage & PROPERTY_USAGE_STORAGE) {
+ new_anim->set(E.name, p_anim->get(E.name));
}
}
+ new_anim->set_path("");
+
+ return new_anim;
}
void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool p_timeline_only) {
@@ -1005,7 +976,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool
updating = true;
String current = player->get_assigned_animation();
- if (current == "" || !player->has_animation(current)) {
+ if (current.is_empty() || !player->has_animation(current)) {
updating = false;
current = "";
return;
@@ -1014,7 +985,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool
Ref<Animation> anim;
anim = player->get_animation(current);
- float pos = CLAMP(anim->get_length() * (p_value / frame->get_max()), 0, anim->get_length());
+ float pos = CLAMP((double)anim->get_length() * (p_value / frame->get_max()), 0, (double)anim->get_length());
if (track_editor->is_snap_enabled()) {
pos = Math::snapped(pos, _get_editor_step());
}
@@ -1039,6 +1010,9 @@ void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) {
if (blend_editor.dialog->is_visible()) {
_animation_blend(); // Update.
}
+ if (library_editor->is_visible()) {
+ library_editor->update_tree();
+ }
}
}
@@ -1078,13 +1052,10 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag,
}
void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
- String current;
- if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) {
- current = animation->get_item_text(animation->get_selected());
- }
+ String current = _get_current();
Ref<Animation> anim;
- if (current != String()) {
+ if (!current.is_empty()) {
anim = player->get_animation(current);
}
@@ -1092,24 +1063,13 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
case TOOL_NEW_ANIM: {
_animation_new();
} break;
- case TOOL_LOAD_ANIM: {
- _animation_load();
- } break;
- case TOOL_SAVE_ANIM: {
- if (anim.is_valid()) {
- _animation_save(anim);
- }
- } break;
- case TOOL_SAVE_AS_ANIM: {
- if (anim.is_valid()) {
- _animation_save_as(anim);
- }
+ case TOOL_ANIM_LIBRARY: {
+ library_editor->set_animation_player(player);
+ library_editor->show_dialog();
} break;
case TOOL_DUPLICATE_ANIM: {
_animation_duplicate();
-
- [[fallthrough]]; // Allow immediate rename after animation is duplicated
- }
+ } break;
case TOOL_RENAME_ANIM: {
_animation_rename();
} break;
@@ -1119,56 +1079,10 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
case TOOL_REMOVE_ANIM: {
_animation_remove();
} break;
- case TOOL_COPY_ANIM: {
- if (!animation->get_item_count()) {
- error_dialog->set_text(TTR("No animation to copy!"));
- error_dialog->popup_centered();
- return;
- }
-
- String current2 = animation->get_item_text(animation->get_selected());
- Ref<Animation> anim2 = player->get_animation(current2);
- EditorSettings::get_singleton()->set_resource_clipboard(anim2);
- } break;
- case TOOL_PASTE_ANIM: {
- Ref<Animation> anim2 = EditorSettings::get_singleton()->get_resource_clipboard();
- if (!anim2.is_valid()) {
- error_dialog->set_text(TTR("No animation resource on clipboard!"));
- error_dialog->popup_centered();
- return;
- }
-
- String name = anim2->get_name();
- if (name == "") {
- name = TTR("Pasted Animation");
- }
-
- int idx = 1;
- String base = name;
- while (player->has_animation(name)) {
- idx++;
- name = base + " " + itos(idx);
- }
-
- undo_redo->create_action(TTR("Paste Animation"));
- undo_redo->add_do_method(player, "add_animation", name, anim2);
- undo_redo->add_undo_method(player, "remove_animation", name);
- undo_redo->add_do_method(this, "_animation_player_changed", player);
- undo_redo->add_undo_method(this, "_animation_player_changed", player);
- undo_redo->commit_action();
-
- _select_anim_by_name(name);
- } break;
case TOOL_EDIT_RESOURCE: {
- if (!animation->get_item_count()) {
- error_dialog->set_text(TTR("No animation to edit!"));
- error_dialog->popup_centered();
- return;
+ if (anim.is_valid()) {
+ EditorNode::get_singleton()->edit_resource(anim);
}
-
- String current2 = animation->get_item_text(animation->get_selected());
- Ref<Animation> anim2 = player->get_animation(current2);
- editor->edit_resource(anim2);
} break;
}
}
@@ -1222,13 +1136,13 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) {
}
}
-void AnimationPlayerEditor::unhandled_key_input(const Ref<InputEvent> &p_ev) {
+void AnimationPlayerEditor::shortcut_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventKey> k = p_ev;
if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo() && !k->is_alt_pressed() && !k->is_ctrl_pressed() && !k->is_meta_pressed()) {
switch (k->get_keycode()) {
- case KEY_A: {
+ case Key::A: {
if (!k->is_shift_pressed()) {
_play_bw_from_pressed();
} else {
@@ -1236,11 +1150,11 @@ void AnimationPlayerEditor::unhandled_key_input(const Ref<InputEvent> &p_ev) {
}
accept_event();
} break;
- case KEY_S: {
+ case Key::S: {
_stop_pressed();
accept_event();
} break;
- case KEY_D: {
+ case Key::D: {
if (!k->is_shift_pressed()) {
_play_from_pressed();
} else {
@@ -1255,7 +1169,7 @@ void AnimationPlayerEditor::unhandled_key_input(const Ref<InputEvent> &p_ev) {
}
void AnimationPlayerEditor::_editor_visibility_changed() {
- if (is_visible() && animation->get_item_count() > 0) {
+ if (is_visible() && animation->has_selectable_items()) {
_start_onion_skinning();
}
}
@@ -1424,7 +1338,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
float pos = cpos + step_off * anim->get_step();
- bool valid = anim->has_loop() || (pos >= 0 && pos <= anim->get_length());
+ bool valid = anim->get_loop_mode() != Animation::LoopMode::LOOP_NONE || (pos >= 0 && pos <= anim->get_length());
onion.captures_valid.write[cidx] = valid;
if (valid) {
player->seek(pos, true);
@@ -1485,13 +1399,12 @@ void AnimationPlayerEditor::_stop_onion_skinning() {
}
void AnimationPlayerEditor::_pin_pressed() {
- EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->update_tree();
+ SceneTreeDock::get_singleton()->get_tree_editor()->update_tree();
}
void AnimationPlayerEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_animation_new"), &AnimationPlayerEditor::_animation_new);
ClassDB::bind_method(D_METHOD("_animation_rename"), &AnimationPlayerEditor::_animation_rename);
- ClassDB::bind_method(D_METHOD("_animation_load"), &AnimationPlayerEditor::_animation_load);
ClassDB::bind_method(D_METHOD("_animation_remove"), &AnimationPlayerEditor::_animation_remove);
ClassDB::bind_method(D_METHOD("_animation_blend"), &AnimationPlayerEditor::_animation_blend);
ClassDB::bind_method(D_METHOD("_animation_edit"), &AnimationPlayerEditor::_animation_edit);
@@ -1512,8 +1425,7 @@ AnimationPlayer *AnimationPlayerEditor::get_player() const {
return player;
}
-AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlayerEditorPlugin *p_plugin) {
- editor = p_editor;
+AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plugin) {
plugin = p_plugin;
singleton = this;
@@ -1579,20 +1491,16 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
tool_anim->set_text(TTR("Animation"));
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/new_animation", TTR("New")), TOOL_NEW_ANIM);
tool_anim->get_popup()->add_separator();
- tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/open_animation", TTR("Load")), TOOL_LOAD_ANIM);
- tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/save_animation", TTR("Save")), TOOL_SAVE_ANIM);
- tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/save_as_animation", TTR("Save As...")), TOOL_SAVE_AS_ANIM);
+ tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/animation_libraries", TTR("Manage Animations...")), TOOL_ANIM_LIBRARY);
tool_anim->get_popup()->add_separator();
- tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/copy_animation", TTR("Copy")), TOOL_COPY_ANIM);
- tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/paste_animation", TTR("Paste")), TOOL_PASTE_ANIM);
- tool_anim->get_popup()->add_separator();
- tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/duplicate_animation", TTR("Duplicate")), TOOL_DUPLICATE_ANIM);
+ tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/duplicate_animation", TTR("Duplicate...")), TOOL_DUPLICATE_ANIM);
tool_anim->get_popup()->add_separator();
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/rename_animation", TTR("Rename...")), TOOL_RENAME_ANIM);
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/edit_transitions", TTR("Edit Transitions...")), TOOL_EDIT_TRANSITIONS);
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/open_animation_in_inspector", TTR("Open in Inspector")), TOOL_EDIT_RESOURCE);
tool_anim->get_popup()->add_separator();
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/remove_animation", TTR("Remove")), TOOL_REMOVE_ANIM);
+ tool_anim->set_disabled(true);
hb->add_child(tool_anim);
animation = memnew(OptionButton);
@@ -1625,11 +1533,11 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
onion_skinning->set_tooltip(TTR("Onion Skinning Options"));
onion_skinning->get_popup()->add_separator(TTR("Directions"));
onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST);
- onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true);
+ onion_skinning->get_popup()->set_item_checked(-1, true);
onion_skinning->get_popup()->add_check_item(TTR("Future"), ONION_SKINNING_FUTURE);
onion_skinning->get_popup()->add_separator(TTR("Depth"));
onion_skinning->get_popup()->add_radio_check_item(TTR("1 step"), ONION_SKINNING_1_STEP);
- onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true);
+ onion_skinning->get_popup()->set_item_checked(-1, true);
onion_skinning->get_popup()->add_radio_check_item(TTR("2 steps"), ONION_SKINNING_2_STEPS);
onion_skinning->get_popup()->add_radio_check_item(TTR("3 steps"), ONION_SKINNING_3_STEPS);
onion_skinning->get_popup()->add_separator();
@@ -1660,8 +1568,14 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
name_title = memnew(Label(TTR("Animation Name:")));
vb->add_child(name_title);
+ HBoxContainer *name_hb = memnew(HBoxContainer);
name = memnew(LineEdit);
- vb->add_child(name);
+ name_hb->add_child(name);
+ name->set_h_size_flags(SIZE_EXPAND_FILL);
+ library = memnew(OptionButton);
+ name_hb->add_child(library);
+ library->hide();
+ vb->add_child(name_hb);
name_dialog->register_text_enter(name);
error_dialog = memnew(ConfirmationDialog);
@@ -1697,16 +1611,13 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
animation->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_animation_selected));
- file->connect("file_selected", callable_mp(this, &AnimationPlayerEditor::_save_animation));
- file->connect("files_selected", callable_mp(this, &AnimationPlayerEditor::_load_animations));
frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed), make_binds(true, false));
scale->connect("text_submitted", callable_mp(this, &AnimationPlayerEditor::_scale_changed));
- renaming = false;
last_active = false;
timeline_position = 0;
- set_process_unhandled_key_input(true);
+ set_process_shortcut_input(true);
add_child(track_editor);
track_editor->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -1715,6 +1626,10 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
_update_player();
+ library_editor = memnew(AnimationLibraryEditor);
+ add_child(library_editor);
+ library_editor->connect("update_editor", callable_mp(this, &AnimationPlayerEditor::_animation_player_changed));
+
// Onion skinning.
track_editor->connect("visibility_changed", callable_mp(this, &AnimationPlayerEditor::_editor_visibility_changed));
@@ -1772,11 +1687,39 @@ AnimationPlayerEditor::~AnimationPlayerEditor() {
void AnimationPlayerEditorPlugin::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ Node3DEditor::get_singleton()->connect("transform_key_request", callable_mp(this, &AnimationPlayerEditorPlugin::_transform_key_request));
+ InspectorDock::get_inspector_singleton()->connect("property_keyed", callable_mp(this, &AnimationPlayerEditorPlugin::_property_keyed));
+ anim_editor->get_track_editor()->connect("keying_changed", callable_mp(this, &AnimationPlayerEditorPlugin::_update_keying));
+ InspectorDock::get_inspector_singleton()->connect("edited_object_changed", callable_mp(anim_editor->get_track_editor(), &AnimationTrackEditor::update_keying));
set_force_draw_over_forwarding_enabled();
} break;
}
}
+void AnimationPlayerEditorPlugin::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) {
+ if (!anim_editor->get_track_editor()->has_keying()) {
+ return;
+ }
+ anim_editor->get_track_editor()->insert_value_key(p_keyed, p_value, p_advance);
+}
+
+void AnimationPlayerEditorPlugin::_transform_key_request(Object *sp, const String &p_sub, const Transform3D &p_key) {
+ if (!anim_editor->get_track_editor()->has_keying()) {
+ return;
+ }
+ Node3D *s = Object::cast_to<Node3D>(sp);
+ if (!s) {
+ return;
+ }
+ anim_editor->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_POSITION_3D, p_key.origin);
+ anim_editor->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_ROTATION_3D, p_key.basis.get_rotation_quaternion());
+ anim_editor->get_track_editor()->insert_transform_key(s, p_sub, Animation::TYPE_SCALE_3D, p_key.basis.get_scale());
+}
+
+void AnimationPlayerEditorPlugin::_update_keying() {
+ InspectorDock::get_inspector_singleton()->set_keying(anim_editor->get_track_editor()->has_keying());
+}
+
void AnimationPlayerEditorPlugin::edit(Object *p_object) {
anim_editor->set_undo_redo(&get_undo_redo());
if (!p_object) {
@@ -1791,17 +1734,16 @@ bool AnimationPlayerEditorPlugin::handles(Object *p_object) const {
void AnimationPlayerEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- editor->make_bottom_panel_item_visible(anim_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(anim_editor);
anim_editor->set_process(true);
anim_editor->ensure_visibility();
}
}
-AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- anim_editor = memnew(AnimationPlayerEditor(editor, this));
+AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin() {
+ anim_editor = memnew(AnimationPlayerEditor(this));
anim_editor->set_undo_redo(EditorNode::get_undo_redo());
- editor->add_bottom_panel_item(TTR("Animation"), anim_editor);
+ EditorNode::get_singleton()->add_bottom_panel_item(TTR("Animation"), anim_editor);
}
AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() {
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 26bcff891d..0cc04460ca 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,35 +31,31 @@
#ifndef ANIMATION_PLAYER_EDITOR_PLUGIN_H
#define ANIMATION_PLAYER_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
+#include "editor/animation_track_editor.h"
#include "editor/editor_plugin.h"
+#include "editor/plugins/animation_library_editor.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/texture_button.h"
+#include "scene/gui/tree.h"
-class AnimationTrackEditor;
class AnimationPlayerEditorPlugin;
class AnimationPlayerEditor : public VBoxContainer {
GDCLASS(AnimationPlayerEditor, VBoxContainer);
- EditorNode *editor;
- AnimationPlayerEditorPlugin *plugin;
- AnimationPlayer *player;
+ AnimationPlayerEditorPlugin *plugin = nullptr;
+ AnimationPlayer *player = nullptr;
enum {
TOOL_NEW_ANIM,
- TOOL_LOAD_ANIM,
- TOOL_SAVE_ANIM,
- TOOL_SAVE_AS_ANIM,
+ TOOL_ANIM_LIBRARY,
TOOL_DUPLICATE_ANIM,
TOOL_RENAME_ANIM,
TOOL_EDIT_TRANSITIONS,
TOOL_REMOVE_ANIM,
- TOOL_COPY_ANIM,
- TOOL_PASTE_ANIM,
TOOL_EDIT_RESOURCE
};
@@ -87,31 +83,35 @@ class AnimationPlayerEditor : public VBoxContainer {
RESOURCE_SAVE
};
- OptionButton *animation;
- Button *stop;
- Button *play;
- Button *play_from;
- Button *play_bw;
- Button *play_bw_from;
- Button *autoplay;
-
- MenuButton *tool_anim;
- Button *onion_toggle;
- MenuButton *onion_skinning;
- Button *pin;
- SpinBox *frame;
- LineEdit *scale;
- LineEdit *name;
- Label *name_title;
- UndoRedo *undo_redo;
+ OptionButton *animation = nullptr;
+ Button *stop = nullptr;
+ Button *play = nullptr;
+ Button *play_from = nullptr;
+ Button *play_bw = nullptr;
+ Button *play_bw_from = nullptr;
+ Button *autoplay = nullptr;
+
+ MenuButton *tool_anim = nullptr;
+ Button *onion_toggle = nullptr;
+ MenuButton *onion_skinning = nullptr;
+ Button *pin = nullptr;
+ SpinBox *frame = nullptr;
+ LineEdit *scale = nullptr;
+ LineEdit *name = nullptr;
+ OptionButton *library = nullptr;
+ Label *name_title = nullptr;
+ UndoRedo *undo_redo = nullptr;
+
Ref<Texture2D> autoplay_icon;
Ref<Texture2D> reset_icon;
Ref<ImageTexture> autoplay_reset_icon;
bool last_active;
float timeline_position;
- EditorFileDialog *file;
- ConfirmationDialog *delete_dialog;
+ EditorFileDialog *file = nullptr;
+ ConfirmationDialog *delete_dialog = nullptr;
+
+ AnimationLibraryEditor *library_editor = nullptr;
struct BlendEditor {
AcceptDialog *dialog = nullptr;
@@ -120,14 +120,14 @@ class AnimationPlayerEditor : public VBoxContainer {
} blend_editor;
- ConfirmationDialog *name_dialog;
- ConfirmationDialog *error_dialog;
- bool renaming;
+ ConfirmationDialog *name_dialog = nullptr;
+ ConfirmationDialog *error_dialog = nullptr;
+ int name_dialog_op = TOOL_NEW_ANIM;
bool updating;
bool updating_blends;
- AnimationTrackEditor *track_editor;
+ AnimationTrackEditor *track_editor = nullptr;
static AnimationPlayerEditor *singleton;
// Onion skinning.
@@ -172,27 +172,22 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_new();
void _animation_rename();
void _animation_name_edited();
- void _animation_load();
-
- void _animation_save_in_path(const Ref<Resource> &p_resource, const String &p_path);
- void _animation_save(const Ref<Resource> &p_resource);
- void _animation_save_as(const Ref<Resource> &p_resource);
void _animation_remove();
void _animation_remove_confirmed();
void _animation_blend();
void _animation_edit();
void _animation_duplicate();
+ Ref<Animation> _animation_clone(const Ref<Animation> p_anim);
void _animation_resource_edit();
void _scale_changed(const String &p_scale);
- void _save_animation(String p_file);
- void _load_animations(Vector<String> p_files);
void _seek_value_changed(float p_value, bool p_set = false, bool p_timeline_only = false);
void _blend_editor_next_changed(const int p_idx);
void _list_changed();
void _update_animation();
void _update_player();
+ void _update_animation_list_icons();
void _blend_edited();
void _animation_player_changed(Object *p_pl);
@@ -200,7 +195,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_key_editor_seek(float p_pos, bool p_drag, bool p_timeline_only = false);
void _animation_key_editor_anim_len_changed(float p_len);
- virtual void unhandled_key_input(const Ref<InputEvent> &p_ev) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_ev) override;
void _animation_tool_menu(int p_option);
void _onion_skinning_menu(int p_option);
@@ -215,6 +210,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _stop_onion_skinning();
void _pin_pressed();
+ String _get_current() const;
~AnimationPlayerEditor();
@@ -240,18 +236,21 @@ public:
void edit(AnimationPlayer *p_player);
void forward_force_draw_over_viewport(Control *p_overlay);
- AnimationPlayerEditor(EditorNode *p_editor, AnimationPlayerEditorPlugin *p_plugin);
+ AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plugin);
};
class AnimationPlayerEditorPlugin : public EditorPlugin {
GDCLASS(AnimationPlayerEditorPlugin, EditorPlugin);
- AnimationPlayerEditor *anim_editor;
- EditorNode *editor;
+ AnimationPlayerEditor *anim_editor = nullptr;
protected:
void _notification(int p_what);
+ void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance);
+ void _transform_key_request(Object *sp, const String &p_sub, const Transform3D &p_key);
+ void _update_keying();
+
public:
virtual Dictionary get_state() const override { return anim_editor->get_state(); }
virtual void set_state(const Dictionary &p_state) override { anim_editor->set_state(p_state); }
@@ -265,7 +264,7 @@ public:
virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
virtual void forward_spatial_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
- AnimationPlayerEditorPlugin(EditorNode *p_node);
+ AnimationPlayerEditorPlugin();
~AnimationPlayerEditorPlugin();
};
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index a1f96f21bf..920fe347ca 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -35,11 +35,15 @@
#include "core/io/resource_loader.h"
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
+#include "scene/gui/tree.h"
+#include "scene/main/viewport.h"
#include "scene/main/window.h"
bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
@@ -53,7 +57,10 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
if (state_machine.is_valid()) {
selected_transition_from = StringName();
selected_transition_to = StringName();
+ selected_transition_index = -1;
+ selected_multi_transition = TransitionLine();
selected_node = StringName();
+ selected_nodes.clear();
_update_mode();
_update_graph();
}
@@ -66,71 +73,40 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
Ref<InputEventKey> k = p_event;
- if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && !k->is_echo()) {
- if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
+ if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
+ if (selected_node != StringName() || !selected_nodes.is_empty() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
_erase_selected();
accept_event();
}
}
- Ref<InputEventMouseButton> mb = p_event;
-
- //Add new node
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
- List<StringName> classes;
- classes.sort_custom<StringName::AlphCompare>();
-
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- menu->add_submenu_item(TTR("Add Animation"), "animations");
-
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
- if (gp && gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
- for (const StringName &E : names) {
- animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
- animations_to_add.push_back(E);
- }
- }
- }
+ // Group selected nodes on a state machine
+ if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->is_ctrl_pressed() && !k->is_shift_pressed() && k->get_keycode() == Key::G && !k->is_echo()) {
+ _group_selected_nodes();
+ }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation") {
- continue; // nope
- }
- int idx = menu->get_item_count();
- menu->add_item(vformat("Add %s", name), idx);
- menu->set_item_metadata(idx, E);
- }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ // Ungroup state machine
+ if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->is_ctrl_pressed() && k->is_shift_pressed() && k->get_keycode() == Key::G && !k->is_echo()) {
+ _ungroup_selected_nodes();
+ }
- if (clipb.is_valid()) {
- menu->add_separator();
- menu->add_item(TTR("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ Ref<InputEventMouseButton> mb = p_event;
- menu->set_position(state_machine_draw->get_screen_transform().xform(mb->get_position()));
- menu->popup();
- add_node_pos = mb->get_position() / EDSCALE + state_machine->get_graph_offset();
+ // Add new node
+ if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) {
+ connecting_from = StringName();
+ _open_menu(mb->get_position());
}
- // select node or push a field inside
- if (mb.is_valid() && !mb->is_shift_pressed() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ // Select node or push a field inside
+ if (mb.is_valid() && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
selected_transition_from = StringName();
selected_transition_to = StringName();
+ selected_transition_index = -1;
+ selected_multi_transition = TransitionLine();
selected_node = StringName();
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
-
if (node_rects[i].play.has_point(mb->get_position())) { //edit name
if (play_mode->get_selected() == 1 || !playback->is_playing()) {
//start
@@ -143,15 +119,14 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
return;
}
- if (node_rects[i].name.has_point(mb->get_position())) { //edit name
-
+ if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
Rect2 edit_rect = node_rects[i].name;
edit_rect.position -= line_sb->get_offset();
edit_rect.size += line_sb->get_minimum_size();
- name_edit_popup->set_position(state_machine_draw->get_screen_transform().xform(edit_rect.position));
+ name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position);
name_edit_popup->set_size(edit_rect.size);
name_edit->set_text(node_rects[i].node_name);
name_edit_popup->popup();
@@ -170,6 +145,12 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
selected_node = node_rects[i].node_name;
+ if (!selected_nodes.has(selected_node)) {
+ selected_nodes.clear();
+ }
+
+ selected_nodes.insert(selected_node);
+
Ref<AnimationNode> anode = state_machine->get_node(selected_node);
EditorNode::get_singleton()->push_item(anode.ptr(), "", true);
state_machine_draw->update();
@@ -206,23 +187,53 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (closest >= 0) {
selected_transition_from = transition_lines[closest].from_node;
selected_transition_to = transition_lines[closest].to_node;
+ selected_transition_index = closest;
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest);
EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
+
+ if (!transition_lines[closest].multi_transitions.is_empty()) {
+ selected_transition_index = -1;
+ selected_multi_transition = transition_lines[closest];
+
+ Ref<EditorAnimationMultiTransitionEdit> multi;
+ multi.instantiate();
+ multi->add_transition(selected_transition_from, selected_transition_to, tr);
+
+ for (int i = 0; i < transition_lines[closest].multi_transitions.size(); i++) {
+ int index = transition_lines[closest].multi_transitions[i].transition_index;
+
+ Ref<AnimationNodeStateMachineTransition> transition = state_machine->get_transition(index);
+ StringName from = transition_lines[closest].multi_transitions[i].from_node;
+ StringName to = transition_lines[closest].multi_transitions[i].to_node;
+
+ multi->add_transition(from, to, transition);
+ }
+ EditorNode::get_singleton()->push_item(multi.ptr(), "", true);
+ }
}
state_machine_draw->update();
_update_mode();
}
- //end moving node
- if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
+ // End moving node
+ if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
if (dragging_selected) {
Ref<AnimationNode> an = state_machine->get_node(selected_node);
updating = true;
+
undo_redo->create_action(TTR("Move Node"));
- undo_redo->add_do_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE);
- undo_redo->add_undo_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node));
+
+ for (int i = 0; i < node_rects.size(); i++) {
+ if (!selected_nodes.has(node_rects[i].node_name)) {
+ continue;
+ }
+
+ undo_redo->add_do_method(state_machine.ptr(), "set_node_position", node_rects[i].node_name, state_machine->get_node_position(node_rects[i].node_name) + drag_ofs / EDSCALE);
+ undo_redo->add_undo_method(state_machine.ptr(), "set_node_position", node_rects[i].node_name, state_machine->get_node_position(node_rects[i].node_name));
+ }
+
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -236,8 +247,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
state_machine_draw->update();
}
- //connect nodes
- if (mb.is_valid() && ((tool_select->is_pressed() && mb->is_shift_pressed()) || tool_connect->is_pressed()) && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
+ // Connect nodes
+ if (mb.is_valid() && ((tool_select->is_pressed() && mb->is_shift_pressed()) || tool_connect->is_pressed()) && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
connecting = true;
@@ -249,47 +260,63 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- //end connecting nodes
- if (mb.is_valid() && connecting && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
+ // End connecting nodes
+ if (mb.is_valid() && connecting && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
if (connecting_to_node != StringName()) {
- if (state_machine->has_transition(connecting_from, connecting_to_node)) {
- EditorNode::get_singleton()->show_warning(TTR("Transition exists!"));
+ Ref<AnimationNode> node = state_machine->get_node(connecting_to_node);
+ Ref<AnimationNodeStateMachine> anodesm = node;
+ Ref<AnimationNodeEndState> end_node = node;
+ if (state_machine->has_transition(connecting_from, connecting_to_node) && state_machine->can_edit_node(connecting_to_node) && !anodesm.is_valid()) {
+ EditorNode::get_singleton()->show_warning(TTR("Transition exists!"));
+ connecting = false;
} else {
- Ref<AnimationNodeStateMachineTransition> tr;
- tr.instantiate();
- tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()));
-
- updating = true;
- undo_redo->create_action(TTR("Add Transition"));
- undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr);
- undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- updating = false;
-
- selected_transition_from = connecting_from;
- selected_transition_to = connecting_to_node;
-
- EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
- _update_mode();
+ if (anodesm.is_valid() || end_node.is_valid()) {
+ _open_connect_menu(mb->get_position());
+ } else {
+ _add_transition();
+ }
}
+ } else {
+ _open_menu(mb->get_position());
}
connecting_to_node = StringName();
- connecting = false;
state_machine_draw->update();
}
+ // Start box selecting
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && tool_select->is_pressed()) {
+ box_selecting = true;
+ box_selecting_from = box_selecting_to = state_machine_draw->get_local_mouse_position();
+ box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x),
+ MIN(box_selecting_from.y, box_selecting_to.y),
+ ABS(box_selecting_from.x - box_selecting_to.x),
+ ABS(box_selecting_from.y - box_selecting_to.y));
+
+ if (mb->is_ctrl_pressed() || mb->is_shift_pressed()) {
+ previous_selected = selected_nodes;
+ } else {
+ selected_nodes.clear();
+ previous_selected.clear();
+ }
+ }
+
+ // End box selecting
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed() && box_selecting) {
+ box_selecting = false;
+ state_machine_draw->update();
+ _update_mode();
+ }
+
Ref<InputEventMouseMotion> mm = p_event;
- //pan window
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
+ // Pan window
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_MIDDLE) != MouseButton::NONE) {
h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
}
- //move mouse while connecting
+ // Move mouse while connecting
if (mm.is_valid() && connecting) {
connecting_to = mm->get_position();
connecting_to_node = StringName();
@@ -303,7 +330,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- //move mouse while moving a node
+ // Move mouse while moving a node
if (mm.is_valid() && dragging_selected_attempt) {
dragging_selected = true;
drag_ofs = mm->get_position() - drag_from;
@@ -343,29 +370,56 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
state_machine_draw->update();
}
- //put ibeam (text cursor) over names to make it clearer that they are editable
+ // Move mouse while moving box select
+ if (mm.is_valid() && box_selecting) {
+ box_selecting_to = state_machine_draw->get_local_mouse_position();
+
+ box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x),
+ MIN(box_selecting_from.y, box_selecting_to.y),
+ ABS(box_selecting_from.x - box_selecting_to.x),
+ ABS(box_selecting_from.y - box_selecting_to.y));
+
+ for (int i = 0; i < node_rects.size(); i++) {
+ bool in_box = node_rects[i].node.intersects(box_selecting_rect);
+
+ if (in_box) {
+ if (previous_selected.has(node_rects[i].node_name)) {
+ selected_nodes.erase(node_rects[i].node_name);
+ } else {
+ selected_nodes.insert(node_rects[i].node_name);
+ }
+ } else {
+ if (previous_selected.has(node_rects[i].node_name)) {
+ selected_nodes.insert(node_rects[i].node_name);
+ } else {
+ selected_nodes.erase(node_rects[i].node_name);
+ }
+ }
+ }
+
+ state_machine_draw->update();
+ }
+
if (mm.is_valid()) {
state_machine_draw->grab_focus();
- bool over_text_now = false;
String new_over_node = StringName();
int new_over_node_what = -1;
if (tool_select->is_pressed()) {
- for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
+ for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
- if (node_rects[i].name.has_point(mm->get_position())) {
- over_text_now = true;
- break;
+ if (!state_machine->can_edit_node(node_rects[i].node_name)) {
+ continue; // start/end node can't be edited
}
if (node_rects[i].node.has_point(mm->get_position())) {
new_over_node = node_rects[i].node_name;
if (node_rects[i].play.has_point(mm->get_position())) {
new_over_node_what = 0;
- }
- if (node_rects[i].edit.has_point(mm->get_position())) {
+ } else if (node_rects[i].edit.has_point(mm->get_position())) {
new_over_node_what = 1;
}
+ break;
}
}
}
@@ -376,14 +430,41 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
state_machine_draw->update();
}
- if (over_text != over_text_now) {
- if (over_text_now) {
- state_machine_draw->set_default_cursor_shape(CURSOR_IBEAM);
- } else {
- state_machine_draw->set_default_cursor_shape(CURSOR_ARROW);
+ // set tooltip for transition
+ if (tool_select->is_pressed()) {
+ int closest = -1;
+ float closest_d = 1e20;
+ for (int i = 0; i < transition_lines.size(); i++) {
+ Vector2 s[2] = {
+ transition_lines[i].from,
+ transition_lines[i].to
+ };
+ Vector2 cpoint = Geometry2D::get_closest_point_to_segment(mm->get_position(), s);
+ float d = cpoint.distance_to(mm->get_position());
+ if (d > transition_lines[i].width) {
+ continue;
+ }
+
+ if (d < closest_d) {
+ closest = i;
+ closest_d = d;
+ }
}
- over_text = over_text_now;
+ if (closest >= 0) {
+ String from = String(transition_lines[closest].from_node);
+ String to = String(transition_lines[closest].to_node);
+ String tooltip = from + " -> " + to;
+
+ for (int i = 0; i < transition_lines[closest].multi_transitions.size(); i++) {
+ from = String(transition_lines[closest].multi_transitions[i].from_node);
+ to = String(transition_lines[closest].multi_transitions[i].to_node);
+ tooltip += "\n" + from + " -> " + to;
+ }
+ state_machine_draw->set_tooltip(tooltip);
+ } else {
+ state_machine_draw->set_tooltip("");
+ }
}
}
@@ -394,6 +475,475 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
+Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Point2 &p_pos) const {
+ // Put ibeam (text cursor) over names to make it clearer that they are editable.
+ Transform2D xform = panel->get_transform() * state_machine_draw->get_transform();
+ Point2 pos = xform.xform_inv(p_pos);
+ Control::CursorShape cursor_shape = get_default_cursor_shape();
+
+ for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
+ if (node_rects[i].node.has_point(pos)) {
+ if (node_rects[i].name.has_point(pos)) {
+ cursor_shape = Control::CURSOR_IBEAM;
+ }
+ break;
+ }
+ }
+ return cursor_shape;
+}
+
+void AnimationNodeStateMachineEditor::_group_selected_nodes() {
+ if (!selected_nodes.is_empty()) {
+ if (selected_nodes.size() == 1 && (selected_nodes.front()->get() == state_machine->start_node || selected_nodes.front()->get() == state_machine->end_node))
+ return;
+
+ Ref<AnimationNodeStateMachine> group_sm = memnew(AnimationNodeStateMachine);
+ Vector2 group_position;
+
+ Vector<NodeUR> nodes_ur;
+ Vector<TransitionUR> transitions_ur;
+
+ int base = 1;
+ String base_name = group_sm->get_caption();
+ String group_name = base_name;
+
+ while (state_machine->has_node(group_name) && !selected_nodes.has(group_name)) {
+ base++;
+ group_name = base_name + " " + itos(base);
+ }
+
+ updating = true;
+ undo_redo->create_action("Group");
+
+ // Move selected nodes to the new state machine
+ for (const StringName &E : selected_nodes) {
+ if (!state_machine->can_edit_node(E)) {
+ continue;
+ }
+
+ Ref<AnimationNode> node = state_machine->get_node(E);
+ Vector2 node_position = state_machine->get_node_position(E);
+ group_position += node_position;
+
+ NodeUR new_node;
+ new_node.name = E;
+ new_node.node = node;
+ new_node.position = node_position;
+
+ nodes_ur.push_back(new_node);
+ }
+
+ // Add the transitions to the new state machine
+ for (int i = 0; i < state_machine->get_transition_count(); i++) {
+ String from = state_machine->get_transition_from(i);
+ String to = state_machine->get_transition_to(i);
+
+ String local_from = from.get_slicec('/', 0);
+ String local_to = to.get_slicec('/', 0);
+
+ String old_from = from;
+ String old_to = to;
+
+ bool from_selected = false;
+ bool to_selected = false;
+
+ if (selected_nodes.has(local_from) && local_from != state_machine->start_node) {
+ from_selected = true;
+ }
+ if (selected_nodes.has(local_to) && local_to != state_machine->end_node) {
+ to_selected = true;
+ }
+ if (!from_selected && !to_selected) {
+ continue;
+ }
+
+ Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
+
+ if (!from_selected) {
+ from = "../" + old_from;
+ }
+ if (!to_selected) {
+ to = "../" + old_to;
+ }
+
+ TransitionUR new_tr;
+ new_tr.new_from = from;
+ new_tr.new_to = to;
+ new_tr.old_from = old_from;
+ new_tr.old_to = old_to;
+ new_tr.transition = tr;
+
+ transitions_ur.push_back(new_tr);
+ }
+
+ for (int i = 0; i < nodes_ur.size(); i++) {
+ undo_redo->add_do_method(state_machine.ptr(), "remove_node", nodes_ur[i].name);
+ undo_redo->add_undo_method(group_sm.ptr(), "remove_node", nodes_ur[i].name);
+ }
+
+ undo_redo->add_do_method(state_machine.ptr(), "add_node", group_name, group_sm, group_position / nodes_ur.size());
+ undo_redo->add_undo_method(state_machine.ptr(), "remove_node", group_name);
+
+ for (int i = 0; i < nodes_ur.size(); i++) {
+ undo_redo->add_do_method(group_sm.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
+ undo_redo->add_undo_method(state_machine.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
+ }
+
+ for (int i = 0; i < transitions_ur.size(); i++) {
+ undo_redo->add_do_method(group_sm.ptr(), "add_transition", transitions_ur[i].new_from, transitions_ur[i].new_to, transitions_ur[i].transition);
+ undo_redo->add_undo_method(state_machine.ptr(), "add_transition", transitions_ur[i].old_from, transitions_ur[i].old_to, transitions_ur[i].transition);
+ }
+
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->commit_action();
+ updating = false;
+
+ selected_nodes.clear();
+ selected_nodes.insert(group_name);
+ state_machine_draw->update();
+ accept_event();
+ _update_mode();
+ }
+}
+
+void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() {
+ bool find = false;
+ Set<StringName> new_selected_nodes;
+
+ for (const StringName &E : selected_nodes) {
+ Ref<AnimationNodeStateMachine> group_sm = state_machine->get_node(E);
+
+ if (group_sm.is_valid()) {
+ find = true;
+
+ Vector2 group_position = state_machine->get_node_position(E);
+ StringName group_name = E;
+
+ List<AnimationNode::ChildNode> nodes;
+ group_sm->get_child_nodes(&nodes);
+
+ Vector<NodeUR> nodes_ur;
+ Vector<TransitionUR> transitions_ur;
+
+ updating = true;
+ undo_redo->create_action("Ungroup");
+
+ // Move all child nodes to current state machine
+ for (int i = 0; i < nodes.size(); i++) {
+ if (!group_sm->can_edit_node(nodes[i].name)) {
+ continue;
+ }
+
+ Vector2 node_position = group_sm->get_node_position(nodes[i].name);
+
+ NodeUR new_node;
+ new_node.name = nodes[i].name;
+ new_node.position = node_position;
+ new_node.node = nodes[i].node;
+
+ nodes_ur.push_back(new_node);
+ }
+
+ for (int i = 0; i < group_sm->get_transition_count(); i++) {
+ String from = group_sm->get_transition_from(i);
+ String to = group_sm->get_transition_to(i);
+ Ref<AnimationNodeStateMachineTransition> tr = group_sm->get_transition(i);
+
+ TransitionUR new_tr;
+ new_tr.new_from = from.replace_first("../", "");
+ new_tr.new_to = to.replace_first("../", "");
+ new_tr.old_from = from;
+ new_tr.old_to = to;
+ new_tr.transition = tr;
+
+ transitions_ur.push_back(new_tr);
+ }
+
+ for (int i = 0; i < nodes_ur.size(); i++) {
+ undo_redo->add_do_method(group_sm.ptr(), "remove_node", nodes_ur[i].name);
+ undo_redo->add_undo_method(state_machine.ptr(), "remove_node", nodes_ur[i].name);
+ }
+
+ undo_redo->add_do_method(state_machine.ptr(), "remove_node", group_name);
+ undo_redo->add_undo_method(state_machine.ptr(), "add_node", group_name, group_sm, group_position);
+
+ for (int i = 0; i < nodes_ur.size(); i++) {
+ new_selected_nodes.insert(nodes_ur[i].name);
+ undo_redo->add_do_method(state_machine.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
+ undo_redo->add_undo_method(group_sm.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
+ }
+
+ for (int i = 0; i < transitions_ur.size(); i++) {
+ if (transitions_ur[i].old_from != state_machine->start_node && transitions_ur[i].old_to != state_machine->end_node) {
+ undo_redo->add_do_method(state_machine.ptr(), "add_transition", transitions_ur[i].new_from, transitions_ur[i].new_to, transitions_ur[i].transition);
+ }
+
+ undo_redo->add_undo_method(group_sm.ptr(), "add_transition", transitions_ur[i].old_from, transitions_ur[i].old_to, transitions_ur[i].transition);
+ }
+
+ for (int i = 0; i < state_machine->get_transition_count(); i++) {
+ String from = state_machine->get_transition_from(i);
+ String to = state_machine->get_transition_to(i);
+ Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
+
+ if (from == group_name || to == group_name) {
+ undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, tr);
+ }
+ }
+
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->commit_action();
+ updating = false;
+ }
+ }
+
+ if (find) {
+ selected_nodes = new_selected_nodes;
+ selected_node = StringName();
+ state_machine_draw->update();
+ accept_event();
+ _update_mode();
+ }
+}
+
+void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
+ List<StringName> classes;
+ classes.sort_custom<StringName::AlphCompare>();
+
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
+
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
+ if (gp && gp->has_node(gp->get_animation_player())) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (ap) {
+ List<StringName> names;
+ ap->get_animation_list(&names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ animations_menu->add_icon_item(get_theme_icon("Animation", "EditorIcons"), E->get());
+ animations_to_add.push_back(E->get());
+ }
+ }
+ }
+
+ for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
+ String name = String(E->get()).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue; // nope
+ }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E->get());
+ }
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
+ menu->add_separator();
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+
+ menu->set_position(state_machine_draw->get_screen_transform().xform(p_position));
+ menu->popup();
+ add_node_pos = p_position / EDSCALE + state_machine->get_graph_offset();
+}
+
+void AnimationNodeStateMachineEditor::_open_connect_menu(const Vector2 &p_position) {
+ ERR_FAIL_COND(connecting_to_node == StringName());
+
+ Ref<AnimationNode> node = state_machine->get_node(connecting_to_node);
+ Ref<AnimationNodeStateMachine> anodesm = node;
+ Ref<AnimationNodeEndState> end_node = node;
+ ERR_FAIL_COND(!anodesm.is_valid() && !end_node.is_valid());
+
+ connect_menu->clear();
+ state_machine_menu->clear();
+ end_menu->clear();
+ nodes_to_connect.clear();
+
+ for (int i = connect_menu->get_child_count() - 1; i >= 0; i--) {
+ Node *child = connect_menu->get_child(i);
+
+ if (child->is_class("PopupMenu")) {
+ connect_menu->remove_child(child);
+ }
+ }
+
+ connect_menu->reset_size();
+ state_machine_menu->reset_size();
+ end_menu->reset_size();
+
+ if (anodesm.is_valid()) {
+ _create_submenu(connect_menu, anodesm, connecting_to_node, connecting_to_node);
+ } else {
+ Ref<AnimationNodeStateMachine> prev = state_machine;
+ _create_submenu(connect_menu, prev, connecting_to_node, connecting_to_node, true);
+ }
+
+ connect_menu->add_submenu_item(TTR("To") + " Animation", connecting_to_node);
+
+ if (state_machine_menu->get_item_count() > 0 || !end_node.is_valid()) {
+ connect_menu->add_submenu_item(TTR("To") + " StateMachine", "state_machines");
+ connect_menu->add_child(state_machine_menu);
+ }
+
+ if (end_node.is_valid()) {
+ connect_menu->add_submenu_item(TTR("To") + " End", "end_nodes");
+ connect_menu->add_child(end_menu);
+ } else {
+ state_machine_menu->add_item(connecting_to_node, nodes_to_connect.size());
+ }
+
+ nodes_to_connect.push_back(connecting_to_node);
+
+ if (nodes_to_connect.size() == 1) {
+ _add_transition();
+ return;
+ }
+
+ connect_menu->set_position(state_machine_draw->get_screen_transform().xform(p_position));
+ connect_menu->popup();
+}
+
+bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<AnimationNodeStateMachine> p_nodesm, const StringName &p_name, const StringName &p_path, bool from_root, Vector<Ref<AnimationNodeStateMachine>> p_parents) {
+ String prev_path;
+ Vector<Ref<AnimationNodeStateMachine>> parents = p_parents;
+
+ if (from_root) {
+ Ref<AnimationNodeStateMachine> prev = p_nodesm->get_prev_state_machine();
+
+ while (prev.is_valid()) {
+ parents.push_back(prev);
+ p_nodesm = prev;
+ prev_path += "../";
+ prev = prev->get_prev_state_machine();
+ }
+ prev_path.remove_at(prev_path.size() - 1);
+ }
+
+ List<StringName> nodes;
+ p_nodesm->get_node_list(&nodes);
+
+ PopupMenu *nodes_menu = memnew(PopupMenu);
+ nodes_menu->set_name(p_name);
+ nodes_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to));
+ p_menu->add_child(nodes_menu);
+
+ bool node_added = false;
+ for (const StringName &E : nodes) {
+ if (p_nodesm->can_edit_node(E)) {
+ Ref<AnimationNodeStateMachine> ansm = p_nodesm->get_node(E);
+
+ String path;
+ if (from_root) {
+ path = prev_path + "/" + E;
+ } else {
+ path = String(p_path) + "/" + E;
+ }
+
+ if (ansm == state_machine) {
+ end_menu->add_item(E, nodes_to_connect.size());
+ nodes_to_connect.push_back(state_machine->end_node);
+ continue;
+ }
+
+ if (ansm.is_valid()) {
+ bool found = false;
+
+ for (int i = 0; i < parents.size(); i++) {
+ if (parents[i] == ansm) {
+ path = path.replace_first("/../" + E, "");
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ state_machine_menu->add_item(E, nodes_to_connect.size());
+ nodes_to_connect.push_back(path);
+ } else {
+ end_menu->add_item(E, nodes_to_connect.size());
+ nodes_to_connect.push_back(path + "/" + state_machine->end_node);
+ }
+
+ if (_create_submenu(nodes_menu, ansm, E, path, false, parents)) {
+ nodes_menu->add_submenu_item(E, E);
+ node_added = true;
+ }
+ } else {
+ nodes_menu->add_item(E, nodes_to_connect.size());
+ nodes_to_connect.push_back(path);
+ node_added = true;
+ }
+ }
+ }
+
+ return node_added;
+}
+
+void AnimationNodeStateMachineEditor::_stop_connecting() {
+ connecting = false;
+ state_machine_draw->update();
+}
+
+void AnimationNodeStateMachineEditor::_delete_selected() {
+ TreeItem *item = delete_tree->get_next_selected(nullptr);
+ while (item) {
+ if (!updating) {
+ updating = true;
+ selected_multi_transition = TransitionLine();
+ undo_redo->create_action("Transition(s) Removed");
+ }
+
+ Vector<String> path = item->get_text(0).split(" -> ");
+
+ selected_transition_from = path[0];
+ selected_transition_to = path[1];
+ _erase_selected(true);
+
+ item = delete_tree->get_next_selected(item);
+ }
+
+ if (updating) {
+ undo_redo->commit_action();
+ updating = false;
+ }
+}
+
+void AnimationNodeStateMachineEditor::_delete_all() {
+ Vector<TransitionLine> multi_transitions = selected_multi_transition.multi_transitions;
+ selected_multi_transition = TransitionLine();
+
+ updating = true;
+ undo_redo->create_action("Transition(s) Removed");
+ _erase_selected(true);
+ for (int i = 0; i < multi_transitions.size(); i++) {
+ selected_transition_from = multi_transitions[i].from_node;
+ selected_transition_to = multi_transitions[i].to_node;
+ _erase_selected(true);
+ }
+ undo_redo->commit_action();
+ updating = false;
+
+ delete_window->hide();
+}
+
+void AnimationNodeStateMachineEditor::_delete_tree_draw() {
+ TreeItem *item = delete_tree->get_next_selected(nullptr);
+ while (item) {
+ delete_window->get_cancel_button()->set_disabled(false);
+ return;
+ }
+ delete_window->get_cancel_button()->set_disabled(true);
+}
+
void AnimationNodeStateMachineEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
@@ -437,7 +987,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
return;
}
- if (base_name == String()) {
+ if (base_name.is_empty()) {
base_name = node->get_class().replace_first("AnimationNode", "");
}
@@ -454,6 +1004,8 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
+ connecting_to_node = name;
+ _add_transition(true);
undo_redo->commit_action();
updating = false;
@@ -480,13 +1032,58 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
+ connecting_to_node = name;
+ _add_transition(true);
undo_redo->commit_action();
updating = false;
state_machine_draw->update();
}
-void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance) {
+void AnimationNodeStateMachineEditor::_connect_to(int p_index) {
+ connecting_to_node = nodes_to_connect[p_index];
+ _add_transition();
+}
+
+void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action) {
+ if (connecting_from != StringName() && connecting_to_node != StringName()) {
+ if (state_machine->has_transition(connecting_from, connecting_to_node)) {
+ EditorNode::get_singleton()->show_warning("Transition exists!");
+ connecting = false;
+ return;
+ }
+
+ Ref<AnimationNodeStateMachineTransition> tr;
+ tr.instantiate();
+ tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()));
+
+ if (!p_nested_action) {
+ updating = true;
+ }
+
+ undo_redo->create_action(TTR("Add Transition"));
+ undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr);
+ undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node);
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->commit_action();
+
+ if (!p_nested_action) {
+ updating = false;
+ }
+
+ selected_transition_from = connecting_from;
+ selected_transition_to = connecting_to_node;
+ selected_transition_index = transition_lines.size();
+
+ EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
+ _update_mode();
+ }
+
+ connecting = false;
+}
+
+void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance, bool p_multi_transitions) {
Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
Color icon_color(1, 1, 1);
Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
@@ -497,7 +1094,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
accent.a *= 0.6;
}
- Ref<Texture2D> icons[6] = {
+ const Ref<Texture2D> icons[6] = {
get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons")),
get_theme_icon(SNAME("TransitionSyncBig"), SNAME("EditorIcons")),
get_theme_icon(SNAME("TransitionEndBig"), SNAME("EditorIcons")),
@@ -514,39 +1111,46 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
linecolor = accent;
linecolor.set_hsv(1.0, linecolor.get_s(), linecolor.get_v());
}
+
state_machine_draw->draw_line(p_from, p_to, linecolor, 2);
Ref<Texture2D> icon = icons[p_mode + (p_auto_advance ? 3 : 0)];
Transform2D xf;
- xf.elements[0] = (p_to - p_from).normalized();
- xf.elements[1] = xf.elements[0].orthogonal();
- xf.elements[2] = (p_from + p_to) * 0.5 - xf.elements[1] * icon->get_height() * 0.5 - xf.elements[0] * icon->get_height() * 0.5;
+ xf.columns[0] = (p_to - p_from).normalized();
+ xf.columns[1] = xf.columns[0].orthogonal();
+ xf.columns[2] = (p_from + p_to) * 0.5 - xf.columns[1] * icon->get_height() * 0.5 - xf.columns[0] * icon->get_height() * 0.5;
state_machine_draw->draw_set_transform_matrix(xf);
- state_machine_draw->draw_texture(icon, Vector2(), icon_color);
+ if (p_multi_transitions) {
+ state_machine_draw->draw_texture(icons[0], Vector2(-icon->get_width(), 0), icon_color);
+ state_machine_draw->draw_texture(icons[0], Vector2(), icon_color);
+ state_machine_draw->draw_texture(icons[0], Vector2(icon->get_width(), 0), icon_color);
+ } else {
+ state_machine_draw->draw_texture(icon, Vector2(), icon_color);
+ }
state_machine_draw->draw_set_transform_matrix(Transform2D());
}
-void AnimationNodeStateMachineEditor::_clip_src_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) {
- if (r_to == r_from) {
+void AnimationNodeStateMachineEditor::_clip_src_line_to_rect(Vector2 &r_from, const Vector2 &p_to, const Rect2 &p_rect) {
+ if (p_to == r_from) {
return;
}
//this could be optimized...
- Vector2 n = (r_to - r_from).normalized();
+ Vector2 n = (p_to - r_from).normalized();
while (p_rect.has_point(r_from)) {
r_from += n;
}
}
-void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) {
- if (r_to == r_from) {
+void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(const Vector2 &p_from, Vector2 &r_to, const Rect2 &p_rect) {
+ if (r_to == p_from) {
return;
}
//this could be optimized...
- Vector2 n = (r_to - r_from).normalized();
+ Vector2 n = (r_to - p_from).normalized();
while (p_rect.has_point(r_to)) {
r_to -= n;
}
@@ -555,20 +1159,27 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Ve
void AnimationNodeStateMachineEditor::_state_machine_draw() {
Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
- Ref<StyleBox> style = get_theme_stylebox(SNAME("state_machine_frame"), SNAME("GraphNode"));
- Ref<StyleBox> style_selected = get_theme_stylebox(SNAME("state_machine_selectedframe"), SNAME("GraphNode"));
+ Ref<StyleBoxFlat> style = get_theme_stylebox(SNAME("state_machine_frame"), SNAME("GraphNode"));
+ Ref<StyleBoxFlat> style_selected = get_theme_stylebox(SNAME("state_machine_selected_frame"), SNAME("GraphNode"));
Ref<Font> font = get_theme_font(SNAME("title_font"), SNAME("GraphNode"));
int font_size = get_theme_font_size(SNAME("title_font_size"), SNAME("GraphNode"));
Color font_color = get_theme_color(SNAME("title_color"), SNAME("GraphNode"));
Ref<Texture2D> play = get_theme_icon(SNAME("Play"), SNAME("EditorIcons"));
- Ref<Texture2D> auto_play = get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons"));
Ref<Texture2D> edit = get_theme_icon(SNAME("Edit"), SNAME("EditorIcons"));
Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
linecolor.a *= 0.3;
Ref<StyleBox> playing_overlay = get_theme_stylebox(SNAME("position"), SNAME("GraphNode"));
+ Ref<StyleBoxFlat> start_overlay = style->duplicate();
+ start_overlay->set_border_width_all(1 * EDSCALE);
+ start_overlay->set_border_color(Color::html("#80f6cf"));
+
+ Ref<StyleBoxFlat> end_overlay = style->duplicate();
+ end_overlay->set_border_width_all(1 * EDSCALE);
+ end_overlay->set_border_color(Color::html("#f26661"));
+
bool playing = false;
StringName current;
StringName blend_from;
@@ -610,22 +1221,25 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
Ref<AnimationNode> anode = state_machine->get_node(E);
String name = E;
bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr());
- Ref<StyleBox> sb = E == selected_node ? style_selected : style;
+ Ref<StyleBox> sb = selected_nodes.has(E) ? style_selected : style;
Size2 s = sb->get_minimum_size();
int strsize = font->get_string_size(name, font_size).width;
s.width += strsize;
s.height += MAX(font->get_height(font_size), play->get_height());
s.width += sep + play->get_width();
+
if (needs_editor) {
s.width += sep + edit->get_width();
}
Vector2 offset;
offset += state_machine->get_node_position(E) * EDSCALE;
- if (selected_node == E && dragging_selected) {
+
+ if (selected_nodes.has(E) && dragging_selected) {
offset += drag_ofs;
}
+
offset -= s / 2;
offset = offset.floor();
@@ -664,7 +1278,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
}
- _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false);
+ _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false, false);
}
Ref<Texture2D> tr_reference_icon = get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons"));
@@ -673,13 +1287,18 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
//draw transition lines
for (int i = 0; i < state_machine->get_transition_count(); i++) {
TransitionLine tl;
+ tl.transition_index = i;
tl.from_node = state_machine->get_transition_from(i);
- Vector2 ofs_from = (dragging_selected && tl.from_node == selected_node) ? drag_ofs : Vector2();
- tl.from = (state_machine->get_node_position(tl.from_node) * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
+ StringName local_from = String(tl.from_node).get_slicec('/', 0);
+ local_from = local_from == ".." ? state_machine->start_node : local_from;
+ Vector2 ofs_from = (dragging_selected && selected_nodes.has(local_from)) ? drag_ofs : Vector2();
+ tl.from = (state_machine->get_node_position(local_from) * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
tl.to_node = state_machine->get_transition_to(i);
- Vector2 ofs_to = (dragging_selected && tl.to_node == selected_node) ? drag_ofs : Vector2();
- tl.to = (state_machine->get_node_position(tl.to_node) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
+ StringName local_to = String(tl.to_node).get_slicec('/', 0);
+ local_to = local_to == ".." ? state_machine->end_node : local_to;
+ Vector2 ofs_to = (dragging_selected && selected_nodes.has(local_to)) ? drag_ofs : Vector2();
+ tl.to = (state_machine->get_node_position(local_to) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
tl.disabled = tr->is_disabled();
@@ -688,62 +1307,79 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
tl.advance_condition_state = false;
tl.mode = tr->get_switch_mode();
tl.width = tr_bidi_offset;
+ tl.travel = false;
+ tl.hidden = false;
- if (state_machine->has_transition(tl.to_node, tl.from_node)) { //offset if same exists
+ if (state_machine->has_local_transition(local_to, local_from)) { //offset if same exists
Vector2 offset = -(tl.from - tl.to).normalized().orthogonal() * tr_bidi_offset;
tl.from += offset;
tl.to += offset;
}
for (int j = 0; j < node_rects.size(); j++) {
- if (node_rects[j].node_name == tl.from_node) {
+ if (node_rects[j].node_name == local_from) {
_clip_src_line_to_rect(tl.from, tl.to, node_rects[j].node);
}
- if (node_rects[j].node_name == tl.to_node) {
+ if (node_rects[j].node_name == local_to) {
_clip_dst_line_to_rect(tl.from, tl.to, node_rects[j].node);
}
}
- bool selected = selected_transition_from == tl.from_node && selected_transition_to == tl.to_node;
+ tl.selected = selected_transition_from == tl.from_node && selected_transition_to == tl.to_node;
- bool travel = false;
-
- if (blend_from == tl.from_node && current == tl.to_node) {
- travel = true;
+ if (blend_from == local_from && current == local_to) {
+ tl.travel = true;
}
if (travel_path.size()) {
- if (current == tl.from_node && travel_path[0] == tl.to_node) {
- travel = true;
+ if (current == local_from && travel_path[0] == local_to) {
+ tl.travel = true;
} else {
for (int j = 0; j < travel_path.size() - 1; j++) {
- if (travel_path[j] == tl.from_node && travel_path[j + 1] == tl.to_node) {
- travel = true;
+ if (travel_path[j] == local_from && travel_path[j + 1] == local_to) {
+ tl.travel = true;
break;
}
}
}
}
- bool auto_advance = tl.auto_advance;
StringName fullpath = AnimationTreeEditor::get_singleton()->get_base_path() + String(tl.advance_condition_name);
if (tl.advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(fullpath))) {
tl.advance_condition_state = true;
- auto_advance = true;
+ tl.auto_advance = true;
}
- _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, auto_advance);
+ // check if already have this local transition
+ for (int j = 0; j < transition_lines.size(); j++) {
+ StringName from = String(transition_lines[j].from_node).get_slicec('/', 0);
+ StringName to = String(transition_lines[j].to_node).get_slicec('/', 0);
+ from = from == ".." ? state_machine->start_node : from;
+ to = to == ".." ? state_machine->end_node : to;
+
+ if (from == local_from && to == local_to) {
+ tl.hidden = true;
+ transition_lines.write[j].disabled = transition_lines[j].disabled && tl.disabled;
+ transition_lines.write[j].multi_transitions.push_back(tl);
+ }
+ }
transition_lines.push_back(tl);
}
+ for (int i = 0; i < transition_lines.size(); i++) {
+ TransitionLine tl = transition_lines[i];
+ if (!tl.hidden) {
+ _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.auto_advance, !tl.multi_transitions.is_empty());
+ }
+ }
+
//draw actual nodes
for (int i = 0; i < node_rects.size(); i++) {
String name = node_rects[i].node_name;
Ref<AnimationNode> anode = state_machine->get_node(name);
bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
- Ref<StyleBox> sb = name == selected_node ? style_selected : style;
+ Ref<StyleBox> sb = selected_nodes.has(name) ? style_selected : style;
int strsize = font->get_string_size(name, font_size).width;
-
NodeRect &nr = node_rects.write[i];
Vector2 offset = nr.node.position;
@@ -754,18 +1390,16 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
//now scroll it to draw
state_machine_draw->draw_style_box(sb, nr.node);
- if (playing && (blend_from == name || current == name || travel_path.find(name) != -1)) {
- state_machine_draw->draw_style_box(playing_overlay, nr.node);
+ if (state_machine->start_node == name) {
+ state_machine_draw->draw_style_box(sb == style_selected ? style_selected : start_overlay, nr.node);
}
- bool onstart = state_machine->get_start_node() == name;
- if (onstart) {
- state_machine_draw->draw_string(font, offset + Vector2(0, -font->get_height(font_size) - 3 * EDSCALE + font->get_ascent(font_size)), TTR("Start"), HALIGN_LEFT, -1, font_size, font_color);
+ if (state_machine->end_node == name) {
+ state_machine_draw->draw_style_box(sb == style_selected ? style_selected : end_overlay, nr.node);
}
- if (state_machine->get_end_node() == name) {
- int endofs = nr.node.size.x - font->get_string_size(TTR("End"), font_size).x;
- state_machine_draw->draw_string(font, offset + Vector2(endofs, -font->get_height(font_size) - 3 * EDSCALE + font->get_ascent(font_size)), TTR("End"), HALIGN_LEFT, -1, font_size, font_color);
+ if (playing && (blend_from == name || current == name || travel_path.has(name))) {
+ state_machine_draw->draw_style_box(playing_overlay, nr.node);
}
offset.x += sb->get_offset().x;
@@ -773,19 +1407,20 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
nr.play.position = offset + Vector2(0, (h - play->get_height()) / 2).floor();
nr.play.size = play->get_size();
- Ref<Texture2D> play_tex = onstart ? auto_play : play;
+ Ref<Texture2D> play_tex = play;
if (over_node == name && over_node_what == 0) {
state_machine_draw->draw_texture(play_tex, nr.play.position, accent);
} else {
state_machine_draw->draw_texture(play_tex, nr.play.position);
}
+
offset.x += sep + play->get_width();
nr.name.position = offset + Vector2(0, (h - font->get_height(font_size)) / 2).floor();
nr.name.size = Vector2(strsize, font->get_height(font_size));
- state_machine_draw->draw_string(font, nr.name.position + Vector2(0, font->get_ascent(font_size)), name, HALIGN_LEFT, -1, font_size, font_color);
+ state_machine_draw->draw_string(font, nr.name.position + Vector2(0, font->get_ascent(font_size)), name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
offset.x += strsize + sep;
if (needs_editor) {
@@ -801,6 +1436,11 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
}
+ //draw box select
+ if (box_selecting) {
+ state_machine_draw->draw_rect(box_selecting_rect, Color(0.7, 0.7, 1.0, 0.3));
+ }
+
scroll_range.position -= state_machine_draw->get_size();
scroll_range.size += state_machine_draw->get_size() * 2.0;
@@ -827,6 +1467,10 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
return;
}
+ if (playback->get_current_node() == state_machine->start_node || playback->get_current_node() == state_machine->end_node) {
+ return;
+ }
+
int idx = -1;
for (int i = 0; i < node_rects.size(); i++) {
if (node_rects[i].node_name == playback->get_current_node()) {
@@ -881,169 +1525,174 @@ void AnimationNodeStateMachineEditor::_update_graph() {
}
void AnimationNodeStateMachineEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || p_what == NOTIFICATION_TRANSLATION_CHANGED) {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
-
- tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
- tool_create->set_icon(get_theme_icon(SNAME("ToolAddNode"), SNAME("EditorIcons")));
- tool_connect->set_icon(get_theme_icon(SNAME("ToolConnect"), SNAME("EditorIcons")));
-
- transition_mode->clear();
- transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionImmediate"), SNAME("EditorIcons")), TTR("Immediate"));
- transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionSync"), SNAME("EditorIcons")), TTR("Sync"));
- transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionEnd"), SNAME("EditorIcons")), TTR("At End"));
-
- tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- tool_autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
- tool_end->set_icon(get_theme_icon(SNAME("AutoEnd"), SNAME("EditorIcons")));
-
- play_mode->clear();
- play_mode->add_icon_item(get_theme_icon(SNAME("PlayTravel"), SNAME("EditorIcons")), TTR("Travel"));
- play_mode->add_icon_item(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")), TTR("Immediate"));
- }
-
- if (p_what == NOTIFICATION_PROCESS) {
- String error;
-
- Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
-
- if (error_time > 0) {
- error = error_text;
- error_time -= get_process_delta_time();
- } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
- error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
- error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
- /*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
- if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) {
- error = TTR("Start and end nodes are needed for a sub-transition.");
- }*/
- } else if (playback.is_null()) {
- error = vformat(TTR("No playback resource set at path: %s."), AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
- }
-
- if (error != error_label->get_text()) {
- error_label->set_text(error);
- if (error != String()) {
- error_panel->show();
- } else {
- error_panel->hide();
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
+ case NOTIFICATION_TRANSLATION_CHANGED: {
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+
+ tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
+ tool_create->set_icon(get_theme_icon(SNAME("ToolAddNode"), SNAME("EditorIcons")));
+ tool_connect->set_icon(get_theme_icon(SNAME("ToolConnect"), SNAME("EditorIcons")));
+
+ transition_mode->clear();
+ transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionImmediate"), SNAME("EditorIcons")), TTR("Immediate"));
+ transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionSync"), SNAME("EditorIcons")), TTR("Sync"));
+ transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionEnd"), SNAME("EditorIcons")), TTR("At End"));
+
+ tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ tool_group->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
+ tool_ungroup->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
+
+ play_mode->clear();
+ play_mode->add_icon_item(get_theme_icon(SNAME("PlayTravel"), SNAME("EditorIcons")), TTR("Travel"));
+ play_mode->add_icon_item(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")), TTR("Immediate"));
+ } break;
+
+ case NOTIFICATION_PROCESS: {
+ String error;
+
+ Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
+
+ if (error_time > 0) {
+ error = error_text;
+ error_time -= get_process_delta_time();
+ } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
+ error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
+ /*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
+ if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) {
+ error = TTR("Start and end nodes are needed for a sub-transition.");
+ }*/
+ } else if (playback.is_null()) {
+ error = vformat(TTR("No playback resource set at path: %s."), AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
}
- }
- for (int i = 0; i < transition_lines.size(); i++) {
- int tidx = -1;
- for (int j = 0; j < state_machine->get_transition_count(); j++) {
- if (transition_lines[i].from_node == state_machine->get_transition_from(j) && transition_lines[i].to_node == state_machine->get_transition_to(j)) {
- tidx = j;
- break;
+ if (error != error_label->get_text()) {
+ error_label->set_text(error);
+ if (!error.is_empty()) {
+ error_panel->show();
+ } else {
+ error_panel->hide();
}
}
- if (tidx == -1) { //missing transition, should redraw
- state_machine_draw->update();
- break;
- }
+ for (int i = 0; i < transition_lines.size(); i++) {
+ int tidx = -1;
+ for (int j = 0; j < state_machine->get_transition_count(); j++) {
+ if (transition_lines[i].from_node == state_machine->get_transition_from(j) && transition_lines[i].to_node == state_machine->get_transition_to(j)) {
+ tidx = j;
+ break;
+ }
+ }
- if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) {
- state_machine_draw->update();
- break;
- }
+ if (tidx == -1) { //missing transition, should redraw
+ state_machine_draw->update();
+ break;
+ }
- if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) {
- state_machine_draw->update();
- break;
- }
+ if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) {
+ state_machine_draw->update();
+ break;
+ }
- if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) {
- state_machine_draw->update();
- break;
- }
+ if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) {
+ state_machine_draw->update();
+ break;
+ }
- if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) {
- state_machine_draw->update();
- break;
- }
+ if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) {
+ state_machine_draw->update();
+ break;
+ }
- bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name)));
+ if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) {
+ state_machine_draw->update();
+ break;
+ }
- if (transition_lines[i].advance_condition_state != acstate) {
- state_machine_draw->update();
- break;
+ bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name)));
+
+ if (transition_lines[i].advance_condition_state != acstate) {
+ state_machine_draw->update();
+ break;
+ }
}
- }
- bool same_travel_path = true;
- Vector<StringName> tp;
- bool is_playing = false;
- StringName current_node;
- StringName blend_from_node;
- play_pos = 0;
- current_length = 0;
-
- if (playback.is_valid()) {
- tp = playback->get_travel_path();
- is_playing = playback->is_playing();
- current_node = playback->get_current_node();
- blend_from_node = playback->get_blend_from_node();
- play_pos = playback->get_current_play_pos();
- current_length = playback->get_current_length();
- }
+ bool same_travel_path = true;
+ Vector<StringName> tp;
+ bool is_playing = false;
+ StringName current_node;
+ StringName blend_from_node;
+ play_pos = 0;
+ current_length = 0;
+
+ if (playback.is_valid()) {
+ tp = playback->get_travel_path();
+ is_playing = playback->is_playing();
+ current_node = playback->get_current_node();
+ blend_from_node = playback->get_blend_from_node();
+ play_pos = playback->get_current_play_pos();
+ current_length = playback->get_current_length();
+ }
- {
- if (last_travel_path.size() != tp.size()) {
- same_travel_path = false;
- } else {
- for (int i = 0; i < last_travel_path.size(); i++) {
- if (last_travel_path[i] != tp[i]) {
- same_travel_path = false;
- break;
+ {
+ if (last_travel_path.size() != tp.size()) {
+ same_travel_path = false;
+ } else {
+ for (int i = 0; i < last_travel_path.size(); i++) {
+ if (last_travel_path[i] != tp[i]) {
+ same_travel_path = false;
+ break;
+ }
}
}
}
- }
- //update if travel state changed
- if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) {
- state_machine_draw->update();
- last_travel_path = tp;
- last_current_node = current_node;
- last_active = is_playing;
- last_blend_from_node = blend_from_node;
- state_machine_play_pos->update();
- }
+ //update if travel state changed
+ if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) {
+ state_machine_draw->update();
+ last_travel_path = tp;
+ last_current_node = current_node;
+ last_active = is_playing;
+ last_blend_from_node = blend_from_node;
+ state_machine_play_pos->update();
+ }
- {
- if (current_node != StringName() && state_machine->has_node(current_node)) {
- String next = current_node;
- Ref<AnimationNodeStateMachine> anodesm = state_machine->get_node(next);
- Ref<AnimationNodeStateMachinePlayback> current_node_playback;
-
- while (anodesm.is_valid()) {
- current_node_playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback");
- next += "/" + current_node_playback->get_current_node();
- anodesm = anodesm->get_node(current_node_playback->get_current_node());
- }
+ {
+ if (current_node != StringName() && state_machine->has_node(current_node)) {
+ String next = current_node;
+ Ref<AnimationNodeStateMachine> anodesm = state_machine->get_node(next);
+ Ref<AnimationNodeStateMachinePlayback> current_node_playback;
- // when current_node is a state machine, use playback of current_node to set play_pos
- if (current_node_playback.is_valid()) {
- play_pos = current_node_playback->get_current_play_pos();
- current_length = current_node_playback->get_current_length();
+ while (anodesm.is_valid()) {
+ current_node_playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback");
+ next += "/" + current_node_playback->get_current_node();
+ anodesm = anodesm->get_node(current_node_playback->get_current_node());
+ }
+
+ // when current_node is a state machine, use playback of current_node to set play_pos
+ if (current_node_playback.is_valid()) {
+ play_pos = current_node_playback->get_current_play_pos();
+ current_length = current_node_playback->get_current_length();
+ }
}
}
- }
- if (last_play_pos != play_pos) {
- last_play_pos = play_pos;
- state_machine_play_pos->update();
- }
- }
+ if (last_play_pos != play_pos) {
+ last_play_pos = play_pos;
+ state_machine_play_pos->update();
+ }
+ } break;
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- over_node = StringName();
- set_process(is_visible_in_tree());
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ over_node = StringName();
+ set_process(is_visible_in_tree());
+ } break;
}
}
@@ -1058,7 +1707,7 @@ void AnimationNodeStateMachineEditor::_removed_from_graph() {
void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
const String &new_name = p_text;
- ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1);
+ ERR_FAIL_COND(new_name.is_empty() || new_name.contains(".") || new_name.contains("/"));
if (new_name == prev_name) {
return; // Nothing to do.
@@ -1102,94 +1751,121 @@ void AnimationNodeStateMachineEditor::_scroll_changed(double) {
state_machine_draw->update();
}
-void AnimationNodeStateMachineEditor::_erase_selected() {
- if (selected_node != StringName() && state_machine->has_node(selected_node)) {
- updating = true;
+void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action) {
+ if (!selected_nodes.is_empty()) {
+ if (!p_nested_action) {
+ updating = true;
+ }
undo_redo->create_action(TTR("Node Removed"));
- undo_redo->add_do_method(state_machine.ptr(), "remove_node", selected_node);
- undo_redo->add_undo_method(state_machine.ptr(), "add_node", selected_node, state_machine->get_node(selected_node), state_machine->get_node_position(selected_node));
- for (int i = 0; i < state_machine->get_transition_count(); i++) {
- String from = state_machine->get_transition_from(i);
- String to = state_machine->get_transition_to(i);
- if (from == selected_node || to == selected_node) {
- undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, state_machine->get_transition(i));
+
+ for (int i = 0; i < node_rects.size(); i++) {
+ if (node_rects[i].node_name == state_machine->start_node || node_rects[i].node_name == state_machine->end_node) {
+ continue;
+ }
+
+ if (!selected_nodes.has(node_rects[i].node_name)) {
+ continue;
+ }
+
+ undo_redo->add_do_method(state_machine.ptr(), "remove_node", node_rects[i].node_name);
+ undo_redo->add_undo_method(state_machine.ptr(), "add_node", node_rects[i].node_name,
+ state_machine->get_node(node_rects[i].node_name),
+ state_machine->get_node_position(node_rects[i].node_name));
+
+ for (int j = 0; j < state_machine->get_transition_count(); j++) {
+ String from = state_machine->get_transition_from(j);
+ String to = state_machine->get_transition_to(j);
+ String local_from = from.get_slicec('/', 0);
+ String local_to = to.get_slicec('/', 0);
+
+ if (local_from == node_rects[i].node_name || local_to == node_rects[i].node_name) {
+ undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, state_machine->get_transition(j));
+ }
}
}
- if (String(state_machine->get_start_node()) == selected_node) {
- undo_redo->add_undo_method(state_machine.ptr(), "set_start_node", selected_node);
- }
+
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
- updating = false;
- selected_node = StringName();
+
+ if (!p_nested_action) {
+ updating = false;
+ }
+
+ selected_nodes.clear();
+ }
+
+ if (!selected_multi_transition.multi_transitions.is_empty()) {
+ delete_tree->clear();
+
+ TreeItem *root = delete_tree->create_item();
+
+ TreeItem *item = delete_tree->create_item(root);
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_text(0, String(selected_transition_from) + " -> " + selected_transition_to);
+ item->set_editable(0, true);
+
+ for (int i = 0; i < selected_multi_transition.multi_transitions.size(); i++) {
+ String from = selected_multi_transition.multi_transitions[i].from_node;
+ String to = selected_multi_transition.multi_transitions[i].to_node;
+
+ item = delete_tree->create_item(root);
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_text(0, from + " -> " + to);
+ item->set_editable(0, true);
+ }
+
+ delete_window->popup_centered(Vector2(400, 200));
+ return;
}
if (selected_transition_to != StringName() && selected_transition_from != StringName() && state_machine->has_transition(selected_transition_from, selected_transition_to)) {
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(state_machine->find_transition(selected_transition_from, selected_transition_to));
- updating = true;
+ if (!p_nested_action) {
+ updating = true;
+ }
undo_redo->create_action(TTR("Transition Removed"));
undo_redo->add_do_method(state_machine.ptr(), "remove_transition", selected_transition_from, selected_transition_to);
undo_redo->add_undo_method(state_machine.ptr(), "add_transition", selected_transition_from, selected_transition_to, tr);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
- updating = false;
+ if (!p_nested_action) {
+ updating = false;
+ }
selected_transition_from = StringName();
selected_transition_to = StringName();
+ selected_transition_index = -1;
+ selected_multi_transition = TransitionLine();
}
state_machine_draw->update();
}
-void AnimationNodeStateMachineEditor::_autoplay_selected() {
- if (selected_node != StringName() && state_machine->has_node(selected_node)) {
- StringName new_start_node;
- if (state_machine->get_start_node() == selected_node) { //toggle it
- new_start_node = StringName();
- } else {
- new_start_node = selected_node;
- }
-
- updating = true;
- undo_redo->create_action(TTR("Set Start Node (Autoplay)"));
- undo_redo->add_do_method(state_machine.ptr(), "set_start_node", new_start_node);
- undo_redo->add_undo_method(state_machine.ptr(), "set_start_node", state_machine->get_start_node());
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- updating = false;
- state_machine_draw->update();
- }
-}
-
-void AnimationNodeStateMachineEditor::_end_selected() {
- if (selected_node != StringName() && state_machine->has_node(selected_node)) {
- StringName new_end_node;
- if (state_machine->get_end_node() == selected_node) { //toggle it
- new_end_node = StringName();
- } else {
- new_end_node = selected_node;
- }
-
- updating = true;
- undo_redo->create_action(TTR("Set Start Node (Autoplay)"));
- undo_redo->add_do_method(state_machine.ptr(), "set_end_node", new_end_node);
- undo_redo->add_undo_method(state_machine.ptr(), "set_end_node", state_machine->get_end_node());
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- updating = false;
- state_machine_draw->update();
- }
-}
-
void AnimationNodeStateMachineEditor::_update_mode() {
if (tool_select->is_pressed()) {
tool_erase_hb->show();
- tool_erase->set_disabled(selected_node == StringName() && selected_transition_from == StringName() && selected_transition_to == StringName());
- tool_autoplay->set_disabled(selected_node == StringName());
- tool_end->set_disabled(selected_node == StringName());
+ bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName();
+ bool start_end_selected = selected_nodes.size() == 1 && (selected_nodes.front()->get() == state_machine->start_node || selected_nodes.front()->get() == state_machine->end_node);
+ tool_erase->set_disabled(nothing_selected || start_end_selected);
+
+ if (selected_nodes.is_empty() || start_end_selected) {
+ tool_group->set_disabled(true);
+ tool_group->set_visible(true);
+ tool_ungroup->set_visible(false);
+ } else {
+ Ref<AnimationNodeStateMachine> ansm = state_machine->get_node(selected_nodes.front()->get());
+
+ if (selected_nodes.size() == 1 && ansm.is_valid()) {
+ tool_group->set_disabled(true);
+ tool_group->set_visible(false);
+ tool_ungroup->set_visible(true);
+ } else {
+ tool_group->set_disabled(false);
+ tool_group->set_visible(true);
+ tool_ungroup->set_visible(false);
+ }
+ }
} else {
tool_erase_hb->hide();
}
@@ -1197,17 +1873,19 @@ void AnimationNodeStateMachineEditor::_update_mode() {
void AnimationNodeStateMachineEditor::_bind_methods() {
ClassDB::bind_method("_update_graph", &AnimationNodeStateMachineEditor::_update_graph);
-
ClassDB::bind_method("_removed_from_graph", &AnimationNodeStateMachineEditor::_removed_from_graph);
-
ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor);
+ ClassDB::bind_method("_connect_to", &AnimationNodeStateMachineEditor::_connect_to);
+ ClassDB::bind_method("_stop_connecting", &AnimationNodeStateMachineEditor::_stop_connecting);
+ ClassDB::bind_method("_delete_selected", &AnimationNodeStateMachineEditor::_delete_selected);
+ ClassDB::bind_method("_delete_all", &AnimationNodeStateMachineEditor::_delete_all);
+ ClassDB::bind_method("_delete_tree_draw", &AnimationNodeStateMachineEditor::_delete_tree_draw);
}
AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = nullptr;
AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
singleton = this;
- updating = false;
HBoxContainer *top_hb = memnew(HBoxContainer);
add_child(top_hb);
@@ -1221,7 +1899,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
tool_select->set_pressed(true);
- tool_select->set_tooltip(TTR("Select and move nodes.\nRMB to add new nodes.\nShift+LMB to create connections."));
+ tool_select->set_tooltip(TTR("Select and move nodes.\nRMB: Add node at position clicked.\nShift+LMB+Drag: Connects the selected node with another node or creates a new node if you select an area without nodes."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), varray(), CONNECT_DEFERRED);
tool_create = memnew(Button);
@@ -1243,28 +1921,27 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_erase_hb = memnew(HBoxContainer);
top_hb->add_child(tool_erase_hb);
tool_erase_hb->add_child(memnew(VSeparator));
+
+ tool_group = memnew(Button);
+ tool_group->set_flat(true);
+ tool_group->set_tooltip(TTR("Group Selected Node(s)") + " (Ctrl+G)");
+ tool_group->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_group_selected_nodes));
+ tool_group->set_disabled(true);
+ tool_erase_hb->add_child(tool_group);
+
+ tool_ungroup = memnew(Button);
+ tool_ungroup->set_flat(true);
+ tool_ungroup->set_tooltip(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)");
+ tool_ungroup->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_ungroup_selected_nodes));
+ tool_ungroup->set_visible(false);
+ tool_erase_hb->add_child(tool_ungroup);
+
tool_erase = memnew(Button);
tool_erase->set_flat(true);
tool_erase->set_tooltip(TTR("Remove selected node or transition."));
- tool_erase_hb->add_child(tool_erase);
- tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected));
+ tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected), varray(false));
tool_erase->set_disabled(true);
-
- tool_erase_hb->add_child(memnew(VSeparator));
-
- tool_autoplay = memnew(Button);
- tool_autoplay->set_flat(true);
- tool_autoplay->set_tooltip(TTR("Toggle autoplay this animation on start, restart or seek to zero."));
- tool_erase_hb->add_child(tool_autoplay);
- tool_autoplay->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_autoplay_selected));
- tool_autoplay->set_disabled(true);
-
- tool_end = memnew(Button);
- tool_end->set_flat(true);
- tool_end->set_tooltip(TTR("Set the end animation. This is useful for sub-transitions."));
- tool_erase_hb->add_child(tool_end);
- tool_end->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_end_selected));
- tool_end->set_disabled(true);
+ tool_erase_hb->add_child(tool_erase);
top_hb->add_child(memnew(VSeparator));
top_hb->add_child(memnew(Label(TTR("Transition: "))));
@@ -1279,6 +1956,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
panel = memnew(PanelContainer);
panel->set_clip_contents(true);
+ panel->set_mouse_filter(Control::MOUSE_FILTER_PASS);
add_child(panel);
panel->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -1287,6 +1965,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
state_machine_draw->connect("gui_input", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_gui_input));
state_machine_draw->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_draw));
state_machine_draw->set_focus_mode(FOCUS_ALL);
+ state_machine_draw->set_mouse_filter(Control::MOUSE_FILTER_PASS);
state_machine_play_pos = memnew(Control);
state_machine_draw->add_child(state_machine_play_pos);
@@ -1318,12 +1997,28 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_menu_type));
+ menu->connect("popup_hide", callable_mp(this, &AnimationNodeStateMachineEditor::_stop_connecting));
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("animations");
animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_animation_type));
+ connect_menu = memnew(PopupMenu);
+ add_child(connect_menu);
+ connect_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to));
+ connect_menu->connect("popup_hide", callable_mp(this, &AnimationNodeStateMachineEditor::_stop_connecting));
+
+ state_machine_menu = memnew(PopupMenu);
+ state_machine_menu->set_name("state_machines");
+ state_machine_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to));
+ connect_menu->add_child(state_machine_menu);
+
+ end_menu = memnew(PopupMenu);
+ end_menu->set_name("end_nodes");
+ end_menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_connect_to));
+ connect_menu->add_child(end_menu);
+
name_edit_popup = memnew(Popup);
add_child(name_edit_popup);
name_edit = memnew(LineEdit);
@@ -1339,13 +2034,94 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
open_file->connect("file_selected", callable_mp(this, &AnimationNodeStateMachineEditor::_file_opened));
undo_redo = EditorNode::get_undo_redo();
- over_text = false;
+ delete_window = memnew(ConfirmationDialog);
+ delete_window->set_flag(Window::FLAG_RESIZE_DISABLED, true);
+ add_child(delete_window);
+
+ delete_tree = memnew(Tree);
+ delete_tree->set_hide_root(true);
+ delete_tree->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_delete_tree_draw));
+ delete_window->add_child(delete_tree);
+
+ Button *ok = delete_window->get_cancel_button();
+ ok->set_text(TTR("Delete Selected"));
+ ok->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_delete_selected));
+
+ Button *delete_all = delete_window->add_button(TTR("Delete All"), true);
+ delete_all->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_delete_all));
over_node_what = -1;
dragging_selected_attempt = false;
connecting = false;
+ selected_transition_index = -1;
last_active = false;
error_time = 0;
}
+
+void EditorAnimationMultiTransitionEdit::add_transition(const StringName &p_from, const StringName &p_to, Ref<AnimationNodeStateMachineTransition> p_transition) {
+ Transition tr;
+ tr.from = p_from;
+ tr.to = p_to;
+ tr.transition = p_transition;
+ transitions.push_back(tr);
+}
+
+bool EditorAnimationMultiTransitionEdit::_set(const StringName &p_name, const Variant &p_property) {
+ int index = String(p_name).get_slicec('/', 0).to_int();
+ StringName prop = String(p_name).get_slicec('/', 1);
+
+ bool found;
+ transitions.write[index].transition->set(prop, p_property, &found);
+ if (found) {
+ return true;
+ }
+
+ return false;
+}
+
+bool EditorAnimationMultiTransitionEdit::_get(const StringName &p_name, Variant &r_property) const {
+ int index = String(p_name).get_slicec('/', 0).to_int();
+ StringName prop = String(p_name).get_slicec('/', 1);
+
+ if (prop == "transition_path") {
+ r_property = String(transitions[index].from) + " -> " + transitions[index].to;
+ return true;
+ }
+
+ bool found;
+ r_property = transitions[index].transition->get(prop, &found);
+ if (found) {
+ return true;
+ }
+
+ return false;
+}
+
+void EditorAnimationMultiTransitionEdit::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < transitions.size(); i++) {
+ List<PropertyInfo> plist;
+ transitions[i].transition->get_property_list(&plist, true);
+
+ PropertyInfo prop_transition_path;
+ prop_transition_path.type = Variant::STRING;
+ prop_transition_path.name = itos(i) + "/" + "transition_path";
+ p_list->push_back(prop_transition_path);
+
+ for (List<PropertyInfo>::Element *F = plist.front(); F; F = F->next()) {
+ if (F->get().name == "script" || F->get().name == "resource_name" || F->get().name == "resource_path" || F->get().name == "resource_local_to_scene") {
+ continue;
+ }
+
+ if (F->get().usage != PROPERTY_USAGE_DEFAULT) {
+ continue;
+ }
+
+ PropertyInfo prop = F->get();
+ prop.name = itos(i) + "/" + prop.name;
+
+ p_list->push_back(prop);
+ }
+ }
+}
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index a969ddd26b..1247d99389 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef ANIMATION_STATE_MACHINE_EDITOR_H
#define ANIMATION_STATE_MACHINE_EDITOR_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
@@ -41,71 +40,88 @@
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+class EditorFileDialog;
+
class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeStateMachine> state_machine;
- Button *tool_select;
- Button *tool_create;
- Button *tool_connect;
- Popup *name_edit_popup;
- LineEdit *name_edit;
+ Button *tool_select = nullptr;
+ Button *tool_create = nullptr;
+ Button *tool_connect = nullptr;
+ Button *tool_group = nullptr;
+ Button *tool_ungroup = nullptr;
+ Popup *name_edit_popup = nullptr;
+ LineEdit *name_edit = nullptr;
- HBoxContainer *tool_erase_hb;
- Button *tool_erase;
- Button *tool_autoplay;
- Button *tool_end;
+ HBoxContainer *tool_erase_hb = nullptr;
+ Button *tool_erase = nullptr;
- OptionButton *transition_mode;
- OptionButton *play_mode;
+ OptionButton *transition_mode = nullptr;
+ OptionButton *play_mode = nullptr;
- PanelContainer *panel;
+ PanelContainer *panel = nullptr;
StringName selected_node;
+ Set<StringName> selected_nodes;
- HScrollBar *h_scroll;
- VScrollBar *v_scroll;
+ HScrollBar *h_scroll = nullptr;
+ VScrollBar *v_scroll = nullptr;
- Control *state_machine_draw;
- Control *state_machine_play_pos;
+ Control *state_machine_draw = nullptr;
+ Control *state_machine_play_pos = nullptr;
- PanelContainer *error_panel;
- Label *error_label;
+ PanelContainer *error_panel = nullptr;
+ Label *error_label = nullptr;
- bool updating;
+ bool updating = false;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
static AnimationNodeStateMachineEditor *singleton;
void _state_machine_gui_input(const Ref<InputEvent> &p_event);
- void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance);
+ void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance, bool p_multi_transitions);
void _state_machine_draw();
void _state_machine_pos_draw();
void _update_graph();
- PopupMenu *menu;
- PopupMenu *animations_menu;
+ PopupMenu *menu = nullptr;
+ PopupMenu *connect_menu = nullptr;
+ PopupMenu *state_machine_menu = nullptr;
+ PopupMenu *end_menu = nullptr;
+ PopupMenu *animations_menu = nullptr;
Vector<String> animations_to_add;
+ Vector<String> nodes_to_connect;
Vector2 add_node_pos;
- bool dragging_selected_attempt;
- bool dragging_selected;
+ ConfirmationDialog *delete_window;
+ Tree *delete_tree;
+
+ bool box_selecting = false;
+ Point2 box_selecting_from;
+ Point2 box_selecting_to;
+ Rect2 box_selecting_rect;
+ Set<StringName> previous_selected;
+
+ bool dragging_selected_attempt = false;
+ bool dragging_selected = false;
Vector2 drag_from;
Vector2 drag_ofs;
StringName snap_x;
StringName snap_y;
- bool connecting;
+ bool connecting = false;
StringName connecting_from;
Vector2 connecting_to;
StringName connecting_to_node;
void _add_menu_type(int p_index);
void _add_animation_type(int p_index);
+ void _connect_to(int p_index);
void _removed_from_graph();
@@ -130,16 +146,37 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
bool disabled = false;
bool auto_advance = false;
float width = 0;
+ bool selected;
+ bool travel;
+ bool hidden;
+ int transition_index;
+ Vector<TransitionLine> multi_transitions;
};
Vector<TransitionLine> transition_lines;
+ struct NodeUR {
+ StringName name;
+ Ref<AnimationNode> node;
+ Vector2 position;
+ };
+
+ struct TransitionUR {
+ StringName new_from;
+ StringName new_to;
+ StringName old_from;
+ StringName old_to;
+ Ref<AnimationNodeStateMachineTransition> transition;
+ };
+
StringName selected_transition_from;
StringName selected_transition_to;
+ int selected_transition_index;
+ TransitionLine selected_multi_transition;
+ void _add_transition(const bool p_nested_action = false);
- bool over_text;
StringName over_node;
- int over_node_what;
+ int over_node_what = -1;
String prev_name;
void _name_edited(const String &p_text);
@@ -147,26 +184,35 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
void _open_editor(const String &p_name);
void _scroll_changed(double);
- void _clip_src_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect);
- void _clip_dst_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect);
+ void _clip_src_line_to_rect(Vector2 &r_from, const Vector2 &p_to, const Rect2 &p_rect);
+ void _clip_dst_line_to_rect(const Vector2 &p_from, Vector2 &r_to, const Rect2 &p_rect);
- void _erase_selected();
+ void _erase_selected(const bool p_nested_action = false);
void _update_mode();
- void _autoplay_selected();
- void _end_selected();
+ void _open_menu(const Vector2 &p_position);
+ void _open_connect_menu(const Vector2 &p_position);
+ bool _create_submenu(PopupMenu *p_menu, Ref<AnimationNodeStateMachine> p_nodesm, const StringName &p_name, const StringName &p_path, bool from_root = false, Vector<Ref<AnimationNodeStateMachine>> p_parents = Vector<Ref<AnimationNodeStateMachine>>());
+ void _stop_connecting();
+
+ void _group_selected_nodes();
+ void _ungroup_selected_nodes();
- bool last_active;
+ void _delete_selected();
+ void _delete_all();
+ void _delete_tree_draw();
+
+ bool last_active = false;
StringName last_blend_from_node;
StringName last_current_node;
Vector<StringName> last_travel_path;
- float last_play_pos;
- float play_pos;
- float current_length;
+ float last_play_pos = 0.0f;
+ float play_pos = 0.0f;
+ float current_length = 0.0f;
- float error_time;
+ float error_time = 0.0f;
String error_text;
- EditorFileDialog *open_file;
+ EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
@@ -184,7 +230,30 @@ public:
static AnimationNodeStateMachineEditor *get_singleton() { return singleton; }
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
AnimationNodeStateMachineEditor();
};
+class EditorAnimationMultiTransitionEdit : public RefCounted {
+ GDCLASS(EditorAnimationMultiTransitionEdit, RefCounted);
+
+ struct Transition {
+ StringName from;
+ StringName to;
+ Ref<AnimationNodeStateMachineTransition> transition;
+ };
+
+ Vector<Transition> transitions;
+
+protected:
+ bool _set(const StringName &p_name, const Variant &p_property);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
+public:
+ void add_transition(const StringName &p_from, const StringName &p_to, Ref<AnimationNodeStateMachineTransition> p_transition);
+
+ EditorAnimationMultiTransitionEdit(){};
+};
+
#endif // ANIMATION_STATE_MACHINE_EDITOR_H
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index 6c5606fbfd..7ea6906d72 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -39,6 +39,8 @@
#include "core/io/resource_loader.h"
#include "core/math/delaunay_2d.h"
#include "core/os/keyboard.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
@@ -143,19 +145,21 @@ void AnimationTreeEditor::enter_editor(const String &p_path) {
}
void AnimationTreeEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_PROCESS) {
- ObjectID root;
- if (tree && tree->get_tree_root().is_valid()) {
- root = tree->get_tree_root()->get_instance_id();
- }
+ switch (p_what) {
+ case NOTIFICATION_PROCESS: {
+ ObjectID root;
+ if (tree && tree->get_tree_root().is_valid()) {
+ root = tree->get_tree_root()->get_instance_id();
+ }
- if (root != current_root) {
- edit_path(Vector<String>());
- }
+ if (root != current_root) {
+ edit_path(Vector<String>());
+ }
- if (button_path.size() != edited_path.size()) {
- edit_path(edited_path);
- }
+ if (button_path.size() != edited_path.size()) {
+ edit_path(edited_path);
+ }
+ } break;
}
}
@@ -226,8 +230,7 @@ AnimationTreeEditor::AnimationTreeEditor() {
AnimationNodeAnimation::get_editable_animation_list = get_animation_list;
path_edit = memnew(ScrollContainer);
add_child(path_edit);
- path_edit->set_enable_h_scroll(true);
- path_edit->set_enable_v_scroll(false);
+ path_edit->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
path_hb = memnew(HBoxContainer);
path_edit->add_child(path_hb);
path_hb->add_child(memnew(Label(TTR("Path:"))));
@@ -258,23 +261,22 @@ void AnimationTreeEditorPlugin::make_visible(bool p_visible) {
//editor->hide_animation_player_editors();
//editor->animation_panel_make_visible(true);
button->show();
- editor->make_bottom_panel_item_visible(anim_tree_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(anim_tree_editor);
anim_tree_editor->set_process(true);
} else {
if (anim_tree_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
button->hide();
anim_tree_editor->set_process(false);
}
}
-AnimationTreeEditorPlugin::AnimationTreeEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+AnimationTreeEditorPlugin::AnimationTreeEditorPlugin() {
anim_tree_editor = memnew(AnimationTreeEditor);
anim_tree_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
- button = editor->add_bottom_panel_item(TTR("AnimationTree"), anim_tree_editor);
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("AnimationTree"), anim_tree_editor);
button->hide();
}
diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h
index de3d89ae17..ab4ef5a001 100644
--- a/editor/plugins/animation_tree_editor_plugin.h
+++ b/editor/plugins/animation_tree_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef ANIMATION_TREE_EDITOR_PLUGIN_H
#define ANIMATION_TREE_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/animation/animation_tree.h"
@@ -40,6 +39,8 @@
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+class EditorFileDialog;
+
class AnimationTreeNodeEditorPlugin : public VBoxContainer {
GDCLASS(AnimationTreeNodeEditorPlugin, VBoxContainer);
@@ -51,11 +52,11 @@ public:
class AnimationTreeEditor : public VBoxContainer {
GDCLASS(AnimationTreeEditor, VBoxContainer);
- ScrollContainer *path_edit;
- HBoxContainer *path_hb;
+ ScrollContainer *path_edit = nullptr;
+ HBoxContainer *path_hb = nullptr;
- AnimationTree *tree;
- MarginContainer *editor_base;
+ AnimationTree *tree = nullptr;
+ MarginContainer *editor_base = nullptr;
Vector<String> button_path;
Vector<String> edited_path;
@@ -95,9 +96,8 @@ public:
class AnimationTreeEditorPlugin : public EditorPlugin {
GDCLASS(AnimationTreeEditorPlugin, EditorPlugin);
- AnimationTreeEditor *anim_tree_editor;
- EditorNode *editor;
- Button *button;
+ AnimationTreeEditor *anim_tree_editor = nullptr;
+ Button *button = nullptr;
public:
virtual String get_name() const override { return "AnimationTree"; }
@@ -106,7 +106,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- AnimationTreeEditorPlugin(EditorNode *p_node);
+ AnimationTreeEditorPlugin();
~AnimationTreeEditorPlugin();
};
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index aacfc3e305..ab7afc5349 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -34,11 +34,22 @@
#include "core/io/json.h"
#include "core/os/keyboard.h"
#include "core/version.h"
+#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/project_settings_editor.h"
+static inline void setup_http_request(HTTPRequest *request) {
+ request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
+
+ const String proxy_host = EDITOR_GET("network/http_proxy/host");
+ const int proxy_port = EDITOR_GET("network/http_proxy/port");
+ request->set_http_proxy(proxy_host, proxy_port);
+ request->set_https_proxy(proxy_host, proxy_port);
+}
+
void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, const String &p_category, int p_category_id, const String &p_author, int p_author_id, const String &p_cost) {
title->set_text(p_title);
asset_id = p_asset_id;
@@ -57,11 +68,13 @@ void EditorAssetLibraryItem::set_image(int p_type, int p_index, const Ref<Textur
}
void EditorAssetLibraryItem::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- icon->set_normal_texture(get_theme_icon(SNAME("ProjectIconLoading"), SNAME("EditorIcons")));
- category->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
- author->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
- price->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ icon->set_normal_texture(get_theme_icon(SNAME("ProjectIconLoading"), SNAME("EditorIcons")));
+ category->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
+ author->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
+ price->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
+ } break;
}
}
@@ -184,7 +197,8 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
void EditorAssetLibraryItemDescription::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
previews_bg->add_theme_style_override("panel", previews->get_theme_stylebox(SNAME("normal"), SNAME("TextEdit")));
} break;
}
@@ -231,6 +245,7 @@ void EditorAssetLibraryItemDescription::configure(const String &p_title, int p_a
description->pop();
description->add_text("\n" + TTR("Description:") + "\n\n");
description->append_text(p_description);
+ description->set_selection_enabled(true);
set_title(p_title);
}
@@ -278,7 +293,7 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() {
preview = memnew(TextureRect);
previews_vbox->add_child(preview);
- preview->set_expand(true);
+ preview->set_ignore_texture_size(true);
preview->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
preview->set_custom_minimum_size(Size2(640 * EDSCALE, 345 * EDSCALE));
@@ -288,8 +303,7 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() {
previews = memnew(ScrollContainer);
previews_bg->add_child(previews);
- previews->set_enable_v_scroll(false);
- previews->set_enable_h_scroll(true);
+ previews->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
preview_hb = memnew(HBoxContainer);
preview_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -344,7 +358,7 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
if (p_code != 200) {
error_text = TTR("Request failed, return code:") + " " + itos(p_code);
status->set_text(TTR("Failed:") + " " + itos(p_code));
- } else if (sha256 != "") {
+ } else if (!sha256.is_empty()) {
String download_sha256 = FileAccess::get_sha256(download->get_download_file());
if (sha256 != download_sha256) {
error_text = TTR("Bad download hash, assuming file has been tampered with.") + "\n";
@@ -355,23 +369,23 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
} break;
}
- if (error_text != String()) {
+ if (!error_text.is_empty()) {
download_error->set_text(TTR("Asset Download Error:") + "\n" + error_text);
download_error->popup_centered();
// Let the user retry the download.
- retry->show();
+ retry_button->show();
return;
}
- install->set_disabled(false);
- status->set_text(TTR("Success!"));
+ install_button->set_disabled(false);
+ status->set_text(TTR("Ready to install!"));
// Make the progress bar invisible but don't reflow other Controls around it.
progress->set_modulate(Color(0, 0, 0, 0));
set_process(false);
// Automatically prompt for installation once the download is completed.
- _install();
+ install();
}
void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asset_id, const Ref<Texture2D> &p_preview, const String &p_download_url, const String &p_sha256_hash) {
@@ -388,11 +402,13 @@ void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asse
void EditorAssetLibraryItemDownload::_notification(int p_what) {
switch (p_what) {
- // FIXME: The editor crashes if 'NOTICATION_THEME_CHANGED' is used.
- case NOTIFICATION_ENTER_TREE: {
- add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
- dismiss->set_normal_texture(get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("AssetLib")));
+ status->add_theme_color_override("font_color", get_theme_color(SNAME("status_color"), SNAME("AssetLib")));
+ dismiss_button->set_normal_texture(get_theme_icon(SNAME("dismiss"), SNAME("AssetLib")));
} break;
+
case NOTIFICATION_PROCESS: {
// Make the progress bar visible again when retrying the download.
progress->set_modulate(Color(1, 1, 1, 1));
@@ -451,7 +467,11 @@ void EditorAssetLibraryItemDownload::_close() {
queue_delete();
}
-void EditorAssetLibraryItemDownload::_install() {
+bool EditorAssetLibraryItemDownload::can_install() const {
+ return !install_button->is_disabled();
+}
+
+void EditorAssetLibraryItemDownload::install() {
String file = download->get_download_file();
if (external_install) {
@@ -465,7 +485,7 @@ void EditorAssetLibraryItemDownload::_install() {
void EditorAssetLibraryItemDownload::_make_request() {
// Hide the Retry button if we've just pressed it.
- retry->hide();
+ retry_button->hide();
download->cancel_request();
download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
@@ -483,9 +503,14 @@ void EditorAssetLibraryItemDownload::_bind_methods() {
}
EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
+ panel = memnew(PanelContainer);
+ add_child(panel);
+
HBoxContainer *hb = memnew(HBoxContainer);
- add_child(hb);
+ panel->add_child(hb);
icon = memnew(TextureRect);
+ icon->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+ icon->set_v_size_flags(0);
hb->add_child(icon);
VBoxContainer *vb = memnew(VBoxContainer);
@@ -498,9 +523,9 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
title_hb->add_child(title);
title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- dismiss = memnew(TextureButton);
- dismiss->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_close));
- title_hb->add_child(dismiss);
+ dismiss_button = memnew(TextureButton);
+ dismiss_button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_close));
+ title_hb->add_child(dismiss_button);
title->set_clip_text(true);
@@ -508,7 +533,6 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
status = memnew(Label(TTR("Idle")));
vb->add_child(status);
- status->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5));
progress = memnew(ProgressBar);
vb->add_child(progress);
@@ -516,32 +540,32 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
vb->add_child(hb2);
hb2->add_spacer();
- install = memnew(Button);
- install->set_text(TTR("Install..."));
- install->set_disabled(true);
- install->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_install));
+ install_button = memnew(Button);
+ install_button->set_text(TTR("Install..."));
+ install_button->set_disabled(true);
+ install_button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::install));
- retry = memnew(Button);
- retry->set_text(TTR("Retry"));
- retry->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_make_request));
+ retry_button = memnew(Button);
+ retry_button->set_text(TTR("Retry"));
+ retry_button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_make_request));
// Only show the Retry button in case of a failure.
- retry->hide();
+ retry_button->hide();
- hb2->add_child(retry);
- hb2->add_child(install);
+ hb2->add_child(retry_button);
+ hb2->add_child(install_button);
set_custom_minimum_size(Size2(310, 0) * EDSCALE);
download = memnew(HTTPRequest);
- add_child(download);
+ panel->add_child(download);
download->connect("request_completed", callable_mp(this, &EditorAssetLibraryItemDownload::_http_download_completed));
- download->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
+ setup_http_request(download);
download_error = memnew(AcceptDialog);
- add_child(download_error);
+ panel->add_child(download_error);
download_error->set_title(TTR("Download Error"));
asset_installer = memnew(EditorAssetInstaller);
- add_child(asset_installer);
+ panel->add_child(asset_installer);
asset_installer->connect("confirmed", callable_mp(this, &EditorAssetLibraryItemDownload::_close));
prev_status = -1;
@@ -553,12 +577,19 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
void EditorAssetLibrary::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
+ add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("AssetLib")));
+ error_label->raise();
+ } break;
+
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
error_tr->set_texture(get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- filter->set_clear_button_enabled(true);
-
- error_label->raise();
+ library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ downloads_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_label->add_theme_color_override("color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
} break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
// Focus the search box automatically when switching to the Templates tab (in the Project Manager)
@@ -571,6 +602,7 @@ void EditorAssetLibrary::_notification(int p_what) {
}
}
} break;
+
case NOTIFICATION_PROCESS: {
HTTPClient::Status s = request->get_http_client_status();
const bool loading = s != HTTPClient::STATUS_DISCONNECTED;
@@ -587,16 +619,10 @@ void EditorAssetLibrary::_notification(int p_what) {
}
} break;
- case NOTIFICATION_THEME_CHANGED: {
- library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- downloads_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- error_tr->set_texture(get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
- filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- filter->set_clear_button_enabled(true);
- } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
_update_repository_options();
+ setup_http_request(request);
} break;
}
}
@@ -614,13 +640,13 @@ void EditorAssetLibrary::_update_repository_options() {
}
}
-void EditorAssetLibrary::unhandled_key_input(const Ref<InputEvent> &p_event) {
+void EditorAssetLibrary::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
const Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed()) {
- if (key->get_keycode_with_modifiers() == (KEY_MASK_CMD | KEY_F) && is_visible_in_tree()) {
+ if (key->get_keycode_with_modifiers() == (KeyModifierMask::CMD | Key::F) && is_visible_in_tree()) {
filter->grab_focus();
filter->select_all();
accept_event();
@@ -631,14 +657,10 @@ void EditorAssetLibrary::unhandled_key_input(const Ref<InputEvent> &p_event) {
void EditorAssetLibrary::_install_asset() {
ERR_FAIL_COND(!description);
- for (int i = 0; i < downloads_hb->get_child_count(); i++) {
- EditorAssetLibraryItemDownload *d = Object::cast_to<EditorAssetLibraryItemDownload>(downloads_hb->get_child(i));
- if (d && d->get_asset_id() == description->get_asset_id()) {
- if (EditorNode::get_singleton() != nullptr) {
- EditorNode::get_singleton()->show_warning(TTR("Download for this asset is already in progress!"));
- }
- return;
- }
+ EditorAssetLibraryItemDownload *d = _get_asset_in_progress(description->get_asset_id());
+ if (d) {
+ d->install();
+ return;
}
EditorAssetLibraryItemDownload *download = memnew(EditorAssetLibraryItemDownload);
@@ -707,9 +729,8 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
if (use_cache) {
String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
- FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
-
- if (file) {
+ Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
+ if (file.is_valid()) {
PackedByteArray cached_data;
int len = file->get_32();
cached_data.resize(len);
@@ -718,8 +739,6 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
file->get_buffer(w, len);
image_data = cached_data;
- file->close();
- memdelete(file);
}
}
@@ -786,23 +805,17 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
if (headers[i].findn("ETag:") == 0) { // Save etag
String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
- FileAccess *file;
-
- file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE);
- if (file) {
+ Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE);
+ if (file.is_valid()) {
file->store_line(new_etag);
- file->close();
- memdelete(file);
}
int len = p_data.size();
const uint8_t *r = p_data.ptr();
file = FileAccess::open(cache_filename_base + ".data", FileAccess::WRITE);
- if (file) {
+ if (file.is_valid()) {
file->store_32(len);
file->store_buffer(r, len);
- file->close();
- memdelete(file);
}
break;
@@ -836,11 +849,9 @@ void EditorAssetLibrary::_update_image_queue() {
Vector<String> headers;
if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) {
- FileAccess *file = FileAccess::open(cache_filename_base + ".etag", FileAccess::READ);
- if (file) {
+ Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::READ);
+ if (file.is_valid()) {
headers.push_back("If-None-Match: " + file->get_line());
- file->close();
- memdelete(file);
}
}
@@ -869,7 +880,7 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag
iq.image_index = p_image_index;
iq.image_type = p_type;
iq.request = memnew(HTTPRequest);
- iq.request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
+ setup_http_request(iq.request);
iq.target = p_for;
iq.queue_id = ++last_queue_id;
@@ -886,6 +897,19 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag
}
void EditorAssetLibrary::_repository_changed(int p_repository_id) {
+ library_error->hide();
+ library_info->set_text(TTR("Loading..."));
+ library_info->show();
+
+ asset_top_page->hide();
+ asset_bottom_page->hide();
+ asset_items->hide();
+
+ filter->set_editable(false);
+ sort->set_disabled(true);
+ categories->set_disabled(true);
+ support->set_disabled(true);
+
host = repository->get_item_metadata(p_repository_id);
if (templates_only) {
_api_request("configure", REQUESTING_CONFIG, "?type=project");
@@ -922,7 +946,7 @@ void EditorAssetLibrary::_search(int p_page) {
support_list += String(support_key[i]) + "+";
}
}
- if (support_list != String()) {
+ if (!support_list.is_empty()) {
args += "&support=" + support_list.substr(0, support_list.length() - 1);
}
@@ -935,7 +959,7 @@ void EditorAssetLibrary::_search(int p_page) {
args += "&reverse=true";
}
- if (filter->get_text() != String()) {
+ if (!filter->get_text().is_empty()) {
args += "&filter=" + filter->get_text().uri_encode();
}
@@ -954,6 +978,10 @@ void EditorAssetLibrary::_filter_debounce_timer_timeout() {
_search();
}
+void EditorAssetLibrary::_request_current_config() {
+ _repository_changed(repository->get_selected());
+}
+
HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int p_page_len, int p_total_items, int p_current_items) {
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -975,7 +1003,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
hbc->add_theme_constant_override("separation", 5 * EDSCALE);
Button *first = memnew(Button);
- first->set_text(TTR("First"));
+ first->set_text(TTR("First", "Pagination"));
if (p_page != 0) {
first->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(0));
} else {
@@ -985,7 +1013,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
hbc->add_child(first);
Button *prev = memnew(Button);
- prev->set_text(TTR("Previous"));
+ prev->set_text(TTR("Previous", "Pagination"));
if (p_page > 0) {
prev->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(p_page - 1));
} else {
@@ -1015,7 +1043,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
}
Button *next = memnew(Button);
- next->set_text(TTR("Next"));
+ next->set_text(TTR("Next", "Pagination"));
if (p_page < p_page_count - 1) {
next->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(p_page + 1));
} else {
@@ -1026,7 +1054,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
hbc->add_child(next);
Button *last = memnew(Button);
- last->set_text(TTR("Last"));
+ last->set_text(TTR("Last", "Pagination"));
if (p_page != p_page_count - 1) {
last->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(p_page_count - 1));
} else {
@@ -1095,6 +1123,10 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
}
if (error_abort) {
+ if (requesting == REQUESTING_CONFIG) {
+ library_info->hide();
+ library_error->show();
+ }
error_hb->show();
return;
}
@@ -1124,22 +1156,21 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
String name = cat["name"];
int id = cat["id"];
categories->add_item(name);
- categories->set_item_metadata(categories->get_item_count() - 1, id);
+ categories->set_item_metadata(-1, id);
category_map[cat["id"]] = name;
}
}
+ filter->set_editable(true);
+ sort->set_disabled(false);
+ categories->set_disabled(false);
+ support->set_disabled(false);
+
_search();
} break;
case REQUESTING_SEARCH: {
initial_loading = false;
- // 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);
}
@@ -1179,8 +1210,8 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
asset_items = memnew(GridContainer);
asset_items->set_columns(2);
- asset_items->add_theme_constant_override("hseparation", 10 * EDSCALE);
- asset_items->add_theme_constant_override("vseparation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("h_separation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("v_separation", 10 * EDSCALE);
library_vb->add_child(asset_items);
@@ -1188,17 +1219,19 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
library_vb->add_child(asset_bottom_page);
if (result.is_empty()) {
- if (filter->get_text() != String()) {
- library_error->set_text(
+ if (!filter->get_text().is_empty()) {
+ library_info->set_text(
vformat(TTR("No results for \"%s\"."), filter->get_text()));
} else {
// No results, even though the user didn't search for anything specific.
// This is typically because the version number changed recently
// and no assets compatible with the new version have been published yet.
- library_error->set_text(
+ library_info->set_text(
vformat(TTR("No results compatible with %s %s."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH)));
}
- library_error->show();
+ library_info->show();
+ } else {
+ library_info->hide();
}
for (int i = 0; i < result.size(); i++) {
@@ -1219,7 +1252,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
item->connect("author_selected", callable_mp(this, &EditorAssetLibrary::_select_author));
item->connect("category_selected", callable_mp(this, &EditorAssetLibrary::_select_category));
- if (r.has("icon_url") && r["icon_url"] != "") {
+ if (r.has("icon_url") && !r["icon_url"].operator String().is_empty()) {
_request_image(item->get_instance_id(), r["icon_url"], IMAGE_QUEUE_ICON, 0);
}
}
@@ -1256,7 +1289,21 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
description->configure(r["title"], r["asset_id"], category_map[r["category_id"]], r["category_id"], r["author"], r["author_id"], r["cost"], r["version"], r["version_string"], r["description"], r["download_url"], r["browse_url"], r["download_hash"]);
- if (r.has("icon_url") && r["icon_url"] != "") {
+ EditorAssetLibraryItemDownload *download_item = _get_asset_in_progress(description->get_asset_id());
+ if (download_item) {
+ if (download_item->can_install()) {
+ description->get_ok_button()->set_text(TTR("Install"));
+ description->get_ok_button()->set_disabled(false);
+ } else {
+ description->get_ok_button()->set_text(TTR("Downloading..."));
+ description->get_ok_button()->set_disabled(true);
+ }
+ } else {
+ description->get_ok_button()->set_text(TTR("Download"));
+ description->get_ok_button()->set_disabled(false);
+ }
+
+ if (r.has("icon_url") && !r["icon_url"].operator String().is_empty()) {
_request_image(description->get_instance_id(), r["icon_url"], IMAGE_QUEUE_ICON, 0);
}
@@ -1313,6 +1360,17 @@ void EditorAssetLibrary::_manage_plugins() {
ProjectSettingsEditor::get_singleton()->set_plugins_page();
}
+EditorAssetLibraryItemDownload *EditorAssetLibrary::_get_asset_in_progress(int p_asset_id) const {
+ for (int i = 0; i < downloads_hb->get_child_count(); i++) {
+ EditorAssetLibraryItemDownload *d = Object::cast_to<EditorAssetLibraryItemDownload>(downloads_hb->get_child(i));
+ if (d && d->get_asset_id() == p_asset_id) {
+ return d;
+ }
+ }
+
+ return nullptr;
+}
+
void EditorAssetLibrary::_install_external_asset(String p_zip_path, String p_title) {
emit_signal(SNAME("install_asset"), p_zip_path, p_title);
}
@@ -1331,7 +1389,6 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
initial_loading = true;
VBoxContainer *library_main = memnew(VBoxContainer);
-
add_child(library_main);
HBoxContainer *search_hb = memnew(HBoxContainer);
@@ -1345,6 +1402,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
} else {
filter->set_placeholder(TTR("Search assets (excluding templates, projects, and demos)"));
}
+ filter->set_clear_button_enabled(true);
search_hb->add_child(filter);
filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->connect("text_changed", callable_mp(this, &EditorAssetLibrary::_search_text_changed));
@@ -1431,8 +1489,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_scroll_bg->set_v_size_flags(Control::SIZE_EXPAND_FILL);
library_scroll = memnew(ScrollContainer);
- library_scroll->set_enable_v_scroll(true);
- library_scroll->set_enable_h_scroll(false);
+ library_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
library_scroll_bg->add_child(library_scroll);
@@ -1453,22 +1510,30 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_vb_border->add_child(library_vb);
- library_loading = memnew(Label(TTR("Loading...")));
- library_loading->set_align(Label::ALIGN_CENTER);
- library_vb->add_child(library_loading);
+ library_info = memnew(Label);
+ library_info->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ library_vb->add_child(library_info);
- library_error = memnew(Label);
- library_error->set_align(Label::ALIGN_CENTER);
+ library_error = memnew(VBoxContainer);
library_error->hide();
library_vb->add_child(library_error);
+ library_error_label = memnew(Label(TTR("Failed to get repository configuration.")));
+ library_error_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ library_error->add_child(library_error_label);
+
+ library_error_retry = memnew(Button(TTR("Retry")));
+ library_error_retry->set_h_size_flags(SIZE_SHRINK_CENTER);
+ library_error_retry->connect("pressed", callable_mp(this, &EditorAssetLibrary::_request_current_config));
+ library_error->add_child(library_error_retry);
+
asset_top_page = memnew(HBoxContainer);
library_vb->add_child(asset_top_page);
asset_items = memnew(GridContainer);
asset_items->set_columns(2);
- asset_items->add_theme_constant_override("hseparation", 10 * EDSCALE);
- asset_items->add_theme_constant_override("vseparation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("h_separation", 10 * EDSCALE);
+ asset_items->add_theme_constant_override("v_separation", 10 * EDSCALE);
library_vb->add_child(asset_items);
@@ -1477,7 +1542,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
request = memnew(HTTPRequest);
add_child(request);
- request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
+ setup_http_request(request);
request->connect("request_completed", callable_mp(this, &EditorAssetLibrary::_http_request_completed));
last_queue_id = 0;
@@ -1487,7 +1552,6 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
error_hb = memnew(HBoxContainer);
library_main->add_child(error_hb);
error_label = memnew(Label);
- error_label->add_theme_color_override("color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
error_hb->add_child(error_label);
error_tr = memnew(TextureRect);
error_tr->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
@@ -1496,11 +1560,10 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
description = nullptr;
set_process(true);
- set_process_unhandled_key_input(true); // Global shortcuts since there is no main element to be focused.
+ set_process_shortcut_input(true); // Global shortcuts since there is no main element to be focused.
downloads_scroll = memnew(ScrollContainer);
- downloads_scroll->set_enable_h_scroll(true);
- downloads_scroll->set_enable_v_scroll(false);
+ downloads_scroll->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
library_main->add_child(downloads_scroll);
downloads_hb = memnew(HBoxContainer);
downloads_scroll->add_child(downloads_hb);
@@ -1526,11 +1589,10 @@ void AssetLibraryEditorPlugin::make_visible(bool p_visible) {
}
}
-AssetLibraryEditorPlugin::AssetLibraryEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+AssetLibraryEditorPlugin::AssetLibraryEditorPlugin() {
addon_library = memnew(EditorAssetLibrary);
addon_library->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- editor->get_main_control()->add_child(addon_library);
+ EditorNode::get_singleton()->get_main_control()->add_child(addon_library);
addon_library->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
addon_library->hide();
}
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 5fbf2833b2..24d7c1d24c 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -39,6 +39,7 @@
#include "scene/gui/grid_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/link_button.h"
+#include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/progress_bar.h"
@@ -52,16 +53,16 @@
class EditorAssetLibraryItem : public PanelContainer {
GDCLASS(EditorAssetLibraryItem, PanelContainer);
- TextureButton *icon;
- LinkButton *title;
- LinkButton *category;
- LinkButton *author;
+ TextureButton *icon = nullptr;
+ LinkButton *title = nullptr;
+ LinkButton *category = nullptr;
+ LinkButton *author = nullptr;
TextureRect *stars[5];
- Label *price;
+ Label *price = nullptr;
- int asset_id;
- int category_id;
- int author_id;
+ int asset_id = 0;
+ int category_id = 0;
+ int author_id = 0;
void _asset_clicked();
void _category_clicked();
@@ -82,11 +83,11 @@ public:
class EditorAssetLibraryItemDescription : public ConfirmationDialog {
GDCLASS(EditorAssetLibraryItemDescription, ConfirmationDialog);
- EditorAssetLibraryItem *item;
- RichTextLabel *description;
- ScrollContainer *previews;
- HBoxContainer *preview_hb;
- PanelContainer *previews_bg;
+ EditorAssetLibraryItem *item = nullptr;
+ RichTextLabel *description = nullptr;
+ ScrollContainer *previews = nullptr;
+ HBoxContainer *preview_hb = nullptr;
+ PanelContainer *previews_bg = nullptr;
struct Preview {
int id = 0;
@@ -97,11 +98,11 @@ class EditorAssetLibraryItemDescription : public ConfirmationDialog {
};
Vector<Preview> preview_images;
- TextureRect *preview;
+ TextureRect *preview = nullptr;
void set_image(int p_type, int p_index, const Ref<Texture2D> &p_image);
- int asset_id;
+ int asset_id = 0;
String download_url;
String title;
String sha256;
@@ -126,32 +127,32 @@ public:
EditorAssetLibraryItemDescription();
};
-class EditorAssetLibraryItemDownload : public PanelContainer {
- GDCLASS(EditorAssetLibraryItemDownload, PanelContainer);
+class EditorAssetLibraryItemDownload : public MarginContainer {
+ GDCLASS(EditorAssetLibraryItemDownload, MarginContainer);
- TextureRect *icon;
- Label *title;
- ProgressBar *progress;
- Button *install;
- Button *retry;
- TextureButton *dismiss;
+ PanelContainer *panel = nullptr;
+ TextureRect *icon = nullptr;
+ Label *title = nullptr;
+ ProgressBar *progress = nullptr;
+ Button *install_button = nullptr;
+ Button *retry_button = nullptr;
+ TextureButton *dismiss_button = nullptr;
- AcceptDialog *download_error;
- HTTPRequest *download;
+ AcceptDialog *download_error = nullptr;
+ HTTPRequest *download = nullptr;
String host;
String sha256;
- Label *status;
+ Label *status = nullptr;
int prev_status;
- int asset_id;
+ int asset_id = 0;
bool external_install;
- EditorAssetInstaller *asset_installer;
+ EditorAssetInstaller *asset_installer = nullptr;
void _close();
- void _install();
void _make_request();
void _http_download_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
@@ -163,6 +164,10 @@ public:
void set_external_install(bool p_enable) { external_install = p_enable; }
int get_asset_id() { return asset_id; }
void configure(const String &p_title, int p_asset_id, const Ref<Texture2D> &p_preview, const String &p_download_url, const String &p_sha256_hash);
+
+ bool can_install() const;
+ void install();
+
EditorAssetLibraryItemDownload();
};
@@ -171,35 +176,37 @@ class EditorAssetLibrary : public PanelContainer {
String host;
- EditorFileDialog *asset_open;
- EditorAssetInstaller *asset_installer;
+ EditorFileDialog *asset_open = nullptr;
+ EditorAssetInstaller *asset_installer = nullptr;
void _asset_open();
void _asset_file_selected(const String &p_file);
void _update_repository_options();
- PanelContainer *library_scroll_bg;
- ScrollContainer *library_scroll;
- VBoxContainer *library_vb;
- Label *library_loading;
- Label *library_error;
- LineEdit *filter;
- Timer *filter_debounce_timer;
- OptionButton *categories;
- OptionButton *repository;
- OptionButton *sort;
- HBoxContainer *error_hb;
- TextureRect *error_tr;
- Label *error_label;
- MenuButton *support;
-
- HBoxContainer *contents;
-
- HBoxContainer *asset_top_page;
- GridContainer *asset_items;
- HBoxContainer *asset_bottom_page;
-
- HTTPRequest *request;
+ PanelContainer *library_scroll_bg = nullptr;
+ ScrollContainer *library_scroll = nullptr;
+ VBoxContainer *library_vb = nullptr;
+ Label *library_info = nullptr;
+ VBoxContainer *library_error = nullptr;
+ Label *library_error_label = nullptr;
+ Button *library_error_retry = nullptr;
+ LineEdit *filter = nullptr;
+ Timer *filter_debounce_timer = nullptr;
+ OptionButton *categories = nullptr;
+ OptionButton *repository = nullptr;
+ OptionButton *sort = nullptr;
+ HBoxContainer *error_hb = nullptr;
+ TextureRect *error_tr = nullptr;
+ Label *error_label = nullptr;
+ MenuButton *support = nullptr;
+
+ HBoxContainer *contents = nullptr;
+
+ HBoxContainer *asset_top_page = nullptr;
+ GridContainer *asset_items = nullptr;
+ HBoxContainer *asset_bottom_page = nullptr;
+
+ HTTPRequest *request = nullptr;
bool templates_only;
bool initial_loading;
@@ -255,7 +262,7 @@ class EditorAssetLibrary : public PanelContainer {
HBoxContainer *_make_pages(int p_page, int p_page_count, int p_page_len, int p_total_items, int p_current_items);
//
- EditorAssetLibraryItemDescription *description;
+ EditorAssetLibraryItemDescription *description = nullptr;
//
enum RequestType {
@@ -268,8 +275,8 @@ class EditorAssetLibrary : public PanelContainer {
RequestType requesting;
Dictionary category_map;
- ScrollContainer *downloads_scroll;
- HBoxContainer *downloads_hb;
+ ScrollContainer *downloads_scroll = nullptr;
+ HBoxContainer *downloads_hb = nullptr;
void _install_asset();
@@ -286,6 +293,8 @@ class EditorAssetLibrary : public PanelContainer {
void _api_request(const String &p_request, RequestType p_request_type, const String &p_arguments = "");
void _http_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
void _filter_debounce_timer_timeout();
+ void _request_current_config();
+ EditorAssetLibraryItemDownload *_get_asset_in_progress(int p_asset_id) const;
void _repository_changed(int p_repository_id);
void _support_toggled(int p_support);
@@ -298,7 +307,7 @@ class EditorAssetLibrary : public PanelContainer {
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
public:
void disable_community_support();
@@ -309,8 +318,7 @@ public:
class AssetLibraryEditorPlugin : public EditorPlugin {
GDCLASS(AssetLibraryEditorPlugin, EditorPlugin);
- EditorAssetLibrary *addon_library;
- EditorNode *editor;
+ EditorAssetLibrary *addon_library = nullptr;
public:
virtual String get_name() const override { return "AssetLib"; }
@@ -322,7 +330,7 @@ public:
//virtual Dictionary get_state() const;
//virtual void set_state(const Dictionary& p_state);
- AssetLibraryEditorPlugin(EditorNode *p_node);
+ AssetLibraryEditorPlugin();
~AssetLibraryEditorPlugin();
};
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index 482c08f50a..a60e49ca9d 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -34,33 +34,37 @@
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
#include "editor/audio_stream_preview.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
void AudioStreamEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", callable_mp(this, &AudioStreamEditor::_preview_changed));
- }
-
- if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
- _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
- _stop_button->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
- _preview->set_color(get_theme_color(SNAME("dark_color_2"), SNAME("Editor")));
- set_color(get_theme_color(SNAME("dark_color_1"), SNAME("Editor")));
-
- _indicator->update();
- _preview->update();
- }
-
- if (p_what == NOTIFICATION_PROCESS) {
- _current = _player->get_playback_position();
- _indicator->update();
- }
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (!is_visible_in_tree()) {
- _stop();
- }
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", callable_mp(this, &AudioStreamEditor::_preview_changed));
+ } break;
+
+ case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_ENTER_TREE: {
+ _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ _stop_button->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
+ _preview->set_color(get_theme_color(SNAME("dark_color_2"), SNAME("Editor")));
+ set_color(get_theme_color(SNAME("dark_color_1"), SNAME("Editor")));
+
+ _indicator->update();
+ _preview->update();
+ } break;
+
+ case NOTIFICATION_PROCESS: {
+ _current = _player->get_playback_position();
+ _indicator->update();
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible_in_tree()) {
+ _stop();
+ }
+ } break;
}
}
@@ -157,7 +161,7 @@ void AudioStreamEditor::_draw_indicator() {
void AudioStreamEditor::_on_input_indicator(Ref<InputEvent> p_event) {
const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
_seek_to(mb->get_position().x);
}
@@ -232,7 +236,7 @@ AudioStreamEditor::AudioStreamEditor() {
hbox->add_child(_play_button);
_play_button->set_focus_mode(Control::FOCUS_NONE);
_play_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_play));
- _play_button->set_shortcut(ED_SHORTCUT("inspector/audio_preview_play_pause", TTR("Audio Preview Play/Pause"), KEY_SPACE));
+ _play_button->set_shortcut(ED_SHORTCUT("inspector/audio_preview_play_pause", TTR("Audio Preview Play/Pause"), Key::SPACE));
_stop_button = memnew(Button);
_stop_button->set_flat(true);
@@ -241,7 +245,7 @@ AudioStreamEditor::AudioStreamEditor() {
_stop_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_stop));
_current_label = memnew(Label);
- _current_label->set_align(Label::ALIGN_RIGHT);
+ _current_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
_current_label->set_h_size_flags(SIZE_EXPAND_FILL);
_current_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts")));
_current_label->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("status_source_size"), SNAME("EditorFonts")));
@@ -271,8 +275,7 @@ void AudioStreamEditorPlugin::make_visible(bool p_visible) {
audio_editor->set_visible(p_visible);
}
-AudioStreamEditorPlugin::AudioStreamEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+AudioStreamEditorPlugin::AudioStreamEditorPlugin() {
audio_editor = memnew(AudioStreamEditor);
add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, audio_editor);
audio_editor->hide();
diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h
index 14e829d025..0d927bddd5 100644
--- a/editor/plugins/audio_stream_editor_plugin.h
+++ b/editor/plugins/audio_stream_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef AUDIO_STREAM_EDITOR_PLUGIN_H
#define AUDIO_STREAM_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/audio/audio_stream_player.h"
#include "scene/gui/color_rect.h"
@@ -76,8 +75,7 @@ public:
class AudioStreamEditorPlugin : public EditorPlugin {
GDCLASS(AudioStreamEditorPlugin, EditorPlugin);
- AudioStreamEditor *audio_editor;
- EditorNode *editor;
+ AudioStreamEditor *audio_editor = nullptr;
public:
virtual String get_name() const override { return "Audio"; }
@@ -86,7 +84,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- AudioStreamEditorPlugin(EditorNode *p_node);
+ AudioStreamEditorPlugin();
~AudioStreamEditorPlugin();
};
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
new file mode 100644
index 0000000000..9e551ae0ed
--- /dev/null
+++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
@@ -0,0 +1,121 @@
+/*************************************************************************/
+/* audio_stream_randomizer_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "audio_stream_randomizer_editor_plugin.h"
+
+#include "editor/editor_node.h"
+
+void AudioStreamRandomizerEditorPlugin::edit(Object *p_object) {
+}
+
+bool AudioStreamRandomizerEditorPlugin::handles(Object *p_object) const {
+ return false;
+}
+
+void AudioStreamRandomizerEditorPlugin::make_visible(bool p_visible) {
+}
+
+void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
+ UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo);
+
+ AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited);
+ if (!randomizer) {
+ return;
+ }
+
+ // Compute the array indices to save.
+ int begin = 0;
+ int end;
+ if (p_array_prefix == "stream_") {
+ end = randomizer->get_streams_count();
+ } else {
+ ERR_FAIL_MSG("Invalid array prefix for AudioStreamRandomizer.");
+ }
+ if (p_from_index < 0) {
+ // Adding new.
+ if (p_to_pos >= 0) {
+ begin = p_to_pos;
+ } else {
+ end = 0; // Nothing to save when adding at the end.
+ }
+ } else if (p_to_pos < 0) {
+ // Removing.
+ begin = p_from_index;
+ } else {
+ // Moving.
+ begin = MIN(p_from_index, p_to_pos);
+ end = MIN(MAX(p_from_index, p_to_pos) + 1, end);
+ }
+
+#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
+ // Save layers' properties.
+ if (p_from_index < 0) {
+ undo_redo->add_undo_method(randomizer, "remove_stream", p_to_pos < 0 ? randomizer->get_streams_count() : p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_undo_method(randomizer, "add_stream", p_from_index);
+ }
+
+ List<PropertyInfo> properties;
+ randomizer->get_property_list(&properties);
+ for (PropertyInfo pi : properties) {
+ if (pi.name.begins_with(p_array_prefix)) {
+ String str = pi.name.trim_prefix(p_array_prefix);
+ int to_char_index = 0;
+ while (to_char_index < str.length()) {
+ if (str[to_char_index] < '0' || str[to_char_index] > '9') {
+ break;
+ }
+ to_char_index++;
+ }
+ if (to_char_index > 0) {
+ int array_index = str.left(to_char_index).to_int();
+ if (array_index >= begin && array_index < end) {
+ ADD_UNDO(randomizer, pi.name);
+ }
+ }
+ }
+ }
+#undef ADD_UNDO
+
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(randomizer, "add_stream", p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(randomizer, "remove_stream", p_from_index);
+ } else {
+ undo_redo->add_do_method(randomizer, "move_stream", p_from_index, p_to_pos);
+ }
+}
+
+AudioStreamRandomizerEditorPlugin::AudioStreamRandomizerEditorPlugin() {
+ EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("AudioStreamRandomizer"), callable_mp(this, &AudioStreamRandomizerEditorPlugin::_move_stream_array_element));
+}
+
+AudioStreamRandomizerEditorPlugin::~AudioStreamRandomizerEditorPlugin() {}
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.h b/editor/plugins/audio_stream_randomizer_editor_plugin.h
new file mode 100644
index 0000000000..7e509dc670
--- /dev/null
+++ b/editor/plugins/audio_stream_randomizer_editor_plugin.h
@@ -0,0 +1,54 @@
+/*************************************************************************/
+/* audio_stream_randomizer_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 AUDIO_STREAM_RANDOMIZER_EDITOR_PLUGIN_H
+#define AUDIO_STREAM_RANDOMIZER_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "servers/audio/audio_stream.h"
+
+class AudioStreamRandomizerEditorPlugin : public EditorPlugin {
+ GDCLASS(AudioStreamRandomizerEditorPlugin, EditorPlugin);
+
+private:
+ void _move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos);
+
+public:
+ virtual String get_name() const override { return "AudioStreamRandomizer"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ AudioStreamRandomizerEditorPlugin();
+ ~AudioStreamRandomizerEditorPlugin();
+};
+
+#endif // AUDIO_STREAM_RANDOMIZER_EDITOR_PLUGIN_H
diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp
new file mode 100644
index 0000000000..9003c4480b
--- /dev/null
+++ b/editor/plugins/bit_map_editor_plugin.cpp
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* bit_map_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "bit_map_editor_plugin.h"
+
+#include "editor/editor_scale.h"
+
+void BitMapEditor::setup(const Ref<BitMap> &p_bitmap) {
+ Ref<ImageTexture> texture;
+ texture.instantiate();
+ texture->create_from_image(p_bitmap->convert_to_image());
+ texture_rect->set_texture(texture);
+
+ size_label->set_text(vformat(String::utf8("%s×%s"), p_bitmap->get_size().width, p_bitmap->get_size().height));
+}
+
+BitMapEditor::BitMapEditor() {
+ texture_rect = memnew(TextureRect);
+ texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+ texture_rect->set_texture_filter(TEXTURE_FILTER_NEAREST);
+ texture_rect->set_custom_minimum_size(Size2(0, 250) * EDSCALE);
+ add_child(texture_rect);
+
+ size_label = memnew(Label);
+ size_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
+ add_child(size_label);
+
+ // Reduce extra padding on top and bottom of size label.
+ Ref<StyleBoxEmpty> stylebox;
+ stylebox.instantiate();
+ stylebox->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+ size_label->add_theme_style_override("normal", stylebox);
+}
+
+///////////////////////
+
+bool EditorInspectorPluginBitMap::can_handle(Object *p_object) {
+ return Object::cast_to<BitMap>(p_object) != nullptr;
+}
+
+void EditorInspectorPluginBitMap::parse_begin(Object *p_object) {
+ BitMap *bitmap = Object::cast_to<BitMap>(p_object);
+ if (!bitmap) {
+ return;
+ }
+ Ref<BitMap> bm(bitmap);
+
+ BitMapEditor *editor = memnew(BitMapEditor);
+ editor->setup(bm);
+ add_custom_control(editor);
+}
+
+///////////////////////
+
+BitMapEditorPlugin::BitMapEditorPlugin() {
+ Ref<EditorInspectorPluginBitMap> plugin;
+ plugin.instantiate();
+ add_inspector_plugin(plugin);
+}
diff --git a/editor/plugins/bit_map_editor_plugin.h b/editor/plugins/bit_map_editor_plugin.h
new file mode 100644
index 0000000000..c883e5542f
--- /dev/null
+++ b/editor/plugins/bit_map_editor_plugin.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* bit_map_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 BIT_MAP_PREVIEW_EDITOR_PLUGIN_H
+#define BIT_MAP_PREVIEW_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "scene/resources/bit_map.h"
+
+class BitMapEditor : public VBoxContainer {
+ GDCLASS(BitMapEditor, VBoxContainer);
+
+ TextureRect *texture_rect = nullptr;
+ Label *size_label = nullptr;
+
+public:
+ void setup(const Ref<BitMap> &p_bitmap);
+
+ BitMapEditor();
+};
+
+class EditorInspectorPluginBitMap : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginBitMap, EditorInspectorPlugin);
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual void parse_begin(Object *p_object) override;
+};
+
+class BitMapEditorPlugin : public EditorPlugin {
+ GDCLASS(BitMapEditorPlugin, EditorPlugin);
+
+public:
+ BitMapEditorPlugin();
+};
+
+#endif // BIT_MAP_PREVIEW_EDITOR_PLUGIN_H
diff --git a/editor/plugins/camera_3d_editor_plugin.cpp b/editor/plugins/camera_3d_editor_plugin.cpp
index 8583e95b25..141837244a 100644
--- a/editor/plugins/camera_3d_editor_plugin.cpp
+++ b/editor/plugins/camera_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,7 @@
#include "camera_3d_editor_plugin.h"
+#include "editor/editor_node.h"
#include "node_3d_editor_plugin.h"
void Camera3DEditor::_node_removed(Node *p_node) {
@@ -95,10 +96,9 @@ void Camera3DEditorPlugin::make_visible(bool p_visible) {
}
}
-Camera3DEditorPlugin::Camera3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+Camera3DEditorPlugin::Camera3DEditorPlugin() {
/* camera_editor = memnew( CameraEditor );
- editor->get_main_control()->add_child(camera_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(camera_editor);
camera_editor->set_anchor(SIDE_LEFT,Control::ANCHOR_END);
camera_editor->set_anchor(SIDE_RIGHT,Control::ANCHOR_END);
diff --git a/editor/plugins/camera_3d_editor_plugin.h b/editor/plugins/camera_3d_editor_plugin.h
index e087dd22a8..a8164f9b85 100644
--- a/editor/plugins/camera_3d_editor_plugin.h
+++ b/editor/plugins/camera_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,16 +31,15 @@
#ifndef CAMERA_EDITOR_PLUGIN_H
#define CAMERA_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/camera_3d.h"
class Camera3DEditor : public Control {
GDCLASS(Camera3DEditor, Control);
- Panel *panel;
- Button *preview;
- Node *node;
+ Panel *panel = nullptr;
+ Button *preview = nullptr;
+ Node *node = nullptr;
void _pressed();
@@ -57,7 +56,6 @@ class Camera3DEditorPlugin : public EditorPlugin {
GDCLASS(Camera3DEditorPlugin, EditorPlugin);
//CameraEditor *camera_editor;
- EditorNode *editor;
public:
virtual String get_name() const override { return "Camera3D"; }
@@ -66,7 +64,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- Camera3DEditorPlugin(EditorNode *p_node);
+ Camera3DEditorPlugin();
~Camera3DEditorPlugin();
};
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 3710b26d1e..d237697597 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -39,8 +39,10 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_toaster.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
+#include "editor/scene_tree_dock.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/2d/gpu_particles_2d.h"
#include "scene/2d/light_2d.h"
@@ -51,18 +53,19 @@
#include "scene/gui/grid_container.h"
#include "scene/gui/nine_patch_rect.h"
#include "scene/gui/subviewport_container.h"
+#include "scene/gui/view_panner.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
// Min and Max are power of two in order to play nicely with successive increment.
// That way, we can naturally reach a 100% zoom from boundaries.
-#define MIN_ZOOM 1. / 128
-#define MAX_ZOOM 128
+constexpr real_t MIN_ZOOM = 1. / 128;
+constexpr real_t MAX_ZOOM = 128;
#define RULER_WIDTH (15 * EDSCALE)
-#define SCALE_HANDLE_DISTANCE 25
-#define MOVE_HANDLE_DISTANCE 25
+constexpr real_t SCALE_HANDLE_DISTANCE = 25;
+constexpr real_t MOVE_HANDLE_DISTANCE = 25;
class SnapDialog : public ConfirmationDialog {
GDCLASS(SnapDialog, ConfirmationDialog);
@@ -242,7 +245,7 @@ bool CanvasItemEditor::_is_node_movable(const Node *p_node, bool p_popup_warning
}
if (Object::cast_to<Control>(p_node) && Object::cast_to<Container>(p_node->get_parent())) {
if (p_popup_warning) {
- _popup_warning_temporarily(warning_child_of_container, 3.0);
+ EditorToaster::get_singleton()->popup_str("Children of a container get their position and size determined only by their parent.", EditorToaster::SEVERITY_WARNING);
}
return false;
}
@@ -333,7 +336,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
- bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(KEY_CTRL);
+ bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(Key::CTRL);
// Smart snap using the canvas position
Vector2 output = p_target;
@@ -461,7 +464,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
}
real_t CanvasItemEditor::snap_angle(real_t p_target, real_t p_start) const {
- if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CTRL)) && snap_rotation_step != 0) {
+ if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(Key::CTRL)) && snap_rotation_step != 0) {
if (snap_relative) {
return Math::snapped(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset + (p_start - (int)(p_start / snap_rotation_step) * snap_rotation_step);
} else {
@@ -472,7 +475,7 @@ real_t CanvasItemEditor::snap_angle(real_t p_target, real_t p_start) const {
}
}
-void CanvasItemEditor::unhandled_key_input(const Ref<InputEvent> &p_ev) {
+void CanvasItemEditor::shortcut_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventKey> k = p_ev;
@@ -482,16 +485,16 @@ void CanvasItemEditor::unhandled_key_input(const Ref<InputEvent> &p_ev) {
}
if (k.is_valid()) {
- if (k->get_keycode() == KEY_CTRL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) {
+ if (k->get_keycode() == Key::CTRL || k->get_keycode() == Key::ALT || k->get_keycode() == Key::SHIFT) {
viewport->update();
}
- if (k->is_pressed() && !k->is_ctrl_pressed() && !k->is_echo()) {
- if ((grid_snap_active || show_grid) && multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->matches_event(p_ev)) {
+ if (k->is_pressed() && !k->is_ctrl_pressed() && !k->is_echo() && (grid_snap_active || _is_grid_visible())) {
+ if (multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->matches_event(p_ev)) {
// Multiply the grid size
grid_step_multiplier = MIN(grid_step_multiplier + 1, 12);
viewport->update();
- } else if ((grid_snap_active || show_grid) && divide_grid_step_shortcut.is_valid() && divide_grid_step_shortcut->matches_event(p_ev)) {
+ } else if (divide_grid_step_shortcut.is_valid() && divide_grid_step_shortcut->matches_event(p_ev)) {
// Divide the grid size
Point2 new_grid_step = grid_step * Math::pow(2.0, grid_step_multiplier - 1);
if (new_grid_step.x >= 1.0 && new_grid_step.y >= 1.0) {
@@ -622,7 +625,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
}
void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked) {
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
_find_canvas_items_at_pos(p_pos, scene, r_items);
@@ -658,7 +661,7 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
//Remove the item if invalid
if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || (!p_allow_locked && _is_node_locked(canvas_item))) {
- r_items.remove(i);
+ r_items.remove_at(i);
i--;
} else {
r_items.write[i].item = canvas_item;
@@ -675,7 +678,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
}
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
bool editable = p_node == scene || p_node->get_owner() == scene || p_node == scene->get_deepest_editable_node(p_node);
bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
@@ -724,7 +727,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
still_selected = false;
if (editor_selection->get_selected_node_list().size() == 1) {
- editor->push_item(editor_selection->get_selected_node_list()[0]);
+ EditorNode::get_singleton()->push_item(editor_selection->get_selected_node_list()[0]);
}
} else {
// Add the item to the selection
@@ -738,7 +741,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
// Reselect
if (Engine::get_singleton()->is_editor_hint()) {
selected_from_canvas = true;
- editor->call("edit_node", item);
+ EditorNode::get_singleton()->edit_node(item);
}
}
}
@@ -746,11 +749,11 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
return still_selected;
}
-List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retreive_locked, bool remove_canvas_item_if_parent_in_selection) {
+List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) {
List<CanvasItem *> selection;
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
- if (canvas_item && canvas_item->is_visible_in_tree() && canvas_item->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retreive_locked || !_is_node_locked(canvas_item))) {
+ if (canvas_item && canvas_item->is_visible_in_tree() && canvas_item->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retrieve_locked || !_is_node_locked(canvas_item))) {
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (se) {
selection.push_back(canvas_item);
@@ -857,7 +860,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, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
+ static_cast<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();
}
@@ -877,14 +880,43 @@ void CanvasItemEditor::_selection_result_pressed(int p_result) {
void CanvasItemEditor::_selection_menu_hide() {
selection_results.clear();
selection_menu->clear();
- selection_menu->set_size(Vector2(0, 0));
+ selection_menu->reset_size();
}
void CanvasItemEditor::_add_node_pressed(int p_result) {
- if (p_result == AddNodeOption::ADD_NODE) {
- editor->get_scene_tree_dock()->open_add_child_dialog();
- } else if (p_result == AddNodeOption::ADD_INSTANCE) {
- editor->get_scene_tree_dock()->open_instance_child_dialog();
+ List<Node *> nodes_to_move;
+
+ switch (p_result) {
+ case ADD_NODE: {
+ SceneTreeDock::get_singleton()->open_add_child_dialog();
+ } break;
+ case ADD_INSTANCE: {
+ SceneTreeDock::get_singleton()->open_instance_child_dialog();
+ } break;
+ case ADD_PASTE: {
+ nodes_to_move = SceneTreeDock::get_singleton()->paste_nodes();
+ [[fallthrough]];
+ }
+ case ADD_MOVE: {
+ if (p_result == ADD_MOVE) {
+ nodes_to_move = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list();
+ }
+ if (nodes_to_move.is_empty()) {
+ return;
+ }
+
+ undo_redo->create_action(TTR("Move Node(s) to Position"));
+ for (Node *node : nodes_to_move) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(node);
+ if (ci) {
+ Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse() * ci->get_transform();
+ undo_redo->add_do_method(ci, "_edit_set_position", xform.xform(node_create_position));
+ undo_redo->add_undo_method(ci, "_edit_set_position", ci->_edit_get_position());
+ }
+ }
+ undo_redo->commit_action();
+ _reset_create_position();
+ } break;
}
}
@@ -906,6 +938,60 @@ void CanvasItemEditor::_reset_create_position() {
node_create_position = Point2();
}
+bool CanvasItemEditor::_is_grid_visible() const {
+ switch (grid_visibility) {
+ case GRID_VISIBILITY_SHOW:
+ return true;
+ case GRID_VISIBILITY_SHOW_WHEN_SNAPPING:
+ return grid_snap_active;
+ case GRID_VISIBILITY_HIDE:
+ return false;
+ }
+ ERR_FAIL_V_MSG(true, "Unexpected grid_visibility value");
+}
+
+void CanvasItemEditor::_prepare_grid_menu() {
+ for (int i = GRID_VISIBILITY_SHOW; i <= GRID_VISIBILITY_HIDE; i++) {
+ grid_menu->set_item_checked(i, i == grid_visibility);
+ }
+}
+
+void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
+ switch (p_id) {
+ case GRID_VISIBILITY_SHOW:
+ case GRID_VISIBILITY_SHOW_WHEN_SNAPPING:
+ case GRID_VISIBILITY_HIDE:
+ grid_visibility = (GridVisibility)p_id;
+ viewport->update();
+ view_menu->get_popup()->hide();
+ return;
+ }
+
+ // Toggle grid: go to the least restrictive option possible.
+ if (grid_snap_active) {
+ switch (grid_visibility) {
+ case GRID_VISIBILITY_SHOW:
+ case GRID_VISIBILITY_SHOW_WHEN_SNAPPING:
+ grid_visibility = GRID_VISIBILITY_HIDE;
+ break;
+ case GRID_VISIBILITY_HIDE:
+ grid_visibility = GRID_VISIBILITY_SHOW_WHEN_SNAPPING;
+ break;
+ }
+ } else {
+ switch (grid_visibility) {
+ case GRID_VISIBILITY_SHOW:
+ grid_visibility = GRID_VISIBILITY_SHOW_WHEN_SNAPPING;
+ break;
+ case GRID_VISIBILITY_SHOW_WHEN_SNAPPING:
+ case GRID_VISIBILITY_HIDE:
+ grid_visibility = GRID_VISIBILITY_SHOW;
+ break;
+ }
+ }
+ viewport->update();
+}
+
bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
Ref<InputEventMouseMotion> m = p_event;
@@ -950,7 +1036,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
// Start dragging a guide
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
// Press button
if (b->get_position().x < RULER_WIDTH && b->get_position().y < RULER_WIDTH) {
// Drag a new double guide
@@ -1009,7 +1095,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
// Release confirms the guide move
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && !b->is_pressed()) {
if (show_guides && EditorNode::get_singleton()->get_edited_scene()) {
Transform2D xform = viewport_scrollable->get_transform() * transform;
@@ -1045,7 +1131,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
} else {
if (dragged_guide_index >= 0) {
- vguides.remove(dragged_guide_index);
+ vguides.remove_at(dragged_guide_index);
undo_redo->create_action(TTR("Remove Vertical Guide"));
if (vguides.is_empty()) {
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_vertical_guides_");
@@ -1078,7 +1164,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
} else {
if (dragged_guide_index >= 0) {
- hguides.remove(dragged_guide_index);
+ hguides.remove_at(dragged_guide_index);
undo_redo->create_action(TTR("Remove Horizontal Guide"));
if (hguides.is_empty()) {
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_horizontal_guides_");
@@ -1107,6 +1193,8 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
}
}
+ snap_target[0] = SNAP_TARGET_NONE;
+ snap_target[1] = SNAP_TARGET_NONE;
drag_type = DRAG_NONE;
viewport->update();
return true;
@@ -1116,142 +1204,42 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bool p_already_accepted) {
- Ref<InputEventMouseButton> b = p_event;
- if (b.is_valid() && !p_already_accepted) {
- const bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->is_ctrl_pressed();
-
- if (pan_on_scroll) {
- // Perform horizontal scrolling first so we can check for Shift being held.
- if (b->is_pressed() &&
- (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->is_shift_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP))) {
- // Pan left
- view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- update_viewport();
- return true;
- }
-
- if (b->is_pressed() &&
- (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->is_shift_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN))) {
- // Pan right
- view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- update_viewport();
- return true;
- }
- }
-
- if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
- // Scroll or pan down
- if (pan_on_scroll) {
- view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- update_viewport();
- } else {
- zoom_widget->set_zoom_by_increments(-1, Input::get_singleton()->is_key_pressed(KEY_ALT));
- if (!Math::is_equal_approx(b->get_factor(), 1.0f)) {
- // Handle high-precision (analog) scrolling.
- zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * b->get_factor() + 1.f));
- }
- _zoom_on_position(zoom_widget->get_zoom(), b->get_position());
- }
- return true;
- }
-
- if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
- // Scroll or pan up
- if (pan_on_scroll) {
- view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- update_viewport();
- } else {
- zoom_widget->set_zoom_by_increments(1, Input::get_singleton()->is_key_pressed(KEY_ALT));
- if (!Math::is_equal_approx(b->get_factor(), 1.0f)) {
- // Handle high-precision (analog) scrolling.
- zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * b->get_factor() + 1.f));
- }
- _zoom_on_position(zoom_widget->get_zoom(), b->get_position());
- }
- return true;
- }
-
- if (!panning) {
- if (b->is_pressed() &&
- (b->get_button_index() == MOUSE_BUTTON_MIDDLE ||
- (b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_PAN) ||
- (b->get_button_index() == MOUSE_BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_panning") && pan_pressed))) {
- // Pan the viewport
- panning = true;
- }
- }
+ panner->set_force_drag(tool == TOOL_PAN);
+ bool panner_active = panner->gui_input(p_event, warped_panning ? viewport->get_global_rect() : Rect2());
+ if (panner->is_panning() != pan_pressed) {
+ pan_pressed = panner->is_panning();
+ _update_cursor();
+ }
- if (panning) {
- if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != MOUSE_BUTTON_WHEEL_DOWN && b->get_button_index() != MOUSE_BUTTON_WHEEL_UP))) {
- // Stop panning the viewport (for any mouse button press except zooming)
- panning = false;
- }
- }
+ if (panner_active) {
+ return true;
}
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
if (k->is_pressed()) {
if (ED_GET_SHORTCUT("canvas_item_editor/zoom_3.125_percent")->matches_event(p_event)) {
- _update_zoom((1.0 / 32.0) * MAX(1, EDSCALE));
+ _shortcut_zoom_set(1.0 / 32.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_6.25_percent")->matches_event(p_event)) {
- _update_zoom((1.0 / 16.0) * MAX(1, EDSCALE));
+ _shortcut_zoom_set(1.0 / 16.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_12.5_percent")->matches_event(p_event)) {
- _update_zoom((1.0 / 8.0) * MAX(1, EDSCALE));
+ _shortcut_zoom_set(1.0 / 8.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_25_percent")->matches_event(p_event)) {
- _update_zoom((1.0 / 4.0) * MAX(1, EDSCALE));
+ _shortcut_zoom_set(1.0 / 4.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_50_percent")->matches_event(p_event)) {
- _update_zoom((1.0 / 2.0) * MAX(1, EDSCALE));
+ _shortcut_zoom_set(1.0 / 2.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_100_percent")->matches_event(p_event)) {
- _update_zoom(1.0 * MAX(1, EDSCALE));
+ _shortcut_zoom_set(1.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_200_percent")->matches_event(p_event)) {
- _update_zoom(2.0 * MAX(1, EDSCALE));
+ _shortcut_zoom_set(2.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_400_percent")->matches_event(p_event)) {
- _update_zoom(4.0 * MAX(1, EDSCALE));
+ _shortcut_zoom_set(4.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_800_percent")->matches_event(p_event)) {
- _update_zoom(8.0 * MAX(1, EDSCALE));
+ _shortcut_zoom_set(8.0);
} else if (ED_GET_SHORTCUT("canvas_item_editor/zoom_1600_percent")->matches_event(p_event)) {
- _update_zoom(16.0 * MAX(1, EDSCALE));
+ _shortcut_zoom_set(16.0);
}
}
-
- bool is_pan_key = pan_view_shortcut.is_valid() && pan_view_shortcut->matches_event(p_event);
-
- if (is_pan_key && (EditorSettings::get_singleton()->get("editors/2d/simple_panning") || drag_type != DRAG_NONE)) {
- if (!panning) {
- if (k->is_pressed() && !k->is_echo()) {
- //Pan the viewport
- panning = true;
- }
- } else {
- if (!k->is_pressed()) {
- // Stop panning the viewport (for any mouse button press)
- panning = false;
- }
- }
- }
-
- if (is_pan_key && pan_pressed != k->is_pressed()) {
- pan_pressed = k->is_pressed();
- _update_cursor();
- }
- }
-
- Ref<InputEventMouseMotion> m = p_event;
- if (m.is_valid()) {
- if (panning) {
- // Pan the viewport
- Point2i relative;
- if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) {
- relative = Input::get_singleton()->warp_mouse_motion(m, viewport->get_global_rect());
- } else {
- relative = m->get_relative();
- }
- view_offset.x -= relative.x / zoom;
- view_offset.y -= relative.y / zoom;
- update_viewport();
- return true;
- }
}
Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
@@ -1277,7 +1265,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
// Pan gesture
- const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
+ const Vector2 delta = (pan_speed / zoom) * pan_gesture->get_delta();
view_offset.x += delta.x;
view_offset.y += delta.y;
update_viewport();
@@ -1287,6 +1275,25 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
return false;
}
+void CanvasItemEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
+ _pan_callback(-p_scroll_vec * pan_speed);
+}
+
+void CanvasItemEditor::_pan_callback(Vector2 p_scroll_vec) {
+ view_offset.x -= p_scroll_vec.x / zoom;
+ view_offset.y -= p_scroll_vec.y / zoom;
+ update_viewport();
+}
+
+void CanvasItemEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
+ zoom_widget->set_zoom_by_increments(-1, p_alt);
+ if (!Math::is_equal_approx(p_scroll_vec.y, (real_t)1.0)) {
+ // Handle high-precision (analog) scrolling.
+ zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * p_scroll_vec.y + 1.f));
+ }
+ _zoom_on_position(zoom_widget->get_zoom(), p_origin);
+}
+
bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> m = p_event;
Ref<InputEventMouseButton> b = p_event;
@@ -1294,8 +1301,8 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Drag the pivot (in pivot mode / with V key)
if (drag_type == DRAG_NONE) {
- if ((b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
- (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_V && tool == TOOL_SELECT && k->get_modifiers_mask() == 0)) {
+ if ((b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::LEFT && tool == TOOL_EDIT_PIVOT) ||
+ (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::V && tool == TOOL_SELECT && k->get_modifiers_mask() == Key::NONE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
// Filters the selection with nodes that allow setting the pivot
@@ -1345,8 +1352,8 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Confirm the pivot move
if (drag_selection.size() >= 1 &&
- ((b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
- (k.is_valid() && !k->is_pressed() && k->get_keycode() == KEY_V))) {
+ ((b.is_valid() && !b->is_pressed() && b->get_button_index() == MouseButton::LEFT && tool == TOOL_EDIT_PIVOT) ||
+ (k.is_valid() && !k->is_pressed() && k->get_keycode() == Key::V))) {
_commit_canvas_item_state(
drag_selection,
vformat(
@@ -1359,7 +1366,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1375,7 +1382,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
// Start rotation
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
if ((b->is_command_pressed() && !b->is_alt_pressed() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -1418,7 +1425,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
}
// Confirms the node rotation
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && !b->is_pressed()) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
drag_selection,
@@ -1442,7 +1449,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1456,12 +1463,12 @@ bool CanvasItemEditor::_gui_input_open_scene_on_double_click(const Ref<InputEven
Ref<InputEventMouseButton> b = p_event;
// Open a sub-scene on double-click
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && b->is_double_click() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && b->is_double_click() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
- if (canvas_item->get_scene_file_path() != "" && canvas_item != editor->get_edited_scene()) {
- editor->open_request(canvas_item->get_scene_file_path());
+ if (!canvas_item->get_scene_file_path().is_empty() && canvas_item != EditorNode::get_singleton()->get_edited_scene()) {
+ EditorNode::get_singleton()->open_request(canvas_item->get_scene_file_path());
return true;
}
}
@@ -1475,7 +1482,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
// Starts anchor dragging if needed
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
Control *control = Object::cast_to<Control>(selection[0]);
@@ -1497,7 +1504,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
}
}
- DragType dragger[] = {
+ const DragType dragger[] = {
DRAG_ANCHOR_TOP_LEFT,
DRAG_ANCHOR_TOP_RIGHT,
DRAG_ANCHOR_BOTTOM_RIGHT,
@@ -1595,7 +1602,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
}
// Confirms new anchor position
- if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
+ if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MouseButton::LEFT && !b->is_pressed()) {
_commit_canvas_item_state(
drag_selection,
vformat(TTR("Move CanvasItem \"%s\" Anchor"), drag_selection[0]->get_name()));
@@ -1604,7 +1611,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1620,7 +1627,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -1628,14 +1635,14 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
Rect2 rect = canvas_item->_edit_get_rect();
Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
- Vector2 endpoints[4] = {
+ const Vector2 endpoints[4] = {
xform.xform(rect.position),
xform.xform(rect.position + Vector2(rect.size.x, 0)),
xform.xform(rect.position + rect.size),
xform.xform(rect.position + Vector2(0, rect.size.y))
};
- DragType dragger[] = {
+ const DragType dragger[] = {
DRAG_TOP_LEFT,
DRAG_TOP,
DRAG_TOP_RIGHT,
@@ -1774,7 +1781,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
}
// Confirm resize
- if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
+ if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MouseButton::LEFT && !b->is_pressed()) {
const Node2D *node2d = Object::cast_to<Node2D>(drag_selection[0]);
if (node2d) {
// Extends from Node2D.
@@ -1811,7 +1818,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@@ -1829,7 +1836,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_ctrl_pressed()) || tool == TOOL_SCALE)) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_ctrl_pressed()) || tool == TOOL_SCALE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -1876,13 +1883,13 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
bool uniform = m->is_shift_pressed();
- bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
Point2 drag_from_local = simple_xform.xform(drag_from);
Point2 drag_to_local = simple_xform.xform(drag_to);
Point2 offset = drag_to_local - drag_from_local;
- Size2 scale = canvas_item->call("get_scale");
+ Size2 scale = canvas_item->_edit_get_scale();
Size2 original_scale = scale;
real_t ratio = scale.y / scale.x;
if (drag_type == DRAG_SCALE_BOTH) {
@@ -1920,12 +1927,12 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
}
- canvas_item->call("set_scale", scale);
+ canvas_item->_edit_set_scale(scale);
return true;
}
// Confirm resize
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && !b->is_pressed()) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
drag_selection,
@@ -1950,7 +1957,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1967,7 +1974,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
//Start moving the nodes
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
if ((b->is_alt_pressed() && !b->is_ctrl_pressed()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -2050,7 +2057,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
// Confirm the move (only if it was moved)
- if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MouseButton::LEFT) {
if (transform.affine_inverse().xform(b->get_position()) != drag_from) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
@@ -2083,7 +2090,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection, true);
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@@ -2095,10 +2102,18 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
// Move the canvas items with the arrow keys
if (k.is_valid() && k->is_pressed() && (tool == TOOL_SELECT || tool == TOOL_MOVE) &&
- (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)) {
+ (k->get_keycode() == Key::UP || k->get_keycode() == Key::DOWN || k->get_keycode() == Key::LEFT || k->get_keycode() == Key::RIGHT)) {
if (!k->is_echo()) {
- // Start moving the canvas items with the keyboard
- drag_selection = _get_edited_canvas_items();
+ // Start moving the canvas items with the keyboard, if they are movable
+ List<CanvasItem *> selection = _get_edited_canvas_items();
+
+ drag_selection.clear();
+ for (CanvasItem *item : selection) {
+ if (_is_node_movable(item, true)) {
+ drag_selection.push_back(item);
+ }
+ }
+
drag_type = DRAG_KEY_MOVE;
drag_from = Vector2();
drag_to = Vector2();
@@ -2112,13 +2127,13 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
bool move_local_base_rotated = k->is_ctrl_pressed() || k->is_meta_pressed();
Vector2 dir;
- if (k->get_keycode() == KEY_UP) {
+ if (k->get_keycode() == Key::UP) {
dir += Vector2(0, -1);
- } else if (k->get_keycode() == KEY_DOWN) {
+ } else if (k->get_keycode() == Key::DOWN) {
dir += Vector2(0, 1);
- } else if (k->get_keycode() == KEY_LEFT) {
+ } else if (k->get_keycode() == Key::LEFT) {
dir += Vector2(-1, 0);
- } else if (k->get_keycode() == KEY_RIGHT) {
+ } else if (k->get_keycode() == Key::RIGHT) {
dir += Vector2(1, 0);
}
if (k->is_shift_pressed()) {
@@ -2166,12 +2181,12 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
if (k.is_valid() && !k->is_pressed() && drag_type == DRAG_KEY_MOVE && (tool == TOOL_SELECT || tool == TOOL_MOVE) &&
- (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)) {
+ (k->get_keycode() == Key::UP || k->get_keycode() == Key::DOWN || k->get_keycode() == Key::LEFT || k->get_keycode() == Key::RIGHT)) {
// Confirm canvas items move by arrow keys
- if ((!Input::get_singleton()->is_key_pressed(KEY_UP)) &&
- (!Input::get_singleton()->is_key_pressed(KEY_DOWN)) &&
- (!Input::get_singleton()->is_key_pressed(KEY_LEFT)) &&
- (!Input::get_singleton()->is_key_pressed(KEY_RIGHT))) {
+ if ((!Input::get_singleton()->is_key_pressed(Key::UP)) &&
+ (!Input::get_singleton()->is_key_pressed(Key::DOWN)) &&
+ (!Input::get_singleton()->is_key_pressed(Key::LEFT)) &&
+ (!Input::get_singleton()->is_key_pressed(Key::RIGHT))) {
if (drag_selection.size() > 1) {
_commit_canvas_item_state(
drag_selection,
@@ -2192,7 +2207,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
return true;
}
- return (k.is_valid() && (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)); // Accept the key event in any case
+ return (k.is_valid() && (k->get_keycode() == Key::UP || k->get_keycode() == Key::DOWN || k->get_keycode() == Key::LEFT || k->get_keycode() == Key::RIGHT)); // Accept the key event in any case
}
bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
@@ -2201,9 +2216,9 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
if (drag_type == DRAG_NONE) {
- if (b.is_valid() &&
- ((b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_alt_pressed() && tool == TOOL_SELECT) ||
- (b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_LIST_SELECT))) {
+ if (b.is_valid() && b->is_pressed() &&
+ ((b->get_button_index() == MouseButton::RIGHT && b->is_alt_pressed() && tool == TOOL_SELECT) ||
+ (b->get_button_index() == MouseButton::LEFT && tool == TOOL_LIST_SELECT))) {
// Popup the selection menu list
Point2 click = transform.affine_inverse().xform(b->get_position());
@@ -2233,7 +2248,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (_is_node_locked(item)) {
locked = 1;
} else {
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
Node *node = item;
while (node && node != scene->get_parent()) {
@@ -2258,25 +2273,42 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
selection_menu_additive_selection = b->is_shift_pressed();
- selection_menu->set_position(get_screen_transform().xform(b->get_position()));
+ selection_menu->set_position(get_screen_position() + b->get_position());
+ selection_menu->reset_size();
selection_menu->popup();
return true;
}
}
- if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_ctrl_pressed()) {
- add_node_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
- add_node_menu->set_size(Vector2(1, 1));
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
+ add_node_menu->clear();
+ add_node_menu->add_icon_item(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), TTR("Add Node Here"), ADD_NODE);
+ add_node_menu->add_icon_item(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), TTR("Instantiate Scene Here"), ADD_INSTANCE);
+ for (Node *node : SceneTreeDock::get_singleton()->get_node_clipboard()) {
+ if (Object::cast_to<CanvasItem>(node)) {
+ add_node_menu->add_icon_item(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")), TTR("Paste Node(s) Here"), ADD_PASTE);
+ break;
+ }
+ }
+ for (Node *node : EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list()) {
+ if (Object::cast_to<CanvasItem>(node)) {
+ add_node_menu->add_icon_item(get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons")), TTR("Move Node(s) Here"), ADD_MOVE);
+ break;
+ }
+ }
+
+ add_node_menu->reset_size();
+ add_node_menu->set_position(viewport->get_screen_transform().xform(b->get_position()));
add_node_menu->popup();
- node_create_position = transform.affine_inverse().xform((get_local_mouse_position()));
+ node_create_position = transform.affine_inverse().xform(b->get_position());
return true;
}
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && tool == TOOL_SELECT && !panner->is_panning()) {
// Single item selection
Point2 click = transform.affine_inverse().xform(b->get_position());
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
if (!scene) {
return true;
}
@@ -2286,7 +2318,6 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
Vector<_SelectResult> selection = Vector<_SelectResult>();
// Retrieve the canvas items
- selection = Vector<_SelectResult>();
_get_canvas_items_at_pos(click, selection);
if (!selection.is_empty()) {
canvas_item = selection[0].item;
@@ -2339,7 +2370,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (selection2.size() > 0) {
drag_type = DRAG_MOVE;
- drag_from = click;
+ drag_from = drag_start_origin;
_save_canvas_item_state(drag_selection);
}
return true;
@@ -2348,9 +2379,9 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
if (drag_type == DRAG_BOX_SELECTION) {
- if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MouseButton::LEFT) {
// Confirms box selection
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
if (scene) {
List<CanvasItem *> selitems;
@@ -2365,7 +2396,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
_find_canvas_items_in_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems);
if (selitems.size() == 1 && editor_selection->get_selected_node_list().is_empty()) {
- editor->push_item(selitems[0]);
+ EditorNode::get_singleton()->push_item(selitems[0]);
}
for (CanvasItem *E : selitems) {
editor_selection->add_node(E);
@@ -2377,7 +2408,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
return true;
}
- if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
// Cancel box selection
drag_type = DRAG_NONE;
viewport->update();
@@ -2392,7 +2423,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
}
- if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_ESCAPE && drag_type == DRAG_NONE && tool == TOOL_SELECT) {
+ if (k.is_valid() && k->is_pressed() && k->get_keycode() == Key::ESCAPE && drag_type == DRAG_NONE && tool == TOOL_SELECT) {
// Unselect everything
editor_selection->clear();
viewport->update();
@@ -2414,7 +2445,7 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
ruler_tool_origin = snap_point(viewport->get_local_mouse_position() / zoom + view_offset);
}
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT) {
if (b->is_pressed()) {
ruler_tool_active = true;
} else {
@@ -2489,31 +2520,34 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
bool accepted = false;
- if (EditorSettings::get_singleton()->get("editors/2d/simple_panning") || !pan_pressed) {
+ Ref<InputEventMouseButton> mb = p_event;
+ bool release_lmb = (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT); // Required to properly release some stuff (e.g. selection box) while panning.
+
+ if (EditorSettings::get_singleton()->get("editors/panning/simple_panning") || !pan_pressed || release_lmb) {
if ((accepted = _gui_input_rulers_and_guides(p_event))) {
- //printf("Rulers and guides\n");
- } else if ((accepted = editor->get_editor_plugins_over()->forward_gui_input(p_event))) {
- //printf("Plugin\n");
+ // print_line("Rulers and guides");
+ } else if ((accepted = EditorNode::get_singleton()->get_editor_plugins_over()->forward_gui_input(p_event))) {
+ // print_line("Plugin");
} else if ((accepted = _gui_input_open_scene_on_double_click(p_event))) {
- //printf("Open scene on double click\n");
+ // print_line("Open scene on double click");
} else if ((accepted = _gui_input_scale(p_event))) {
- //printf("Set scale\n");
+ // print_line("Set scale");
} else if ((accepted = _gui_input_pivot(p_event))) {
- //printf("Set pivot\n");
+ // print_line("Set pivot");
} else if ((accepted = _gui_input_resize(p_event))) {
- //printf("Resize\n");
+ // print_line("Resize");
} else if ((accepted = _gui_input_rotate(p_event))) {
- //printf("Rotate\n");
+ // print_line("Rotate");
} else if ((accepted = _gui_input_move(p_event))) {
- //printf("Move\n");
+ // print_line("Move");
} else if ((accepted = _gui_input_anchors(p_event))) {
- //printf("Anchors\n");
+ // print_line("Anchors");
} else if ((accepted = _gui_input_select(p_event))) {
- //printf("Selection\n");
+ // print_line("Selection");
} else if ((accepted = _gui_input_ruler_tool(p_event))) {
- //printf("Measure\n");
+ // print_line("Measure");
} else {
- //printf("Not accepted\n");
+ // print_line("Not accepted");
}
}
@@ -2530,14 +2564,14 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
_update_cursor();
// Grab focus
- if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) {
+ if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) {
viewport->call_deferred(SNAME("grab_focus"));
}
}
void CanvasItemEditor::_update_cursor() {
// Compute an eventual rotation of the cursor
- CursorShape rotation_array[4] = { CURSOR_HSIZE, CURSOR_BDIAGSIZE, CURSOR_VSIZE, CURSOR_FDIAGSIZE };
+ const CursorShape rotation_array[4] = { CURSOR_HSIZE, CURSOR_BDIAGSIZE, CURSOR_VSIZE, CURSOR_FDIAGSIZE };
int rotation_array_index = 0;
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -2650,7 +2684,7 @@ void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string
p_position += Vector2(-text_size.x / 2, text_size.y + 5);
break;
}
- viewport->draw_string(font, p_position, p_string, HALIGN_LEFT, -1, font_size, color);
+ viewport->draw_string(font, p_position, p_string, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color);
}
void CanvasItemEditor::_draw_margin_at_position(int p_value, Point2 p_position, Side p_side) {
@@ -2710,7 +2744,7 @@ void CanvasItemEditor::_draw_guides() {
Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
Size2 text_size = font->get_string_size(str, font_size);
- viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, HALIGN_LEFT, -1, font_size, text_color, outline_size, outline_color);
+ viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color, outline_size, outline_color);
viewport->draw_line(Point2(dragged_guide_pos.x, 0), Point2(dragged_guide_pos.x, viewport->get_size().y), guide_color, Math::round(EDSCALE));
}
if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_H_GUIDE) {
@@ -2718,7 +2752,7 @@ void CanvasItemEditor::_draw_guides() {
Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
Size2 text_size = font->get_string_size(str, font_size);
- viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, HALIGN_LEFT, -1, font_size, text_color, outline_size, outline_color);
+ viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color, outline_size, outline_color);
viewport->draw_line(Point2(0, dragged_guide_pos.y), Point2(viewport->get_size().x, dragged_guide_pos.y), guide_color, Math::round(EDSCALE));
}
}
@@ -2747,7 +2781,7 @@ void CanvasItemEditor::_draw_rulers() {
// The rule transform
Transform2D ruler_transform = Transform2D();
- if (show_grid || grid_snap_active) {
+ if (grid_snap_active || _is_grid_visible()) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (snap_relative && selection.size() > 0) {
ruler_transform.translate(_get_encompassing_rect_from_list(selection).position);
@@ -2790,7 +2824,7 @@ void CanvasItemEditor::_draw_rulers() {
if (i % (major_subdivision * minor_subdivision) == 0) {
viewport->draw_line(Point2(position.x, 0), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE));
real_t val = (ruler_transform * major_subdivide * minor_subdivide).xform(Point2(i, 0)).x;
- viewport->draw_string(font, Point2(position.x + 2, font->get_height(font_size)), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HALIGN_LEFT, -1, font_size, font_color);
+ viewport->draw_string(font, Point2(position.x + 2, font->get_height(font_size)), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
} else {
if (i % minor_subdivision == 0) {
viewport->draw_line(Point2(position.x, RULER_WIDTH * 0.33), Point2(position.x, RULER_WIDTH), graduation_color, Math::round(EDSCALE));
@@ -2810,7 +2844,7 @@ void CanvasItemEditor::_draw_rulers() {
Transform2D text_xform = Transform2D(-Math_PI / 2.0, Point2(font->get_height(font_size), position.y - 2));
viewport->draw_set_transform_matrix(viewport->get_transform() * text_xform);
- viewport->draw_string(font, Point2(), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HALIGN_LEFT, -1, font_size, font_color);
+ viewport->draw_string(font, Point2(), TS->format_number(vformat(((int)val == val) ? "%d" : "%.1f", val)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
viewport->draw_set_transform_matrix(viewport->get_transform());
} else {
@@ -2827,7 +2861,7 @@ void CanvasItemEditor::_draw_rulers() {
}
void CanvasItemEditor::_draw_grid() {
- if (show_grid || grid_snap_active) {
+ if (_is_grid_visible()) {
// Draw the grid
Vector2 real_grid_offset;
const List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -2913,14 +2947,6 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 corner = Point2(begin.x, end.y);
Vector2 length_vector = (begin - end).abs() / zoom;
- 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));
- if (draw_secondary_lines) {
- viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE));
- viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE));
- }
-
Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
@@ -2936,7 +2962,23 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 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);
text_pos.y = CLAMP(text_pos.y, text_height * 1.5, viewport->get_rect().size.y - text_height * 1.5);
- viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color);
+
+ if (begin.is_equal_approx(end)) {
+ viewport->draw_string(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color);
+ Ref<Texture2D> position_icon = get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons"));
+ viewport->draw_texture(get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons")), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2);
+ return;
+ }
+
+ viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color);
+
+ 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));
+ if (draw_secondary_lines) {
+ viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE));
+ viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE));
+ }
if (draw_secondary_lines) {
const real_t horizontal_angle_rad = length_vector.angle();
@@ -2946,16 +2988,16 @@ 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, TS->format_number(vformat("%.1f px", length_vector.y)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.y)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
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, TS->format_number(vformat(String::utf8("%d°"), vertical_angle)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
+ viewport->draw_string(font, v_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), vertical_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_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, TS->format_number(vformat("%.1f px", length_vector.x)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%.1f px", length_vector.x)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
Point2 h_angle_text_pos = Point2();
h_angle_text_pos.x = CLAMP(end.x - angle_text_width / 2, angle_text_width / 2, viewport->get_rect().size.x - angle_text_width);
@@ -2972,7 +3014,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
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, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
+ viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
// Angle arcs
int arc_point_count = 8;
@@ -3007,17 +3049,17 @@ void CanvasItemEditor::_draw_ruler_tool() {
text_pos.y = CLAMP(text_pos.y, text_height * 2.5, viewport->get_rect().size.y - text_height / 2);
if (draw_secondary_lines) {
- viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color);
+ viewport->draw_string(font, text_pos, TS->format_number(vformat("%.2f " + TTR("units"), (length_vector / grid_step).length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color);
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, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.y / grid_step.y))), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.y / grid_step.y))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_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, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.x / grid_step.x))), HALIGN_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
+ viewport->draw_string(font, text_pos2, TS->format_number(vformat("%d " + TTR("units"), roundf(length_vector.x / grid_step.x))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color, outline_size, outline_color);
} else {
- viewport->draw_string(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), roundf((length_vector / grid_step).length()))), HALIGN_LEFT, -1, font_size, font_color, outline_size, outline_color);
+ viewport->draw_string(font, text_pos, TS->format_number(vformat("%d " + TTR("units"), roundf((length_vector / grid_step).length()))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color, outline_size, outline_color);
}
}
} else {
@@ -3107,7 +3149,6 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
if (dragged_anchor >= 0) {
// Draw the 4 lines when dragged
- bool anchor_snapped;
Color color_snapped = Color(0.64, 0.93, 0.67, 0.5);
Vector2 corners_pos[4];
@@ -3121,7 +3162,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) {
real_t anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i];
line_starts[i] = corners_pos[i].lerp(corners_pos[(i + 1) % 4], anchor_val);
line_ends[i] = corners_pos[(i + 3) % 4].lerp(corners_pos[(i + 2) % 4], anchor_val);
- anchor_snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0;
+ bool anchor_snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0;
viewport->draw_line(line_starts[i], line_ends[i], anchor_snapped ? color_snapped : color_base, (i == dragged_anchor || (i + 3) % 4 == dragged_anchor) ? 2 : 1);
}
@@ -3285,7 +3326,7 @@ void CanvasItemEditor::_draw_selection() {
// Draw the selected items position / surrounding boxes
if (canvas_item->_edit_use_rect()) {
Rect2 rect = canvas_item->_edit_get_rect();
- Vector2 endpoints[4] = {
+ const Vector2 endpoints[4] = {
xform.xform(rect.position),
xform.xform(rect.position + Vector2(rect.size.x, 0)),
xform.xform(rect.position + rect.size),
@@ -3331,7 +3372,7 @@ void CanvasItemEditor::_draw_selection() {
// Draw the resize handles
if (tool == TOOL_SELECT && canvas_item->_edit_use_rect() && _is_node_movable(canvas_item)) {
Rect2 rect = canvas_item->_edit_get_rect();
- Vector2 endpoints[4] = {
+ const Vector2 endpoints[4] = {
xform.xform(rect.position),
xform.xform(rect.position + Vector2(rect.size.x, 0)),
xform.xform(rect.position + rect.size),
@@ -3354,8 +3395,8 @@ void CanvasItemEditor::_draw_selection() {
}
// Draw the move handles
- bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
- bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT);
if (tool == TOOL_MOVE && show_transformation_gizmos) {
if (_is_node_movable(canvas_item)) {
Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
@@ -3364,10 +3405,11 @@ void CanvasItemEditor::_draw_selection() {
Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE);
viewport->draw_set_transform_matrix(simple_xform);
- Vector<Point2> points;
- points.push_back(Vector2(move_factor.x * EDSCALE, 5 * EDSCALE));
- points.push_back(Vector2(move_factor.x * EDSCALE, -5 * EDSCALE));
- points.push_back(Vector2((move_factor.x + 10) * EDSCALE, 0));
+ Vector<Point2> points = {
+ Vector2(move_factor.x * EDSCALE, 5 * EDSCALE),
+ Vector2(move_factor.x * EDSCALE, -5 * EDSCALE),
+ Vector2((move_factor.x + 10) * EDSCALE, 0)
+ };
viewport->draw_colored_polygon(points, get_theme_color(SNAME("axis_x_color"), SNAME("Editor")));
viewport->draw_line(Point2(), Point2(move_factor.x * EDSCALE, 0), get_theme_color(SNAME("axis_x_color"), SNAME("Editor")), Math::round(EDSCALE));
@@ -3391,7 +3433,7 @@ void CanvasItemEditor::_draw_selection() {
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
- bool uniform = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ bool uniform = Input::get_singleton()->is_key_pressed(Key::SHIFT);
Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom;
if (drag_type == DRAG_SCALE_X) {
@@ -3499,7 +3541,7 @@ void CanvasItemEditor::_draw_axis() {
Color area_axis_color = EditorSettings::get_singleton()->get("editors/2d/viewport_border_color");
- Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
Vector2 screen_endpoints[4] = {
transform.xform(Vector2(0, 0)),
@@ -3517,12 +3559,12 @@ void CanvasItemEditor::_draw_axis() {
void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
ERR_FAIL_COND(!p_node);
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) {
return;
}
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- if (canvas_item && !canvas_item->is_visible()) {
+ if (canvas_item && !canvas_item->is_visible_in_tree()) {
return;
}
@@ -3580,19 +3622,19 @@ void CanvasItemEditor::_draw_hover() {
viewport->draw_texture(node_icon, pos, Color(1.0, 1.0, 1.0, 0.5));
// Draw name
- viewport->draw_string(font, pos + Point2(node_icon->get_size().x + 4, item_size.y - 3), node_name, HALIGN_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5));
+ viewport->draw_string(font, pos + Point2(node_icon->get_size().x + 4, item_size.y - 3), node_name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5));
}
}
void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
ERR_FAIL_COND(!p_node);
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) {
return;
}
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- if (canvas_item && !canvas_item->is_visible()) {
+ if (canvas_item && !canvas_item->is_visible_in_tree()) {
return;
}
@@ -3633,8 +3675,8 @@ void CanvasItemEditor::_draw_viewport() {
// Update the transform
transform = Transform2D();
transform.scale_basis(Size2(zoom, zoom));
- transform.elements[2] = -view_offset * zoom;
- editor->get_scene_root()->set_global_canvas_transform(transform);
+ transform.columns[2] = -view_offset * zoom;
+ EditorNode::get_singleton()->get_scene_root()->set_global_canvas_transform(transform);
// hide/show buttons depending on the selection
bool all_locked = true;
@@ -3665,25 +3707,23 @@ void CanvasItemEditor::_draw_viewport() {
group_button->set_disabled(selection.is_empty());
ungroup_button->set_visible(all_group);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-
_draw_grid();
_draw_ruler_tool();
_draw_axis();
- if (editor->get_edited_scene()) {
- _draw_locks_and_groups(editor->get_edited_scene());
- _draw_invisible_nodes_positions(editor->get_edited_scene());
+ if (EditorNode::get_singleton()->get_edited_scene()) {
+ _draw_locks_and_groups(EditorNode::get_singleton()->get_edited_scene());
+ _draw_invisible_nodes_positions(EditorNode::get_singleton()->get_edited_scene());
}
_draw_selection();
RID ci = viewport->get_canvas_item();
RenderingServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D());
- EditorPluginList *over_plugin_list = editor->get_editor_plugins_over();
+ EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over();
if (!over_plugin_list->is_empty()) {
over_plugin_list->forward_canvas_draw_over_viewport(viewport);
}
- EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
+ EditorPluginList *force_over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_force_over();
if (!force_over_plugin_list->is_empty()) {
force_over_plugin_list->forward_canvas_force_draw_over_viewport(viewport);
}
@@ -3708,256 +3748,158 @@ void CanvasItemEditor::set_current_tool(Tool p_tool) {
_button_tool_select(p_tool);
}
-void CanvasItemEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
- EditorNode::get_singleton()->get_scene_root()->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels"));
+void CanvasItemEditor::_update_editor_settings() {
+ select_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
+ list_select_button->set_icon(get_theme_icon(SNAME("ListSelect"), SNAME("EditorIcons")));
+ move_button->set_icon(get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons")));
+ scale_button->set_icon(get_theme_icon(SNAME("ToolScale"), SNAME("EditorIcons")));
+ rotate_button->set_icon(get_theme_icon(SNAME("ToolRotate"), SNAME("EditorIcons")));
+ smart_snap_button->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
+ grid_snap_button->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
+ snap_config_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ skeleton_menu->set_icon(get_theme_icon(SNAME("Bone"), SNAME("EditorIcons")));
+ override_camera_button->set_icon(get_theme_icon(SNAME("Camera2D"), SNAME("EditorIcons")));
+ pan_button->set_icon(get_theme_icon(SNAME("ToolPan"), SNAME("EditorIcons")));
+ ruler_button->set_icon(get_theme_icon(SNAME("Ruler"), SNAME("EditorIcons")));
+ pivot_button->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
+ select_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
+ anchor_handle = get_theme_icon(SNAME("EditorControlAnchor"), SNAME("EditorIcons"));
+ lock_button->set_icon(get_theme_icon(SNAME("Lock"), SNAME("EditorIcons")));
+ unlock_button->set_icon(get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons")));
+ group_button->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
+ ungroup_button->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
+ key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons")));
+ key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons")));
+ key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons")));
+ key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")));
+ key_auto_insert_button->set_icon(get_theme_icon(SNAME("AutoKey"), SNAME("EditorIcons")));
+ // Use a different color for the active autokey icon to make them easier
+ // to distinguish from the other key icons at the top. On a light theme,
+ // the icon will be dark, so we need to lighten it before blending it
+ // with the red color.
+ const Color key_auto_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25);
+ key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55));
+ animation_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
- bool has_container_parents = false;
- int nb_control = 0;
- int nb_having_pivot = 0;
+ _update_context_menu_stylebox();
- // Update the viewport if the canvas_item changes
- List<CanvasItem *> selection = _get_edited_canvas_items(true);
- for (CanvasItem *canvas_item : selection) {
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ pan_speed = int(EditorSettings::get_singleton()->get("editors/panning/2d_editor_pan_speed"));
+ warped_panning = bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning"));
+}
- Rect2 rect;
- if (canvas_item->_edit_use_rect()) {
- rect = canvas_item->_edit_get_rect();
- } else {
- rect = Rect2();
- }
- Transform2D xform = canvas_item->get_transform();
+void CanvasItemEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ EditorNode::get_singleton()->get_scene_root()->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels"));
- if (rect != se->prev_rect || xform != se->prev_xform) {
- viewport->update();
- se->prev_rect = rect;
- se->prev_xform = xform;
- }
+ int nb_having_pivot = 0;
- Control *control = Object::cast_to<Control>(canvas_item);
- if (control) {
- real_t anchors[4];
- Vector2 pivot;
-
- pivot = control->get_pivot_offset();
- anchors[SIDE_LEFT] = control->get_anchor(SIDE_LEFT);
- anchors[SIDE_RIGHT] = control->get_anchor(SIDE_RIGHT);
- anchors[SIDE_TOP] = control->get_anchor(SIDE_TOP);
- anchors[SIDE_BOTTOM] = control->get_anchor(SIDE_BOTTOM);
-
- if (pivot != se->prev_pivot || anchors[SIDE_LEFT] != se->prev_anchors[SIDE_LEFT] || anchors[SIDE_RIGHT] != se->prev_anchors[SIDE_RIGHT] || anchors[SIDE_TOP] != se->prev_anchors[SIDE_TOP] || anchors[SIDE_BOTTOM] != se->prev_anchors[SIDE_BOTTOM]) {
- se->prev_pivot = pivot;
- se->prev_anchors[SIDE_LEFT] = anchors[SIDE_LEFT];
- se->prev_anchors[SIDE_RIGHT] = anchors[SIDE_RIGHT];
- se->prev_anchors[SIDE_TOP] = anchors[SIDE_TOP];
- se->prev_anchors[SIDE_BOTTOM] = anchors[SIDE_BOTTOM];
+ // Update the viewport if the canvas_item changes
+ List<CanvasItem *> selection = _get_edited_canvas_items(true);
+ for (CanvasItem *canvas_item : selection) {
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+
+ Rect2 rect;
+ if (canvas_item->_edit_use_rect()) {
+ rect = canvas_item->_edit_get_rect();
+ } else {
+ rect = Rect2();
+ }
+ Transform2D xform = canvas_item->get_transform();
+
+ if (rect != se->prev_rect || xform != se->prev_xform) {
viewport->update();
+ se->prev_rect = rect;
+ se->prev_xform = xform;
}
- nb_control++;
- if (Object::cast_to<Container>(control->get_parent())) {
- has_container_parents = true;
+ Control *control = Object::cast_to<Control>(canvas_item);
+ if (control) {
+ real_t anchors[4];
+ Vector2 pivot;
+
+ pivot = control->get_pivot_offset();
+ anchors[SIDE_LEFT] = control->get_anchor(SIDE_LEFT);
+ anchors[SIDE_RIGHT] = control->get_anchor(SIDE_RIGHT);
+ anchors[SIDE_TOP] = control->get_anchor(SIDE_TOP);
+ anchors[SIDE_BOTTOM] = control->get_anchor(SIDE_BOTTOM);
+
+ if (pivot != se->prev_pivot || anchors[SIDE_LEFT] != se->prev_anchors[SIDE_LEFT] || anchors[SIDE_RIGHT] != se->prev_anchors[SIDE_RIGHT] || anchors[SIDE_TOP] != se->prev_anchors[SIDE_TOP] || anchors[SIDE_BOTTOM] != se->prev_anchors[SIDE_BOTTOM]) {
+ se->prev_pivot = pivot;
+ se->prev_anchors[SIDE_LEFT] = anchors[SIDE_LEFT];
+ se->prev_anchors[SIDE_RIGHT] = anchors[SIDE_RIGHT];
+ se->prev_anchors[SIDE_TOP] = anchors[SIDE_TOP];
+ se->prev_anchors[SIDE_BOTTOM] = anchors[SIDE_BOTTOM];
+ viewport->update();
+ }
}
- }
- if (canvas_item->_edit_use_pivot()) {
- nb_having_pivot++;
+ if (canvas_item->_edit_use_pivot()) {
+ nb_having_pivot++;
+ }
}
- }
- // Activate / Deactivate the pivot tool
- pivot_button->set_disabled(nb_having_pivot == 0);
+ // Activate / Deactivate the pivot tool
+ pivot_button->set_disabled(nb_having_pivot == 0);
- // Show / Hide the layout and anchors mode buttons
- if (nb_control > 0 && nb_control == selection.size()) {
- presets_menu->set_visible(true);
- anchor_mode_button->set_visible(true);
+ // Update the viewport if bones changes
+ for (KeyValue<BoneKey, BoneList> &E : bone_list) {
+ Object *b = ObjectDB::get_instance(E.key.from);
+ if (!b) {
+ viewport->update();
+ break;
+ }
- // Disable if the selected node is child of a container
- if (has_container_parents) {
- presets_menu->set_disabled(true);
- presets_menu->set_tooltip(TTR("Children of containers have their anchors and margins values overridden by their parent."));
- anchor_mode_button->set_disabled(true);
- anchor_mode_button->set_tooltip(TTR("Children of containers have their anchors and margins values overridden by their parent."));
- } else {
- presets_menu->set_disabled(false);
- presets_menu->set_tooltip(TTR("Presets for the anchors and margins values of a Control node."));
- anchor_mode_button->set_disabled(false);
- anchor_mode_button->set_tooltip(TTR("When active, moving Control nodes changes their anchors instead of their margins."));
- }
- } else {
- presets_menu->set_visible(false);
- anchor_mode_button->set_visible(false);
- }
+ Node2D *b2 = Object::cast_to<Node2D>(b);
+ if (!b2 || !b2->is_inside_tree()) {
+ continue;
+ }
- // Update the viewport if bones changes
- for (KeyValue<BoneKey, BoneList> &E : bone_list) {
- Object *b = ObjectDB::get_instance(E.key.from);
- if (!b) {
- viewport->update();
- break;
+ Transform2D global_xform = b2->get_global_transform();
+
+ if (global_xform != E.value.xform) {
+ E.value.xform = global_xform;
+ viewport->update();
+ }
+
+ Bone2D *bone = Object::cast_to<Bone2D>(b);
+ if (bone && bone->get_length() != E.value.length) {
+ E.value.length = bone->get_length();
+ viewport->update();
+ }
}
+ } break;
- Node2D *b2 = Object::cast_to<Node2D>(b);
- if (!b2 || !b2->is_inside_tree()) {
- continue;
+ case NOTIFICATION_ENTER_TREE: {
+ select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons")));
+ for (int i = 0; i < 4; i++) {
+ select_sb->set_margin_size(Side(i), 4);
+ select_sb->set_default_margin(Side(i), 4);
}
- Transform2D global_xform = b2->get_global_transform();
+ AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
+ _keying_changed();
+ _update_editor_settings();
+ } break;
- if (global_xform != E.value.xform) {
- E.value.xform = global_xform;
- viewport->update();
- }
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons")));
+ _update_editor_settings();
+ } break;
- Bone2D *bone = Object::cast_to<Bone2D>(b);
- if (bone && bone->get_length() != E.value.length) {
- E.value.length = bone->get_length();
- viewport->update();
- }
- }
- }
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible() && override_camera_button->is_pressed()) {
+ EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
- if (p_what == NOTIFICATION_ENTER_TREE) {
- select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons")));
- for (int i = 0; i < 4; i++) {
- select_sb->set_margin_size(Side(i), 4);
- select_sb->set_default_margin(Side(i), 4);
- }
-
- AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
- _keying_changed();
-
- } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons")));
- }
-
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- select_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
- list_select_button->set_icon(get_theme_icon(SNAME("ListSelect"), SNAME("EditorIcons")));
- move_button->set_icon(get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons")));
- scale_button->set_icon(get_theme_icon(SNAME("ToolScale"), SNAME("EditorIcons")));
- rotate_button->set_icon(get_theme_icon(SNAME("ToolRotate"), SNAME("EditorIcons")));
- smart_snap_button->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
- grid_snap_button->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
- snap_config_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
- skeleton_menu->set_icon(get_theme_icon(SNAME("Bone"), SNAME("EditorIcons")));
- override_camera_button->set_icon(get_theme_icon(SNAME("Camera2D"), SNAME("EditorIcons")));
- pan_button->set_icon(get_theme_icon(SNAME("ToolPan"), SNAME("EditorIcons")));
- ruler_button->set_icon(get_theme_icon(SNAME("Ruler"), SNAME("EditorIcons")));
- pivot_button->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
- select_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
- anchor_handle = get_theme_icon(SNAME("EditorControlAnchor"), SNAME("EditorIcons"));
- lock_button->set_icon(get_theme_icon(SNAME("Lock"), SNAME("EditorIcons")));
- unlock_button->set_icon(get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons")));
- group_button->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
- ungroup_button->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
- key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons")));
- key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons")));
- key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons")));
- key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")));
- key_auto_insert_button->set_icon(get_theme_icon(SNAME("AutoKey"), SNAME("EditorIcons")));
- // Use a different color for the active autokey icon to make them easier
- // to distinguish from the other key icons at the top. On a light theme,
- // the icon will be dark, so we need to lighten it before blending it
- // with the red color.
- const Color key_auto_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25);
- key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55));
- animation_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
-
- _update_context_menu_stylebox();
-
- presets_menu->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
-
- PopupMenu *p = presets_menu->get_popup();
-
- p->clear();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")), TTR("Top Left"), ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")), TTR("Top Right"), ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")), TTR("Bottom Right"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")), TTR("Bottom Left"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT);
- p->add_separator();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftCenter"), SNAME("EditorIcons")), TTR("Center Left"), ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopCenter"), SNAME("EditorIcons")), TTR("Center Top"), ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignRightCenter"), SNAME("EditorIcons")), TTR("Center Right"), ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomCenter"), SNAME("EditorIcons")), TTR("Center Bottom"), ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Center"), ANCHORS_AND_OFFSETS_PRESET_CENTER);
- p->add_separator();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")), TTR("Left Wide"), ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")), TTR("Top Wide"), ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")), TTR("Right Wide"), ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")), TTR("Bottom Wide"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlVcenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlHcenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE);
- p->add_separator();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignWide"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_AND_OFFSETS_PRESET_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")), TTR("Keep Ratio"), ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO);
- p->add_separator();
- p->add_submenu_item(TTR("Anchors only"), "Anchors");
- p->set_item_icon(21, get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
-
- anchors_popup->clear();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT);
- anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftCenter"), SNAME("EditorIcons")), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopCenter"), SNAME("EditorIcons")), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignRightCenter"), SNAME("EditorIcons")), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomCenter"), SNAME("EditorIcons")), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Center"), ANCHORS_PRESET_CENTER);
- anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlVcenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlHcenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE);
- anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignWide"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_PRESET_WIDE);
-
- anchor_mode_button->set_icon(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
-
- info_overlay->get_theme()->set_stylebox("normal", "Label", get_theme_stylebox(SNAME("CanvasItemInfoOverlay"), SNAME("EditorStyles")));
- warning_child_of_container->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- warning_child_of_container->add_theme_font_override("font", get_theme_font(SNAME("main"), SNAME("EditorFonts")));
- warning_child_of_container->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("main_size"), SNAME("EditorFonts")));
- }
-
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (!is_visible() && override_camera_button->is_pressed()) {
- EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
-
- debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
- override_camera_button->set_pressed(false);
- }
+ debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
+ override_camera_button->set_pressed(false);
+ }
+ } break;
}
}
void CanvasItemEditor::_selection_changed() {
- // Update the anchors_mode
- int nbValidControls = 0;
- int nbAnchorsMode = 0;
- List<Node *> selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
- if (!control) {
- continue;
- }
- if (Object::cast_to<Container>(control->get_parent())) {
- continue;
- }
-
- nbValidControls++;
- if (control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_")) {
- nbAnchorsMode++;
- }
- }
- anchors_mode = (nbValidControls == nbAnchorsMode);
- anchor_mode_button->set_pressed(anchors_mode);
-
if (!selected_from_canvas) {
drag_type = DRAG_NONE;
}
@@ -3966,7 +3908,7 @@ void CanvasItemEditor::_selection_changed() {
void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
Array selection = editor_selection->get_selected_nodes();
- if (selection.size() != 1 || (Node *)selection[0] != p_canvas_item) {
+ if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) {
drag_type = DRAG_NONE;
// Clear the selection
@@ -3999,13 +3941,13 @@ void CanvasItemEditor::_update_scrollbars() {
Size2 vmin = v_scroll->get_minimum_size();
// Get the visible frame.
- Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));
// Calculate scrollable area.
Rect2 canvas_item_rect = Rect2(Point2(), screen_rect);
- if (editor->is_inside_tree() && editor->get_edited_scene()) {
- Rect2 content_rect = _get_encompassing_rect(editor->get_edited_scene());
+ if (EditorNode::get_singleton()->is_inside_tree() && EditorNode::get_singleton()->get_edited_scene()) {
+ Rect2 content_rect = _get_encompassing_rect(EditorNode::get_singleton()->get_edited_scene());
canvas_item_rect.expand_to(content_rect.position);
canvas_item_rect.expand_to(content_rect.position + content_rect.size);
}
@@ -4079,34 +4021,6 @@ void CanvasItemEditor::_update_scrollbars() {
updating_scroll = false;
}
-void CanvasItemEditor::_popup_warning_depop(Control *p_control) {
- ERR_FAIL_COND(!popup_temporarily_timers.has(p_control));
-
- Timer *timer = popup_temporarily_timers[p_control];
- timer->queue_delete();
- p_control->hide();
- popup_temporarily_timers.erase(p_control);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-}
-
-void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const double p_duration) {
- Timer *timer;
- if (!popup_temporarily_timers.has(p_control)) {
- timer = memnew(Timer);
- timer->connect("timeout", callable_mp(this, &CanvasItemEditor::_popup_warning_depop), varray(p_control));
- timer->set_one_shot(true);
- add_child(timer);
-
- popup_temporarily_timers[p_control] = timer;
- } else {
- timer = popup_temporarily_timers[p_control];
- }
-
- timer->start(p_duration);
- p_control->show();
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-}
-
void CanvasItemEditor::_update_scroll(real_t) {
if (updating_scroll) {
return;
@@ -4117,90 +4031,6 @@ void CanvasItemEditor::_update_scroll(real_t) {
viewport->update();
}
-void CanvasItemEditor::_set_anchors_and_offsets_preset(Control::LayoutPreset p_preset) {
- List<Node *> selection = editor_selection->get_selected_node_list();
-
- undo_redo->create_action(TTR("Change Anchors and Offsets"));
-
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
- if (control) {
- undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
- switch (p_preset) {
- case PRESET_TOP_LEFT:
- case PRESET_TOP_RIGHT:
- case PRESET_BOTTOM_LEFT:
- case PRESET_BOTTOM_RIGHT:
- case PRESET_CENTER_LEFT:
- case PRESET_CENTER_TOP:
- case PRESET_CENTER_RIGHT:
- case PRESET_CENTER_BOTTOM:
- case PRESET_CENTER:
- undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_KEEP_SIZE);
- break;
- case PRESET_LEFT_WIDE:
- case PRESET_TOP_WIDE:
- case PRESET_RIGHT_WIDE:
- case PRESET_BOTTOM_WIDE:
- case PRESET_VCENTER_WIDE:
- case PRESET_HCENTER_WIDE:
- case PRESET_WIDE:
- undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_MINSIZE);
- break;
- }
- undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
- }
- }
-
- undo_redo->commit_action();
-
- anchors_mode = false;
- anchor_mode_button->set_pressed(anchors_mode);
-}
-
-void CanvasItemEditor::_set_anchors_and_offsets_to_keep_ratio() {
- List<Node *> selection = editor_selection->get_selected_node_list();
-
- undo_redo->create_action(TTR("Change Anchors and Offsets"));
-
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
- if (control) {
- Point2 top_left_anchor = _position_to_anchor(control, Point2());
- Point2 bottom_right_anchor = _position_to_anchor(control, control->get_size());
- undo_redo->add_do_method(control, "set_anchor", SIDE_LEFT, top_left_anchor.x, false, true);
- undo_redo->add_do_method(control, "set_anchor", SIDE_RIGHT, bottom_right_anchor.x, false, true);
- undo_redo->add_do_method(control, "set_anchor", SIDE_TOP, top_left_anchor.y, false, true);
- undo_redo->add_do_method(control, "set_anchor", SIDE_BOTTOM, bottom_right_anchor.y, false, true);
- undo_redo->add_do_method(control, "set_meta", "_edit_use_anchors_", true);
-
- bool use_anchors = control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_");
- undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
- undo_redo->add_undo_method(control, "set_meta", "_edit_use_anchors_", use_anchors);
-
- anchors_mode = true;
- anchor_mode_button->set_pressed(anchors_mode);
- }
- }
-
- undo_redo->commit_action();
-}
-
-void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) {
- List<Node *> selection = editor_selection->get_selected_node_list();
-
- undo_redo->create_action(TTR("Change Anchors"));
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
- if (control) {
- undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
- undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
- }
- }
-
- undo_redo->commit_action();
-}
-
void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) {
p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM);
@@ -4234,6 +4064,10 @@ void CanvasItemEditor::_update_zoom(real_t p_zoom) {
_zoom_on_position(p_zoom, viewport_scrollable->get_size() / 2.0);
}
+void CanvasItemEditor::_shortcut_zoom_set(real_t p_zoom) {
+ _zoom_on_position(p_zoom * MAX(1, EDSCALE), viewport->get_local_mouse_position());
+}
+
void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) {
smart_snap_active = p_status;
viewport->update();
@@ -4267,7 +4101,7 @@ void CanvasItemEditor::_button_tool_select(int p_index) {
}
void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) {
- Map<Node *, Object *> &selection = editor_selection->get_selection();
+ const Map<Node *, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
@@ -4343,21 +4177,6 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
}
}
-void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) {
- List<CanvasItem *> selection = _get_edited_canvas_items(false, false);
- for (CanvasItem *E : selection) {
- Control *control = Object::cast_to<Control>(E);
- if (!control || Object::cast_to<Container>(control->get_parent())) {
- continue;
- }
-
- control->set_meta("_edit_use_anchors_", p_status);
- }
-
- anchors_mode = p_status;
- viewport->update();
-}
-
void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
if (p_game_running) {
override_camera_button->set_disabled(false);
@@ -4372,12 +4191,6 @@ void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
void CanvasItemEditor::_popup_callback(int p_op) {
last_option = MenuOption(p_op);
switch (p_op) {
- case SHOW_GRID: {
- show_grid = !show_grid;
- int idx = view_menu->get_popup()->get_item_index(SHOW_GRID);
- view_menu->get_popup()->set_item_checked(idx, show_grid);
- viewport->update();
- } break;
case SHOW_ORIGIN: {
show_origin = !show_origin;
int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN);
@@ -4454,7 +4267,7 @@ 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, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
+ static_cast<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: {
@@ -4509,8 +4322,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
case UNLOCK_SELECTED: {
@@ -4531,8 +4344,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
case GROUP_SELECTED: {
@@ -4553,8 +4366,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
case UNGROUP_SELECTED: {
@@ -4575,110 +4388,10 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(viewport, "update", Variant());
- undo_redo->add_undo_method(viewport, "update", Variant());
+ undo_redo->add_do_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "update");
undo_redo->commit_action();
} break;
- case ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT: {
- _set_anchors_and_offsets_preset(PRESET_TOP_LEFT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT: {
- _set_anchors_and_offsets_preset(PRESET_TOP_RIGHT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT: {
- _set_anchors_and_offsets_preset(PRESET_BOTTOM_LEFT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT: {
- _set_anchors_and_offsets_preset(PRESET_BOTTOM_RIGHT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_LEFT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_RIGHT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_TOP);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_BOTTOM);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER: {
- _set_anchors_and_offsets_preset(PRESET_CENTER);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_TOP_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_LEFT_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_VCENTER_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_HCENTER_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_WIDE: {
- _set_anchors_and_offsets_preset(Control::PRESET_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO: {
- _set_anchors_and_offsets_to_keep_ratio();
- } break;
-
- case ANCHORS_PRESET_TOP_LEFT: {
- _set_anchors_preset(PRESET_TOP_LEFT);
- } break;
- case ANCHORS_PRESET_TOP_RIGHT: {
- _set_anchors_preset(PRESET_TOP_RIGHT);
- } break;
- case ANCHORS_PRESET_BOTTOM_LEFT: {
- _set_anchors_preset(PRESET_BOTTOM_LEFT);
- } break;
- case ANCHORS_PRESET_BOTTOM_RIGHT: {
- _set_anchors_preset(PRESET_BOTTOM_RIGHT);
- } break;
- case ANCHORS_PRESET_CENTER_LEFT: {
- _set_anchors_preset(PRESET_CENTER_LEFT);
- } break;
- case ANCHORS_PRESET_CENTER_RIGHT: {
- _set_anchors_preset(PRESET_CENTER_RIGHT);
- } break;
- case ANCHORS_PRESET_CENTER_TOP: {
- _set_anchors_preset(PRESET_CENTER_TOP);
- } break;
- case ANCHORS_PRESET_CENTER_BOTTOM: {
- _set_anchors_preset(PRESET_CENTER_BOTTOM);
- } break;
- case ANCHORS_PRESET_CENTER: {
- _set_anchors_preset(PRESET_CENTER);
- } break;
- case ANCHORS_PRESET_TOP_WIDE: {
- _set_anchors_preset(PRESET_TOP_WIDE);
- } break;
- case ANCHORS_PRESET_LEFT_WIDE: {
- _set_anchors_preset(PRESET_LEFT_WIDE);
- } break;
- case ANCHORS_PRESET_RIGHT_WIDE: {
- _set_anchors_preset(PRESET_RIGHT_WIDE);
- } break;
- case ANCHORS_PRESET_BOTTOM_WIDE: {
- _set_anchors_preset(PRESET_BOTTOM_WIDE);
- } break;
- case ANCHORS_PRESET_VCENTER_WIDE: {
- _set_anchors_preset(PRESET_VCENTER_WIDE);
- } break;
- case ANCHORS_PRESET_HCENTER_WIDE: {
- _set_anchors_preset(PRESET_HCENTER_WIDE);
- } break;
- case ANCHORS_PRESET_WIDE: {
- _set_anchors_preset(Control::PRESET_WIDE);
- } break;
case ANIM_INSERT_KEY:
case ANIM_INSERT_KEY_EXISTING: {
@@ -4699,7 +4412,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case ANIM_COPY_POSE: {
pose_clipboard.clear();
- Map<Node *, Object *> &selection = editor_selection->get_selection();
+ const Map<Node *, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
@@ -4862,7 +4575,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
Rect2 rect;
int count = 0;
- Map<Node *, Object *> &selection = editor_selection->get_selection();
+ const Map<Node *, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
if (!canvas_item) {
@@ -4899,7 +4612,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
if (p_op == VIEW_CENTER_TO_SELECTION) {
center = rect.get_center();
- Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center);
+ Vector2 offset = viewport->get_size() / 2 - EditorNode::get_singleton()->get_scene_root()->get_global_canvas_transform().xform(center);
view_offset -= (offset / zoom).round();
update_viewport();
@@ -4950,7 +4663,7 @@ Dictionary CanvasItemEditor::get_state() const {
state["snap_node_center"] = snap_node_center;
state["snap_other_nodes"] = snap_other_nodes;
state["snap_guides"] = snap_guides;
- state["show_grid"] = show_grid;
+ state["grid_visibility"] = grid_visibility;
state["show_origin"] = show_origin;
state["show_viewport"] = show_viewport;
state["show_rulers"] = show_rulers;
@@ -5052,10 +4765,8 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
smartsnap_config_popup->set_item_checked(idx, snap_guides);
}
- if (state.has("show_grid")) {
- show_grid = state["show_grid"];
- int idx = view_menu->get_popup()->get_item_index(SHOW_GRID);
- view_menu->get_popup()->set_item_checked(idx, show_grid);
+ if (state.has("grid_visibility")) {
+ grid_visibility = (GridVisibility)(int)(state["grid_visibility"]);
}
if (state.has("show_origin")) {
@@ -5136,31 +4847,32 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
viewport->update();
}
-void CanvasItemEditor::add_control_to_info_overlay(Control *p_control) {
+void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
ERR_FAIL_COND(!p_control);
- p_control->set_h_size_flags(p_control->get_h_size_flags() & ~Control::SIZE_EXPAND_FILL);
- info_overlay->add_child(p_control);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
+ hbc_context_menu->add_child(p_control);
}
-void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) {
- info_overlay->remove_child(p_control);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
+void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) {
+ hbc_context_menu->remove_child(p_control);
}
-void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
- ERR_FAIL_COND(!p_control);
+void CanvasItemEditor::add_control_to_left_panel(Control *p_control) {
+ left_panel_split->add_child(p_control);
+ left_panel_split->move_child(p_control, 0);
+}
- hbc_context_menu->add_child(p_control);
+void CanvasItemEditor::add_control_to_right_panel(Control *p_control) {
+ right_panel_split->add_child(p_control);
+ right_panel_split->move_child(p_control, 1);
}
-void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) {
- hbc_context_menu->remove_child(p_control);
+void CanvasItemEditor::remove_control_from_left_panel(Control *p_control) {
+ left_panel_split->remove_child(p_control);
}
-HSplitContainer *CanvasItemEditor::get_palette_split() {
- return palette_split;
+void CanvasItemEditor::remove_control_from_right_panel(Control *p_control) {
+ right_panel_split->remove_child(p_control);
}
VSplitContainer *CanvasItemEditor::get_bottom_split() {
@@ -5171,77 +4883,25 @@ void CanvasItemEditor::focus_selection() {
_focus_selection(VIEW_CENTER_TO_SELECTION);
}
-CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
- key_pos = true;
- key_rot = true;
- key_scale = false;
-
- show_grid = false;
- show_origin = true;
- show_viewport = true;
- show_helpers = false;
- show_rulers = true;
- show_guides = true;
- show_transformation_gizmos = true;
- show_edit_locks = true;
+CanvasItemEditor::CanvasItemEditor() {
zoom = 1.0 / MAX(1, EDSCALE);
view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH);
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(8, 8); // A power-of-two value works better as a default
- 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 = Math::deg2rad(15.0);
- snap_scale_step = 0.1f;
- smart_snap_active = false;
- grid_snap_active = false;
- snap_node_parent = true;
- snap_node_anchors = true;
- snap_node_sides = true;
- snap_node_center = true;
- snap_other_nodes = true;
- snap_guides = true;
- snap_rotation = false;
- snap_scale = false;
- snap_relative = false;
- // Enable pixel snapping even if pixel snap rendering is disabled in the Project Settings.
- // This results in crisper visuals by preventing 2D nodes from being placed at subpixel coordinates.
- snap_pixel = true;
+
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
- selected_from_canvas = false;
- anchors_mode = false;
-
- drag_type = DRAG_NONE;
- drag_from = Vector2();
- drag_to = Vector2();
- dragged_guide_pos = Point2();
- dragged_guide_index = -1;
- is_hovering_h_guide = false;
- is_hovering_v_guide = false;
- panning = false;
- pan_pressed = false;
-
- ruler_tool_active = false;
- ruler_tool_origin = Point2();
-
- bone_last_frame = 0;
-
- tool = TOOL_SELECT;
- undo_redo = p_editor->get_undo_redo();
- editor = p_editor;
- editor_selection = p_editor->get_editor_selection();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ editor_selection = EditorNode::get_singleton()->get_editor_selection();
editor_selection->add_editor_plugin(this);
editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed));
- editor->get_scene_tree_dock()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
- editor->get_scene_tree_dock()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
+ SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
+ SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
- editor->call_deferred(SNAME("connect"), "play_pressed", Callable(this, "_update_override_camera_button"), make_binds(true));
- editor->call_deferred(SNAME("connect"), "stop_pressed", Callable(this, "_update_override_camera_button"), make_binds(false));
+ EditorNode::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", Callable(this, "_update_override_camera_button"), make_binds(true));
+ EditorNode::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", Callable(this, "_update_override_camera_button"), make_binds(false));
hb = memnew(HBoxContainer);
add_child(hb);
@@ -5251,12 +4911,16 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
add_child(bottom_split);
bottom_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- palette_split = memnew(HSplitContainer);
- bottom_split->add_child(palette_split);
- palette_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ left_panel_split = memnew(HSplitContainer);
+ bottom_split->add_child(left_panel_split);
+ left_panel_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ right_panel_split = memnew(HSplitContainer);
+ left_panel_split->add_child(right_panel_split);
+ right_panel_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
viewport_scrollable = memnew(Control);
- palette_split->add_child(viewport_scrollable);
+ right_panel_split->add_child(viewport_scrollable);
viewport_scrollable->set_mouse_filter(MOUSE_FILTER_PASS);
viewport_scrollable->set_clip_contents(true);
viewport_scrollable->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -5267,12 +4931,20 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport_scrollable->add_child(scene_tree);
scene_tree->set_stretch(true);
scene_tree->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
- scene_tree->add_child(p_editor->get_scene_root());
+ scene_tree->add_child(EditorNode::get_singleton()->get_scene_root());
controls_vb = memnew(VBoxContainer);
controls_vb->set_begin(Point2(5, 5));
- viewport = memnew(CanvasItemEditorViewport(p_editor, this));
+ zoom_widget = memnew(EditorZoomWidget);
+ controls_vb->add_child(zoom_widget);
+ zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
+ zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom));
+
+ panner.instantiate();
+ panner->set_callbacks(callable_mp(this, &CanvasItemEditor::_scroll_callback), callable_mp(this, &CanvasItemEditor::_pan_callback), callable_mp(this, &CanvasItemEditor::_zoom_callback));
+
+ viewport = memnew(CanvasItemEditorViewport(this));
viewport_scrollable->add_child(viewport);
viewport->set_mouse_filter(MOUSE_FILTER_PASS);
viewport->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
@@ -5280,23 +4952,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->set_focus_mode(FOCUS_ALL);
viewport->connect("draw", callable_mp(this, &CanvasItemEditor::_draw_viewport));
viewport->connect("gui_input", callable_mp(this, &CanvasItemEditor::_gui_input_viewport));
-
- info_overlay = memnew(VBoxContainer);
- info_overlay->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_LEFT);
- info_overlay->set_offset(SIDE_LEFT, 10);
- info_overlay->set_offset(SIDE_BOTTOM, -15);
- info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN);
- info_overlay->add_theme_constant_override("separation", 10);
- viewport_scrollable->add_child(info_overlay);
-
- // Make sure all labels inside of the container are styled the same.
- Theme *info_overlay_theme = memnew(Theme);
- info_overlay->set_theme(info_overlay_theme);
-
- warning_child_of_container = memnew(Label);
- warning_child_of_container->hide();
- warning_child_of_container->set_text(TTR("Warning: Children of a container get their position and size determined only by their parent."));
- add_control_to_info_overlay(warning_child_of_container);
+ viewport->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key));
h_scroll = memnew(HScrollBar);
viewport->add_child(h_scroll);
@@ -5310,13 +4966,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->add_child(controls_vb);
- zoom_widget = memnew(EditorZoomWidget);
- controls_vb->add_child(zoom_widget);
- zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
- zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom));
-
- updating_scroll = false;
-
// Add some margin to the left for better aesthetics.
// This prevents the first button's hover/pressed effect from "touching" the panel's border,
// which looks ugly.
@@ -5330,9 +4979,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
select_button->set_toggle_mode(true);
select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SELECT));
select_button->set_pressed(true);
- select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), KEY_Q));
+ select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), Key::Q));
select_button->set_shortcut_context(this);
- select_button->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("RMB: Add node at position clicked."));
+ select_button->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Alt+Drag: Scale selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("RMB: Add node at position clicked."));
hb->add_child(memnew(VSeparator));
@@ -5341,7 +4990,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(move_button);
move_button->set_toggle_mode(true);
move_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_MOVE));
- move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), KEY_W));
+ move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), Key::W));
move_button->set_shortcut_context(this);
move_button->set_tooltip(TTR("Move Mode"));
@@ -5350,7 +4999,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(rotate_button);
rotate_button->set_toggle_mode(true);
rotate_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_ROTATE));
- rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), KEY_E));
+ rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), Key::E));
rotate_button->set_shortcut_context(this);
rotate_button->set_tooltip(TTR("Rotate Mode"));
@@ -5359,9 +5008,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(scale_button);
scale_button->set_toggle_mode(true);
scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SCALE));
- scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), KEY_S));
+ scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), Key::S));
scale_button->set_shortcut_context(this);
- scale_button->set_tooltip(TTR("Scale Mode"));
+ scale_button->set_tooltip(TTR("Shift: Scale proportionally."));
hb->add_child(memnew(VSeparator));
@@ -5384,7 +5033,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(pan_button);
pan_button->set_toggle_mode(true);
pan_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_PAN));
- pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), KEY_G));
+ pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), Key::G));
pan_button->set_shortcut_context(this);
pan_button->set_tooltip(TTR("You can also use Pan View shortcut (Space by default) to pan in any mode."));
@@ -5393,7 +5042,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(ruler_button);
ruler_button->set_toggle_mode(true);
ruler_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_RULER));
- ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), KEY_R));
+ ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), Key::R));
ruler_button->set_shortcut_context(this);
ruler_button->set_tooltip(TTR("Ruler Mode"));
@@ -5405,7 +5054,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
smart_snap_button->set_toggle_mode(true);
smart_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_smart_snap));
smart_snap_button->set_tooltip(TTR("Toggle smart snapping."));
- smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KEY_MASK_SHIFT | KEY_S));
+ smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KeyModifierMask::SHIFT | Key::S));
smart_snap_button->set_shortcut_context(this);
grid_snap_button = memnew(Button);
@@ -5414,7 +5063,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
grid_snap_button->set_toggle_mode(true);
grid_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_grid_snap));
grid_snap_button->set_tooltip(TTR("Toggle grid snapping."));
- grid_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_grid_snap", TTR("Use Grid Snap"), KEY_MASK_SHIFT | KEY_G));
+ grid_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_grid_snap", TTR("Use Grid Snap"), KeyModifierMask::SHIFT | Key::G));
grid_snap_button->set_shortcut_context(this);
snap_config_menu = memnew(MenuButton);
@@ -5457,7 +5106,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(LOCK_SELECTED));
lock_button->set_tooltip(TTR("Lock selected node, preventing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KEY_MASK_CMD | KEY_L));
+ lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD | Key::L));
unlock_button = memnew(Button);
unlock_button->set_flat(true);
@@ -5465,7 +5114,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNLOCK_SELECTED));
unlock_button->set_tooltip(TTR("Unlock selected node, allowing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_L));
+ unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L));
group_button = memnew(Button);
group_button->set_flat(true);
@@ -5473,7 +5122,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(GROUP_SELECTED));
group_button->set_tooltip(TTR("Makes sure the object's children are not selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KEY_MASK_CMD | KEY_G));
+ group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G));
ungroup_button = memnew(Button);
ungroup_button->set_flat(true);
@@ -5481,7 +5130,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNGROUP_SELECTED));
ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G));
+ ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
hb->add_child(memnew(VSeparator));
@@ -5495,7 +5144,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->set_hide_on_checkable_item_selection(false);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bone2D Node(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bone2D Node(s) from Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::B), SKELETON_MAKE_BONES);
p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
hb->add_child(memnew(VSeparator));
@@ -5519,21 +5168,33 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p = view_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Always Show Grid"), KEY_NUMBERSIGN), SHOW_GRID);
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS);
+
+ grid_menu = memnew(PopupMenu);
+ grid_menu->connect("about_to_popup", callable_mp(this, &CanvasItemEditor::_prepare_grid_menu));
+ grid_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_on_grid_menu_id_pressed));
+ grid_menu->set_name("GridMenu");
+ grid_menu->add_radio_check_item(TTR("Show"), GRID_VISIBILITY_SHOW);
+ grid_menu->add_radio_check_item(TTR("Show When Snapping"), GRID_VISIBILITY_SHOW_WHEN_SNAPPING);
+ grid_menu->add_radio_check_item(TTR("Hide"), GRID_VISIBILITY_HIDE);
+ grid_menu->add_separator();
+ grid_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/toggle_grid", TTR("Toggle Grid"), KeyModifierMask::CMD | Key::APOSTROPHE));
+ p->add_child(grid_menu);
+ p->add_submenu_item(TTR("Grid"), "GridMenu");
+
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), Key::H), SHOW_HELPERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers")), SHOW_RULERS);
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), KEY_Y), SHOW_GUIDES);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), Key::Y), SHOW_GUIDES);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_origin", TTR("Show Origin")), SHOW_ORIGIN);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_viewport", TTR("Show Viewport")), SHOW_VIEWPORT);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_edit_locks", TTR("Show Group And Lock Icons")), SHOW_EDIT_LOCKS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_transformation_gizmos", TTR("Show Transformation Gizmos")), SHOW_TRANSFORMATION_GIZMOS);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION);
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), Key::F), VIEW_CENTER_TO_SELECTION);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KeyModifierMask::SHIFT | Key::F), VIEW_FRAME_TO_SELECTION);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/clear_guides", TTR("Clear Guides")), CLEAR_GUIDES);
p->add_separator();
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::P), PREVIEW_CANVAS_SCALE);
hb->add_child(memnew(VSeparator));
@@ -5546,28 +5207,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(context_menu_container);
_update_context_menu_stylebox();
- presets_menu = memnew(MenuButton);
- presets_menu->set_shortcut_context(this);
- presets_menu->set_text(TTR("Layout"));
- hbc_context_menu->add_child(presets_menu);
- presets_menu->hide();
- presets_menu->set_switch_on_hover(true);
-
- p = presets_menu->get_popup();
- p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
-
- anchors_popup = memnew(PopupMenu);
- p->add_child(anchors_popup);
- anchors_popup->set_name("Anchors");
- anchors_popup->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
-
- anchor_mode_button = memnew(Button);
- anchor_mode_button->set_flat(true);
- hbc_context_menu->add_child(anchor_mode_button);
- anchor_mode_button->set_toggle_mode(true);
- anchor_mode_button->hide();
- anchor_mode_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_anchor_mode));
-
+ // Animation controls.
animation_hb = memnew(HBoxContainer);
hbc_context_menu->add_child(animation_hb);
animation_hb->add_child(memnew(VSeparator));
@@ -5604,7 +5244,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_KEY));
key_insert_button->set_tooltip(TTR("Insert keys (based on mask)."));
- key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), KEY_INSERT));
+ key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), Key::INSERT));
key_insert_button->set_shortcut_context(this);
animation_hb->add_child(key_insert_button);
@@ -5627,11 +5267,11 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p = animation_menu->get_popup();
p->add_shortcut(ED_GET_SHORTCUT("canvas_item_editor/anim_insert_key"), ANIM_INSERT_KEY);
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key_existing_tracks", TTR("Insert Key (Existing Tracks)"), KEY_MASK_CMD + KEY_INSERT), ANIM_INSERT_KEY_EXISTING);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key_existing_tracks", TTR("Insert Key (Existing Tracks)"), KeyModifierMask::CMD + Key::INSERT), ANIM_INSERT_KEY_EXISTING);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_copy_pose", TTR("Copy Pose")), ANIM_COPY_POSE);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_paste_pose", TTR("Paste Pose")), ANIM_PASTE_POSE);
- p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_clear_pose", TTR("Clear Pose"), KEY_MASK_SHIFT | KEY_K), ANIM_CLEAR_POSE);
+ p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_clear_pose", TTR("Clear Pose"), KeyModifierMask::SHIFT | Key::K), ANIM_CLEAR_POSE);
snap_dialog = memnew(SnapDialog);
snap_dialog->connect("confirmed", callable_mp(this, &CanvasItemEditor::_snap_changed));
@@ -5647,33 +5287,32 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
add_node_menu = memnew(PopupMenu);
add_child(add_node_menu);
- add_node_menu->add_icon_item(editor->get_scene_tree_dock()->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), TTR("Add Node Here"));
- add_node_menu->add_icon_item(editor->get_scene_tree_dock()->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), TTR("Instance Scene Here"));
add_node_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_add_node_pressed));
- multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), KEY_KP_MULTIPLY);
- divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), KEY_KP_DIVIDE);
- pan_view_shortcut = ED_SHORTCUT("canvas_item_editor/pan_view", TTR("Pan View"), KEY_SPACE);
+ multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), Key::KP_MULTIPLY);
+ divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), Key::KP_DIVIDE);
skeleton_menu->get_popup()->set_item_checked(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES), true);
+
+ // Store the singleton instance.
singleton = this;
// To ensure that scripts can parse the list of shortcuts correctly, we have to define
// those shortcuts one by one.
// Resetting zoom to 100% is a duplicate shortcut of `canvas_item_editor/reset_zoom`,
// but it ensures both 1 and Ctrl + 0 can be used to reset zoom.
- ED_SHORTCUT("canvas_item_editor/zoom_3.125_percent", TTR("Zoom to 3.125%"), KEY_MASK_SHIFT | KEY_5);
- ED_SHORTCUT("canvas_item_editor/zoom_6.25_percent", TTR("Zoom to 6.25%"), KEY_MASK_SHIFT | KEY_4);
- ED_SHORTCUT("canvas_item_editor/zoom_12.5_percent", TTR("Zoom to 12.5%"), KEY_MASK_SHIFT | KEY_3);
- ED_SHORTCUT("canvas_item_editor/zoom_25_percent", TTR("Zoom to 25%"), KEY_MASK_SHIFT | KEY_2);
- ED_SHORTCUT("canvas_item_editor/zoom_50_percent", TTR("Zoom to 50%"), KEY_MASK_SHIFT | KEY_1);
- ED_SHORTCUT("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"), KEY_1);
- ED_SHORTCUT("canvas_item_editor/zoom_200_percent", TTR("Zoom to 200%"), KEY_2);
- ED_SHORTCUT("canvas_item_editor/zoom_400_percent", TTR("Zoom to 400%"), KEY_3);
- ED_SHORTCUT("canvas_item_editor/zoom_800_percent", TTR("Zoom to 800%"), KEY_4);
- ED_SHORTCUT("canvas_item_editor/zoom_1600_percent", TTR("Zoom to 1600%"), KEY_5);
-
- set_process_unhandled_key_input(true);
+ ED_SHORTCUT("canvas_item_editor/zoom_3.125_percent", TTR("Zoom to 3.125%"), KeyModifierMask::SHIFT | Key::KEY_5);
+ ED_SHORTCUT("canvas_item_editor/zoom_6.25_percent", TTR("Zoom to 6.25%"), KeyModifierMask::SHIFT | Key::KEY_4);
+ ED_SHORTCUT("canvas_item_editor/zoom_12.5_percent", TTR("Zoom to 12.5%"), KeyModifierMask::SHIFT | Key::KEY_3);
+ ED_SHORTCUT("canvas_item_editor/zoom_25_percent", TTR("Zoom to 25%"), KeyModifierMask::SHIFT | Key::KEY_2);
+ ED_SHORTCUT("canvas_item_editor/zoom_50_percent", TTR("Zoom to 50%"), KeyModifierMask::SHIFT | Key::KEY_1);
+ ED_SHORTCUT("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"), Key::KEY_1);
+ ED_SHORTCUT("canvas_item_editor/zoom_200_percent", TTR("Zoom to 200%"), Key::KEY_2);
+ ED_SHORTCUT("canvas_item_editor/zoom_400_percent", TTR("Zoom to 400%"), Key::KEY_3);
+ ED_SHORTCUT("canvas_item_editor/zoom_800_percent", TTR("Zoom to 800%"), Key::KEY_4);
+ ED_SHORTCUT("canvas_item_editor/zoom_1600_percent", TTR("Zoom to 1600%"), Key::KEY_5);
+
+ set_process_shortcut_input(true);
// Update the menus' checkboxes
call_deferred(SNAME("set_state"), get_state());
@@ -5694,12 +5333,12 @@ void CanvasItemEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
canvas_item_editor->show();
canvas_item_editor->set_physics_process(true);
- RenderingServer::get_singleton()->viewport_set_disable_2d(editor->get_scene_root()->get_viewport_rid(), false);
+ RenderingServer::get_singleton()->viewport_set_disable_2d(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), false);
} else {
canvas_item_editor->hide();
canvas_item_editor->set_physics_process(false);
- RenderingServer::get_singleton()->viewport_set_disable_2d(editor->get_scene_root()->get_viewport_rid(), true);
+ RenderingServer::get_singleton()->viewport_set_disable_2d(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), true);
}
}
@@ -5711,11 +5350,10 @@ void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) {
canvas_item_editor->set_state(p_state);
}
-CanvasItemEditorPlugin::CanvasItemEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- canvas_item_editor = memnew(CanvasItemEditor(editor));
+CanvasItemEditorPlugin::CanvasItemEditorPlugin() {
+ canvas_item_editor = memnew(CanvasItemEditor);
canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- editor->get_main_control()->add_child(canvas_item_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(canvas_item_editor);
canvas_item_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
canvas_item_editor->hide();
}
@@ -5755,7 +5393,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
bool add_preview = false;
for (int i = 0; i < files.size(); i++) {
String path = files[i];
- RES res = ResourceLoader::load(path);
+ Ref<Resource> res = ResourceLoader::load(path);
ERR_FAIL_COND(res.is_null());
Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
@@ -5783,7 +5421,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
}
if (add_preview) {
- editor->get_scene_root()->add_child(preview_node);
+ EditorNode::get_singleton()->get_scene_root()->add_child(preview_node);
}
}
@@ -5794,7 +5432,7 @@ void CanvasItemEditorViewport::_remove_preview() {
node->queue_delete();
preview_node->remove_child(node);
}
- editor->get_scene_root()->remove_child(preview_node);
+ EditorNode::get_singleton()->get_scene_root()->remove_child(preview_node);
label->hide();
label_desc->hide();
@@ -5837,45 +5475,41 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
if (parent) {
editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true);
- editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
editor_data->get_undo_redo().add_do_reference(child);
editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child);
} else { // If no parent is selected, set as root node of the scene.
- editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child);
- editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
+ editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
}
if (parent) {
String new_name = parent->validate_child_name(child);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
+ editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
}
- String node_class = child->get_class();
- if (node_class == "Polygon2D") {
- editor_data->get_undo_redo().add_do_property(child, "texture/texture", texture);
- } else if (node_class == "TouchScreenButton") {
- editor_data->get_undo_redo().add_do_property(child, "normal", texture);
- } else if (node_class == "TextureButton") {
- editor_data->get_undo_redo().add_do_property(child, "texture_button", texture);
+ if (Object::cast_to<TouchScreenButton>(child) || Object::cast_to<TextureButton>(child)) {
+ editor_data->get_undo_redo().add_do_property(child, "texture_normal", texture);
} else {
editor_data->get_undo_redo().add_do_property(child, "texture", texture);
}
// make visible for certain node type
- if (ClassDB::is_parent_class(node_class, "Control")) {
+ if (Object::cast_to<Control>(child)) {
Size2 texture_size = texture->get_size();
editor_data->get_undo_redo().add_do_property(child, "rect_size", texture_size);
- } else if (node_class == "Polygon2D") {
+ } else if (Object::cast_to<Polygon2D>(child)) {
Size2 texture_size = texture->get_size();
- Vector<Vector2> list;
- list.push_back(Vector2(0, 0));
- list.push_back(Vector2(texture_size.width, 0));
- list.push_back(Vector2(texture_size.width, texture_size.height));
- list.push_back(Vector2(0, texture_size.height));
+ Vector<Vector2> list = {
+ Vector2(0, 0),
+ Vector2(texture_size.width, 0),
+ Vector2(texture_size.width, texture_size.height),
+ Vector2(0, texture_size.height)
+ };
editor_data->get_undo_redo().add_do_property(child, "polygon", list);
}
@@ -5899,8 +5533,10 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
return false;
}
- if (editor->get_edited_scene()->get_scene_file_path() != "") { // cyclical instancing
- if (_cyclical_dependency_exists(editor->get_edited_scene()->get_scene_file_path(), instantiated_scene)) {
+ Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
+
+ if (!edited_scene->get_scene_file_path().is_empty()) { // cyclical instancing
+ if (_cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) {
memdelete(instantiated_scene);
return false;
}
@@ -5908,26 +5544,28 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene);
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true);
+ editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene);
editor_data->get_undo_redo().add_do_reference(instantiated_scene);
editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
String new_name = parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name);
+ editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name));
- CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
- if (parent_ci) {
+ CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene);
+ if (instance_ci) {
Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point);
target_pos = canvas_item_editor->snap_point(target_pos);
- target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
- // Preserve instance position of the original scene.
- CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene);
- if (instance_ci) {
- target_pos += instance_ci->_edit_get_position();
+
+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
+ if (parent_ci) {
+ target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
}
+ // Preserve instance position of the original scene.
+ target_pos += instance_ci->_edit_get_position();
+
editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_position", target_pos);
}
@@ -5950,7 +5588,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
for (int i = 0; i < selected_files.size(); i++) {
String path = selected_files[i];
- RES res = ResourceLoader::load(path);
+ Ref<Resource> res = ResourceLoader::load(path);
if (res.is_null()) {
continue;
}
@@ -5996,29 +5634,30 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
if (String(d["type"]) == "files") {
Vector<String> files = d["files"];
bool can_instantiate = false;
- for (int i = 0; i < files.size(); i++) { // check if dragged files contain resource or scene can be created at least once
- RES res = ResourceLoader::load(files[i]);
- if (res.is_null()) {
- continue;
- }
- String type = res->get_class();
- if (type == "PackedScene") {
- Ref<PackedScene> sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
- if (!instantiated_scene) {
+
+ List<String> scene_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
+ List<String> texture_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("Texture2D", &texture_extensions);
+
+ for (int i = 0; i < files.size(); i++) {
+ // Check if dragged files with texture or scene extension can be created at least once.
+ if (texture_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
+ Ref<Resource> res = ResourceLoader::load(files[i]);
+ if (res.is_null()) {
continue;
}
- memdelete(instantiated_scene);
- } else if (ClassDB::is_parent_class(type, "Texture2D")) {
- Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
- if (!texture.is_valid()) {
- continue;
+ Ref<PackedScene> scn = res;
+ if (scn.is_valid()) {
+ Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ if (!instantiated_scene) {
+ continue;
+ }
+ memdelete(instantiated_scene);
}
- } else {
- continue;
+ can_instantiate = true;
+ break;
}
- can_instantiate = true;
- break;
}
if (can_instantiate) {
if (!preview_node->get_parent()) { // create preview only once
@@ -6059,9 +5698,9 @@ bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
}
void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
- bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
- bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
+ bool is_shift = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT);
selected_files.clear();
Dictionary d = p_data;
@@ -6072,8 +5711,8 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
return;
}
- List<Node *> selected_nodes = editor->get_editor_selection()->get_selected_node_list();
- Node *root_node = editor->get_edited_scene();
+ List<Node *> selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list();
+ Node *root_node = EditorNode::get_singleton()->get_edited_scene();
if (selected_nodes.size() > 0) {
Node *selected_node = selected_nodes[0];
target_node = root_node;
@@ -6086,7 +5725,6 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
if (root_node) {
target_node = root_node;
} else {
- drop_pos = p_point;
target_node = nullptr;
}
}
@@ -6124,25 +5762,39 @@ Node *CanvasItemEditorViewport::_make_texture_node_type(String texture_node_type
return node;
}
+void CanvasItemEditorViewport::_update_theme() {
+ List<BaseButton *> btn_list;
+ button_group->get_buttons(&btn_list);
+
+ for (int i = 0; i < btn_list.size(); i++) {
+ CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]);
+ check->set_icon(get_theme_icon(check->get_text(), SNAME("EditorIcons")));
+ }
+
+ label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+}
+
void CanvasItemEditorViewport::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ _update_theme();
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
+ _update_theme();
connect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit));
- label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
} break;
+
case NOTIFICATION_EXIT_TREE: {
disconnect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit));
} break;
-
- default:
- break;
}
}
void CanvasItemEditorViewport::_bind_methods() {
}
-CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasItemEditor *p_canvas_item_editor) {
+CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_item_editor) {
default_texture_node_type = "Sprite2D";
// Node2D
texture_node_types.push_back("Sprite2D");
@@ -6157,16 +5809,15 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
texture_node_types.push_back("NinePatchRect");
target_node = nullptr;
- editor = p_node;
- editor_data = editor->get_scene_tree_dock()->get_editor_data();
+ editor_data = SceneTreeDock::get_singleton()->get_editor_data();
canvas_item_editor = p_canvas_item_editor;
preview_node = memnew(Control);
accept = memnew(AcceptDialog);
- editor->get_gui_base()->add_child(accept);
+ EditorNode::get_singleton()->get_gui_base()->add_child(accept);
selector = memnew(AcceptDialog);
- editor->get_gui_base()->add_child(selector);
+ EditorNode::get_singleton()->get_gui_base()->add_child(selector);
selector->set_title(TTR("Change Default Type"));
selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
selector->connect("cancelled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
@@ -6179,7 +5830,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
btn_group = memnew(VBoxContainer);
vbc->add_child(btn_group);
- btn_group->set_h_size_flags(0);
+ btn_group->set_h_size_flags(SIZE_EXPAND_FILL);
button_group.instantiate();
for (int i = 0; i < texture_node_types.size(); i++) {
@@ -6192,14 +5843,14 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
label = memnew(Label);
label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1));
- label->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE);
+ label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE);
label->hide();
canvas_item_editor->get_controls_container()->add_child(label);
label_desc = memnew(Label);
label_desc->add_theme_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1));
label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1));
- label_desc->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE);
+ label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE);
label_desc->add_theme_constant_override("line_spacing", 0);
label_desc->hide();
canvas_item_editor->get_controls_container()->add_child(label_desc);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 286771ee08..7a49041131 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,10 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef CONTROL_EDITOR_PLUGIN_H
-#define CONTROL_EDITOR_PLUGIN_H
+#ifndef CANVAS_ITEM_EDITOR_PLUGIN_H
+#define CANVAS_ITEM_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_zoom_widget.h"
#include "scene/gui/box_container.h"
@@ -39,9 +38,13 @@
#include "scene/gui/label.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/spin_box.h"
+#include "scene/gui/split_container.h"
+#include "scene/gui/texture_rect.h"
#include "scene/main/canvas_item.h"
+class EditorData;
class CanvasItemEditorViewport;
+class ViewPanner;
class CanvasItemEditorSelectedItem : public Object {
GDCLASS(CanvasItemEditorSelectedItem, Object);
@@ -83,11 +86,11 @@ public:
enum AddNodeOption {
ADD_NODE,
ADD_INSTANCE,
+ ADD_PASTE,
+ ADD_MOVE,
};
private:
- EditorNode *editor;
-
enum SnapTarget {
SNAP_TARGET_NONE = 0,
SNAP_TARGET_PARENT,
@@ -113,7 +116,6 @@ private:
SNAP_RELATIVE,
SNAP_CONFIGURE,
SNAP_USE_PIXEL,
- SHOW_GRID,
SHOW_HELPERS,
SHOW_RULERS,
SHOW_GUIDES,
@@ -125,55 +127,6 @@ private:
UNLOCK_SELECTED,
GROUP_SELECTED,
UNGROUP_SELECTED,
- ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT,
- ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT,
- ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT,
- ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM,
- ANCHORS_AND_OFFSETS_PRESET_CENTER,
- ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO,
- ANCHORS_PRESET_TOP_LEFT,
- ANCHORS_PRESET_TOP_RIGHT,
- ANCHORS_PRESET_BOTTOM_LEFT,
- ANCHORS_PRESET_BOTTOM_RIGHT,
- ANCHORS_PRESET_CENTER_LEFT,
- ANCHORS_PRESET_CENTER_RIGHT,
- ANCHORS_PRESET_CENTER_TOP,
- ANCHORS_PRESET_CENTER_BOTTOM,
- ANCHORS_PRESET_CENTER,
- ANCHORS_PRESET_TOP_WIDE,
- ANCHORS_PRESET_LEFT_WIDE,
- ANCHORS_PRESET_RIGHT_WIDE,
- ANCHORS_PRESET_BOTTOM_WIDE,
- ANCHORS_PRESET_VCENTER_WIDE,
- ANCHORS_PRESET_HCENTER_WIDE,
- ANCHORS_PRESET_WIDE,
- OFFSETS_PRESET_TOP_LEFT,
- OFFSETS_PRESET_TOP_RIGHT,
- OFFSETS_PRESET_BOTTOM_LEFT,
- OFFSETS_PRESET_BOTTOM_RIGHT,
- OFFSETS_PRESET_CENTER_LEFT,
- OFFSETS_PRESET_CENTER_RIGHT,
- OFFSETS_PRESET_CENTER_TOP,
- OFFSETS_PRESET_CENTER_BOTTOM,
- OFFSETS_PRESET_CENTER,
- OFFSETS_PRESET_TOP_WIDE,
- OFFSETS_PRESET_LEFT_WIDE,
- OFFSETS_PRESET_RIGHT_WIDE,
- OFFSETS_PRESET_BOTTOM_WIDE,
- OFFSETS_PRESET_VCENTER_WIDE,
- OFFSETS_PRESET_HCENTER_WIDE,
- OFFSETS_PRESET_WIDE,
ANIM_INSERT_KEY,
ANIM_INSERT_KEY_EXISTING,
ANIM_INSERT_POS,
@@ -221,70 +174,73 @@ private:
DRAG_KEY_MOVE
};
- bool selection_menu_additive_selection;
+ enum GridVisibility {
+ GRID_VISIBILITY_SHOW,
+ GRID_VISIBILITY_SHOW_WHEN_SNAPPING,
+ GRID_VISIBILITY_HIDE,
+ };
+
+ bool selection_menu_additive_selection = false;
- Tool tool;
- Control *viewport;
- Control *viewport_scrollable;
+ Tool tool = TOOL_SELECT;
+ Control *viewport = nullptr;
+ Control *viewport_scrollable = nullptr;
- HScrollBar *h_scroll;
- VScrollBar *v_scroll;
- HBoxContainer *hb;
+ HScrollBar *h_scroll = nullptr;
+ VScrollBar *v_scroll = nullptr;
+ HBoxContainer *hb = nullptr;
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
- PanelContainer *context_menu_container;
- HBoxContainer *hbc_context_menu;
-
- Map<Control *, Timer *> popup_temporarily_timers;
-
- Label *warning_child_of_container;
- VBoxContainer *info_overlay;
+ PanelContainer *context_menu_container = nullptr;
+ HBoxContainer *hbc_context_menu = nullptr;
Transform2D transform;
- bool show_grid;
- bool show_rulers;
- bool show_guides;
- bool show_origin;
- bool show_viewport;
- bool show_helpers;
- bool show_edit_locks;
- bool show_transformation_gizmos;
-
- real_t zoom;
+ GridVisibility grid_visibility = GRID_VISIBILITY_SHOW_WHEN_SNAPPING;
+ bool show_rulers = true;
+ bool show_guides = true;
+ bool show_origin = true;
+ bool show_viewport = true;
+ bool show_helpers = false;
+ bool show_edit_locks = true;
+ bool show_transformation_gizmos = true;
+
+ real_t zoom = 1.0;
Point2 view_offset;
Point2 previous_update_view_offset;
- bool selected_from_canvas;
- bool anchors_mode;
+ bool selected_from_canvas = false;
Point2 grid_offset;
- Point2 grid_step;
- int primary_grid_steps;
- int grid_step_multiplier;
-
- real_t snap_rotation_step;
- real_t snap_rotation_offset;
- real_t snap_scale_step;
- bool smart_snap_active;
- bool grid_snap_active;
-
- bool snap_node_parent;
- bool snap_node_anchors;
- bool snap_node_sides;
- bool snap_node_center;
- bool snap_other_nodes;
- bool snap_guides;
- bool snap_rotation;
- bool snap_scale;
- bool snap_relative;
- bool snap_pixel;
- bool key_pos;
- bool key_rot;
- bool key_scale;
- bool panning;
- bool pan_pressed;
-
- bool ruler_tool_active;
+ Point2 grid_step = Point2(8, 8); // A power-of-two value works better as a default.
+ int primary_grid_steps = 8;
+ int grid_step_multiplier = 0;
+
+ real_t snap_rotation_step = 0.0;
+ real_t snap_rotation_offset = Math::deg2rad(15.0);
+ real_t snap_scale_step = 0.1f;
+ bool smart_snap_active = false;
+ bool grid_snap_active = false;
+
+ bool snap_node_parent = true;
+ bool snap_node_anchors = true;
+ bool snap_node_sides = true;
+ bool snap_node_center = true;
+ bool snap_other_nodes = true;
+ bool snap_guides = true;
+ bool snap_rotation = false;
+ bool snap_scale = false;
+ bool snap_relative = false;
+ // Enable pixel snapping even if pixel snap rendering is disabled in the Project Settings.
+ // This results in crisper visuals by preventing 2D nodes from being placed at subpixel coordinates.
+ bool snap_pixel = true;
+
+ bool key_pos = true;
+ bool key_rot = true;
+ bool key_scale = false;
+
+ bool pan_pressed = false;
+
+ bool ruler_tool_active = false;
Point2 ruler_tool_origin;
Point2 node_create_position;
@@ -313,7 +269,7 @@ private:
uint64_t last_pass = 0;
};
- uint64_t bone_last_frame;
+ uint64_t bone_last_frame = 0;
struct BoneKey {
ObjectID from;
@@ -337,65 +293,60 @@ private:
};
List<PoseClipboard> pose_clipboard;
- Button *select_button;
-
- Button *move_button;
- Button *scale_button;
- Button *rotate_button;
+ Button *select_button = nullptr;
- Button *list_select_button;
- Button *pivot_button;
- Button *pan_button;
+ Button *move_button = nullptr;
+ Button *scale_button = nullptr;
+ Button *rotate_button = nullptr;
- Button *ruler_button;
+ Button *list_select_button = nullptr;
+ Button *pivot_button = nullptr;
+ Button *pan_button = nullptr;
- Button *smart_snap_button;
- Button *grid_snap_button;
- MenuButton *snap_config_menu;
- PopupMenu *smartsnap_config_popup;
+ Button *ruler_button = nullptr;
- Button *lock_button;
- Button *unlock_button;
+ Button *smart_snap_button = nullptr;
+ Button *grid_snap_button = nullptr;
+ MenuButton *snap_config_menu = nullptr;
+ PopupMenu *smartsnap_config_popup = nullptr;
- Button *group_button;
- Button *ungroup_button;
+ Button *lock_button = nullptr;
+ Button *unlock_button = nullptr;
- MenuButton *skeleton_menu;
- Button *override_camera_button;
- MenuButton *view_menu;
- HBoxContainer *animation_hb;
- MenuButton *animation_menu;
+ Button *group_button = nullptr;
+ Button *ungroup_button = nullptr;
- MenuButton *presets_menu;
- PopupMenu *anchors_and_margins_popup;
- PopupMenu *anchors_popup;
+ MenuButton *skeleton_menu = nullptr;
+ Button *override_camera_button = nullptr;
+ MenuButton *view_menu = nullptr;
+ PopupMenu *grid_menu = nullptr;
+ HBoxContainer *animation_hb = nullptr;
+ MenuButton *animation_menu = nullptr;
- Button *anchor_mode_button;
+ Button *key_loc_button = nullptr;
+ Button *key_rot_button = nullptr;
+ Button *key_scale_button = nullptr;
+ Button *key_insert_button = nullptr;
+ Button *key_auto_insert_button = nullptr;
- Button *key_loc_button;
- Button *key_rot_button;
- Button *key_scale_button;
- Button *key_insert_button;
- Button *key_auto_insert_button;
+ PopupMenu *selection_menu = nullptr;
+ PopupMenu *add_node_menu = nullptr;
- PopupMenu *selection_menu;
- PopupMenu *add_node_menu;
-
- Control *top_ruler;
- Control *left_ruler;
+ Control *top_ruler = nullptr;
+ Control *left_ruler = nullptr;
Point2 drag_start_origin;
- DragType drag_type;
- Point2 drag_from;
- Point2 drag_to;
+ DragType drag_type = DRAG_NONE;
+ Point2 drag_from = Vector2();
+ Point2 drag_to = Vector2();
Point2 drag_rotation_center;
List<CanvasItem *> drag_selection;
- int dragged_guide_index;
- Point2 dragged_guide_pos;
- bool is_hovering_h_guide;
- bool is_hovering_v_guide;
+ int dragged_guide_index = -1;
+ Point2 dragged_guide_pos = Point2();
+ bool is_hovering_h_guide = false;
+ bool is_hovering_v_guide = false;
- bool updating_value_dialog;
+ bool updating_value_dialog = false;
Point2 box_selecting_to;
@@ -407,7 +358,13 @@ private:
Ref<Shortcut> set_pivot_shortcut;
Ref<Shortcut> multiply_grid_step_shortcut;
Ref<Shortcut> divide_grid_step_shortcut;
- Ref<Shortcut> pan_view_shortcut;
+
+ Ref<ViewPanner> panner;
+ bool warped_panning = true;
+ int pan_speed = 20;
+ void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
+ void _pan_callback(Vector2 p_scroll_vec);
+ void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
bool _is_node_locked(const Node *p_node);
bool _is_node_movable(const Node *p_node, bool p_popup_warning = false);
@@ -417,9 +374,9 @@ private:
void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append);
- ConfirmationDialog *snap_dialog;
+ ConfirmationDialog *snap_dialog = nullptr;
- CanvasItem *ref_item;
+ CanvasItem *ref_item = nullptr;
void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false);
void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false);
@@ -429,7 +386,7 @@ private:
Vector2 _position_to_anchor(const Control *p_control, Vector2 position);
void _popup_callback(int p_op);
- bool updating_scroll;
+ bool updating_scroll = false;
void _update_scroll(real_t);
void _update_scrollbars();
void _snap_changed();
@@ -438,10 +395,14 @@ private:
void _add_node_pressed(int p_result);
void _node_created(Node *p_node);
void _reset_create_position();
+ void _update_editor_settings();
+ bool _is_grid_visible() const;
+ void _prepare_grid_menu();
+ void _on_grid_menu_id_pressed(int p_id);
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
- List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
+ List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true);
Rect2 _get_encompassing_rect(const Node *p_node);
@@ -452,7 +413,7 @@ private:
void _keying_changed();
- virtual void unhandled_key_input(const Ref<InputEvent> &p_ev) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_ev) override;
void _draw_text_at_position(Point2 p_position, String p_string, Side p_side);
void _draw_margin_at_position(int p_value, Point2 p_position, Side p_side);
@@ -515,15 +476,10 @@ private:
const SnapTarget p_snap_target, List<const CanvasItem *> p_exceptions,
const Node *p_current);
- void _set_anchors_preset(Control::LayoutPreset p_preset);
- void _set_anchors_and_offsets_preset(Control::LayoutPreset p_preset);
- void _set_anchors_and_offsets_to_keep_ratio();
-
- void _button_toggle_anchor_mode(bool p_status);
-
- VBoxContainer *controls_vb;
- EditorZoomWidget *zoom_widget;
+ VBoxContainer *controls_vb = nullptr;
+ EditorZoomWidget *zoom_widget = nullptr;
void _update_zoom(real_t p_zoom);
+ void _shortcut_zoom_set(real_t p_zoom);
void _zoom_on_position(real_t p_zoom, Point2 p_position = Point2());
void _button_toggle_smart_snap(bool p_status);
void _button_toggle_grid_snap(bool p_status);
@@ -532,12 +488,11 @@ private:
void _update_override_camera_button(bool p_game_running);
- HSplitContainer *palette_split;
- VSplitContainer *bottom_split;
+ HSplitContainer *left_panel_split = nullptr;
+ HSplitContainer *right_panel_split = nullptr;
+ VSplitContainer *bottom_split = nullptr;
void _update_context_menu_stylebox();
- void _popup_warning_temporarily(Control *p_control, const double p_duration);
- void _popup_warning_depop(Control *p_control);
void _set_owner_for_node_and_children(Node *p_node, Node *p_owner);
@@ -578,10 +533,12 @@ public:
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
- void add_control_to_info_overlay(Control *p_control);
- void remove_control_from_info_overlay(Control *p_control);
+ void add_control_to_left_panel(Control *p_control);
+ void remove_control_from_left_panel(Control *p_control);
+
+ void add_control_to_right_panel(Control *p_control);
+ void remove_control_from_right_panel(Control *p_control);
- HSplitContainer *get_palette_split();
VSplitContainer *get_bottom_split();
Control *get_viewport_control() { return viewport; }
@@ -598,18 +555,15 @@ public:
void focus_selection();
- bool is_anchors_mode_enabled() { return anchors_mode; };
-
- EditorSelection *editor_selection;
+ EditorSelection *editor_selection = nullptr;
- CanvasItemEditor(EditorNode *p_editor);
+ CanvasItemEditor();
};
class CanvasItemEditorPlugin : public EditorPlugin {
GDCLASS(CanvasItemEditorPlugin, EditorPlugin);
- CanvasItemEditor *canvas_item_editor;
- EditorNode *editor;
+ CanvasItemEditor *canvas_item_editor = nullptr;
public:
virtual String get_name() const override { return "2D"; }
@@ -622,7 +576,7 @@ public:
CanvasItemEditor *get_canvas_item_editor() { return canvas_item_editor; }
- CanvasItemEditorPlugin(EditorNode *p_node);
+ CanvasItemEditorPlugin();
~CanvasItemEditorPlugin();
};
@@ -635,19 +589,18 @@ class CanvasItemEditorViewport : public Control {
Vector<String> texture_node_types;
Vector<String> selected_files;
- Node *target_node;
+ Node *target_node = nullptr;
Point2 drop_pos;
- EditorNode *editor;
- EditorData *editor_data;
- CanvasItemEditor *canvas_item_editor;
- Control *preview_node;
- AcceptDialog *accept;
- AcceptDialog *selector;
- Label *selector_label;
- Label *label;
- Label *label_desc;
- VBoxContainer *btn_group;
+ EditorData *editor_data = nullptr;
+ CanvasItemEditor *canvas_item_editor = nullptr;
+ Control *preview_node = nullptr;
+ AcceptDialog *accept = nullptr;
+ AcceptDialog *selector = nullptr;
+ Label *selector_label = nullptr;
+ Label *label = nullptr;
+ Label *label_desc = nullptr;
+ VBoxContainer *btn_group = nullptr;
Ref<ButtonGroup> button_group;
void _on_mouse_exit();
@@ -665,6 +618,7 @@ class CanvasItemEditorViewport : public Control {
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
void _perform_drop_data();
void _show_resource_type_selector();
+ void _update_theme();
static void _bind_methods();
@@ -675,8 +629,8 @@ public:
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
virtual void drop_data(const Point2 &p_point, const Variant &p_data) override;
- CanvasItemEditorViewport(EditorNode *p_node, CanvasItemEditor *p_canvas_item_editor);
+ CanvasItemEditorViewport(CanvasItemEditor *p_canvas_item_editor);
~CanvasItemEditorViewport();
};
-#endif
+#endif //CANVAS_ITEM_EDITOR_PLUGIN_H
diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
index 8e340b28ef..f018376e4b 100644
--- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -38,11 +38,8 @@ void CollisionPolygon2DEditor::_set_node(Node *p_polygon) {
node = Object::cast_to<CollisionPolygon2D>(p_polygon);
}
-CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) :
- AbstractPolygon2DEditor(p_editor) {
- node = nullptr;
-}
+CollisionPolygon2DEditor::CollisionPolygon2DEditor() {}
-CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) :
- AbstractPolygon2DEditorPlugin(p_node, memnew(CollisionPolygon2DEditor(p_node)), "CollisionPolygon2D") {
+CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin() :
+ AbstractPolygon2DEditorPlugin(memnew(CollisionPolygon2DEditor), "CollisionPolygon2D") {
}
diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.h b/editor/plugins/collision_polygon_2d_editor_plugin.h
index e78c486a39..0225d5d620 100644
--- a/editor/plugins/collision_polygon_2d_editor_plugin.h
+++ b/editor/plugins/collision_polygon_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,21 +37,21 @@
class CollisionPolygon2DEditor : public AbstractPolygon2DEditor {
GDCLASS(CollisionPolygon2DEditor, AbstractPolygon2DEditor);
- CollisionPolygon2D *node;
+ CollisionPolygon2D *node = nullptr;
protected:
virtual Node2D *_get_node() const override;
virtual void _set_node(Node *p_polygon) override;
public:
- CollisionPolygon2DEditor(EditorNode *p_editor);
+ CollisionPolygon2DEditor();
};
class CollisionPolygon2DEditorPlugin : public AbstractPolygon2DEditorPlugin {
GDCLASS(CollisionPolygon2DEditorPlugin, AbstractPolygon2DEditorPlugin);
public:
- CollisionPolygon2DEditorPlugin(EditorNode *p_node);
+ CollisionPolygon2DEditorPlugin();
};
#endif // COLLISION_POLYGON_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index fb32d7b1fd..af20064a8d 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "scene/resources/capsule_shape_2d.h"
#include "scene/resources/circle_shape_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
@@ -183,7 +184,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
size.y = p_point.y * RECT_HANDLES[idx].y * 2;
}
- if (Input::get_singleton()->is_key_pressed(KEY_ALT)) {
+ if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
rect->set_size(size.abs());
node->set_global_position(original_transform.get_origin());
} else {
@@ -323,6 +324,10 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
return false;
}
+ if (!node->is_visible_in_tree()) {
+ return false;
+ }
+
if (shape_type == -1) {
return false;
}
@@ -333,7 +338,7 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
if (mb.is_valid()) {
Vector2 gpoint = mb->get_position();
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
for (int i = 0; i < handles.size(); i++) {
if (xform.xform(handles[i]).distance_to(gpoint) < 8) {
@@ -394,7 +399,7 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
return false;
}
- if (shape_type == RECTANGLE_SHAPE && k->get_keycode() == KEY_ALT) {
+ if (shape_type == RECTANGLE_SHAPE && k->get_keycode() == Key::ALT) {
set_handle(edit_handle, last_point); // Update handle when Alt key is toggled.
}
}
@@ -445,6 +450,10 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
return;
}
+ if (!node->is_visible_in_tree()) {
+ return;
+ }
+
_get_current_shape_type();
if (shape_type == -1) {
@@ -574,12 +583,11 @@ void CollisionShape2DEditor::_bind_methods() {
ClassDB::bind_method("_get_current_shape_type", &CollisionShape2DEditor::_get_current_shape_type);
}
-CollisionShape2DEditor::CollisionShape2DEditor(EditorNode *p_editor) {
+CollisionShape2DEditor::CollisionShape2DEditor() {
node = nullptr;
canvas_item_editor = nullptr;
- editor = p_editor;
- undo_redo = p_editor->get_undo_redo();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
edit_handle = -1;
pressed = false;
@@ -601,11 +609,9 @@ void CollisionShape2DEditorPlugin::make_visible(bool visible) {
}
}
-CollisionShape2DEditorPlugin::CollisionShape2DEditorPlugin(EditorNode *p_editor) {
- editor = p_editor;
-
- collision_shape_2d_editor = memnew(CollisionShape2DEditor(p_editor));
- p_editor->get_gui_base()->add_child(collision_shape_2d_editor);
+CollisionShape2DEditorPlugin::CollisionShape2DEditorPlugin() {
+ collision_shape_2d_editor = memnew(CollisionShape2DEditor);
+ EditorNode::get_singleton()->get_gui_base()->add_child(collision_shape_2d_editor);
}
CollisionShape2DEditorPlugin::~CollisionShape2DEditorPlugin() {
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index ab95600a52..da9e9f339f 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,9 +31,7 @@
#ifndef COLLISION_SHAPE_2D_EDITOR_PLUGIN_H
#define COLLISION_SHAPE_2D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
-
#include "scene/2d/collision_shape_2d.h"
class CanvasItemEditor;
@@ -63,10 +61,9 @@ class CollisionShape2DEditor : public Control {
Point2(1, -1),
};
- EditorNode *editor;
- UndoRedo *undo_redo;
- CanvasItemEditor *canvas_item_editor;
- CollisionShape2D *node;
+ UndoRedo *undo_redo = nullptr;
+ CanvasItemEditor *canvas_item_editor = nullptr;
+ CollisionShape2D *node = nullptr;
Vector<Point2> handles;
@@ -93,14 +90,13 @@ public:
void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(Node *p_node);
- CollisionShape2DEditor(EditorNode *p_editor);
+ CollisionShape2DEditor();
};
class CollisionShape2DEditorPlugin : public EditorPlugin {
GDCLASS(CollisionShape2DEditorPlugin, EditorPlugin);
- CollisionShape2DEditor *collision_shape_2d_editor;
- EditorNode *editor;
+ CollisionShape2DEditor *collision_shape_2d_editor = nullptr;
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return collision_shape_2d_editor->forward_canvas_gui_input(p_event); }
@@ -112,7 +108,7 @@ public:
virtual bool handles(Object *p_obj) const override;
virtual void make_visible(bool visible) override;
- CollisionShape2DEditorPlugin(EditorNode *p_editor);
+ CollisionShape2DEditorPlugin();
~CollisionShape2DEditorPlugin();
};
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
new file mode 100644
index 0000000000..5ca8216d4d
--- /dev/null
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -0,0 +1,1013 @@
+/*************************************************************************/
+/* control_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "control_editor_plugin.h"
+
+#include "editor/editor_node.h"
+#include "editor/plugins/canvas_item_editor_plugin.h"
+
+void ControlPositioningWarning::_update_warning() {
+ if (!control_node) {
+ title_icon->set_texture(nullptr);
+ title_label->set_text("");
+ hint_label->set_text("");
+ return;
+ }
+
+ Node *parent_node = control_node->get_parent_control();
+ if (!parent_node) {
+ title_icon->set_texture(get_theme_icon(SNAME("SubViewport"), SNAME("EditorIcons")));
+ title_label->set_text(TTR("This node doesn't have a control parent."));
+ hint_label->set_text(TTR("Use the appropriate layout properties depending on where you are going to put it."));
+ } else if (Object::cast_to<Container>(parent_node)) {
+ title_icon->set_texture(get_theme_icon(SNAME("Container"), SNAME("EditorIcons")));
+ title_label->set_text(TTR("This node is a child of a container."));
+ hint_label->set_text(TTR("Use container properties for positioning."));
+ } else {
+ title_icon->set_texture(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
+ title_label->set_text(TTR("This node is a child of a regular control."));
+ hint_label->set_text(TTR("Use anchors and the rectangle for positioning."));
+ }
+
+ bg_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg_group_note"), SNAME("EditorProperty")));
+}
+
+void ControlPositioningWarning::_update_toggler() {
+ Ref<Texture2D> arrow;
+ if (hint_label->is_visible()) {
+ arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree"));
+ set_tooltip(TTR("Collapse positioning hint."));
+ } else {
+ if (is_layout_rtl()) {
+ arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree"));
+ } else {
+ arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree"));
+ }
+ set_tooltip(TTR("Expand positioning hint."));
+ }
+
+ hint_icon->set_texture(arrow);
+}
+
+void ControlPositioningWarning::set_control(Control *p_node) {
+ control_node = p_node;
+ _update_warning();
+}
+
+void ControlPositioningWarning::gui_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
+ bool state = !hint_label->is_visible();
+
+ hint_filler_left->set_visible(state);
+ hint_label->set_visible(state);
+ hint_filler_right->set_visible(state);
+
+ _update_toggler();
+ }
+}
+
+void ControlPositioningWarning::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED:
+ _update_warning();
+ _update_toggler();
+ break;
+ }
+}
+
+ControlPositioningWarning::ControlPositioningWarning() {
+ set_mouse_filter(MOUSE_FILTER_STOP);
+
+ bg_panel = memnew(PanelContainer);
+ bg_panel->set_mouse_filter(MOUSE_FILTER_IGNORE);
+ add_child(bg_panel);
+
+ grid = memnew(GridContainer);
+ grid->set_columns(3);
+ bg_panel->add_child(grid);
+
+ title_icon = memnew(TextureRect);
+ title_icon->set_stretch_mode(TextureRect::StretchMode::STRETCH_KEEP_CENTERED);
+ grid->add_child(title_icon);
+
+ title_label = memnew(Label);
+ title_label->set_autowrap_mode(Label::AutowrapMode::AUTOWRAP_WORD);
+ title_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ title_label->set_vertical_alignment(VerticalAlignment::VERTICAL_ALIGNMENT_CENTER);
+ grid->add_child(title_label);
+
+ hint_icon = memnew(TextureRect);
+ hint_icon->set_stretch_mode(TextureRect::StretchMode::STRETCH_KEEP_CENTERED);
+ grid->add_child(hint_icon);
+
+ // Filler.
+ hint_filler_left = memnew(Control);
+ hint_filler_left->hide();
+ grid->add_child(hint_filler_left);
+
+ hint_label = memnew(Label);
+ hint_label->set_autowrap_mode(Label::AutowrapMode::AUTOWRAP_WORD);
+ hint_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hint_label->set_vertical_alignment(VerticalAlignment::VERTICAL_ALIGNMENT_CENTER);
+ hint_label->hide();
+ grid->add_child(hint_label);
+
+ // Filler.
+ hint_filler_right = memnew(Control);
+ hint_filler_right->hide();
+ grid->add_child(hint_filler_right);
+}
+
+void EditorPropertyAnchorsPreset::_set_read_only(bool p_read_only) {
+ options->set_disabled(p_read_only);
+};
+
+void EditorPropertyAnchorsPreset::_option_selected(int p_which) {
+ int64_t val = options->get_item_metadata(p_which);
+ emit_changed(get_edited_property(), val);
+}
+
+void EditorPropertyAnchorsPreset::update_property() {
+ int64_t which = get_edited_object()->get(get_edited_property());
+
+ for (int i = 0; i < options->get_item_count(); i++) {
+ Variant val = options->get_item_metadata(i);
+ if (val != Variant() && which == (int64_t)val) {
+ options->select(i);
+ return;
+ }
+ }
+}
+
+void EditorPropertyAnchorsPreset::setup(const Vector<String> &p_options) {
+ options->clear();
+
+ Vector<String> split_after;
+ split_after.append("Custom");
+ split_after.append("PresetWide");
+ split_after.append("PresetBottomLeft");
+ split_after.append("PresetCenter");
+
+ for (int i = 0, j = 0; i < p_options.size(); i++, j++) {
+ Vector<String> text_split = p_options[i].split(":");
+ int64_t current_val = text_split[1].to_int();
+
+ String humanized_name = text_split[0];
+ if (humanized_name.begins_with("Preset")) {
+ if (humanized_name == "PresetWide") {
+ humanized_name = "Full Rect";
+ } else {
+ humanized_name = humanized_name.trim_prefix("Preset");
+ humanized_name = humanized_name.capitalize();
+ }
+
+ String icon_name = text_split[0].trim_prefix("Preset");
+ icon_name = "ControlAlign" + icon_name;
+ options->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(icon_name, "EditorIcons"), humanized_name);
+ } else {
+ options->add_item(humanized_name);
+ }
+
+ options->set_item_metadata(j, current_val);
+ if (split_after.has(text_split[0])) {
+ options->add_separator();
+ j++;
+ }
+ }
+}
+
+EditorPropertyAnchorsPreset::EditorPropertyAnchorsPreset() {
+ options = memnew(OptionButton);
+ options->set_clip_text(true);
+ options->set_flat(true);
+ add_child(options);
+ add_focusable(options);
+ options->connect("item_selected", callable_mp(this, &EditorPropertyAnchorsPreset::_option_selected));
+}
+
+void EditorPropertySizeFlags::_set_read_only(bool p_read_only) {
+ for (CheckBox *check : flag_checks) {
+ check->set_disabled(p_read_only);
+ }
+ flag_presets->set_disabled(p_read_only);
+};
+
+void EditorPropertySizeFlags::_preset_selected(int p_which) {
+ int preset = flag_presets->get_item_id(p_which);
+ if (preset == SIZE_FLAGS_PRESET_CUSTOM) {
+ flag_options->set_visible(true);
+ return;
+ }
+ flag_options->set_visible(false);
+
+ uint32_t value = 0;
+ switch (preset) {
+ case SIZE_FLAGS_PRESET_FILL:
+ value = Control::SIZE_FILL;
+ break;
+ case SIZE_FLAGS_PRESET_SHRINK_BEGIN:
+ value = Control::SIZE_SHRINK_BEGIN;
+ break;
+ case SIZE_FLAGS_PRESET_SHRINK_CENTER:
+ value = Control::SIZE_SHRINK_CENTER;
+ break;
+ case SIZE_FLAGS_PRESET_SHRINK_END:
+ value = Control::SIZE_SHRINK_END;
+ break;
+ }
+
+ bool is_expand = flag_expand->is_visible() && flag_expand->is_pressed();
+ if (is_expand) {
+ value |= Control::SIZE_EXPAND;
+ }
+
+ emit_changed(get_edited_property(), value);
+}
+
+void EditorPropertySizeFlags::_expand_toggled() {
+ uint32_t value = get_edited_object()->get(get_edited_property());
+
+ if (flag_expand->is_visible() && flag_expand->is_pressed()) {
+ value |= Control::SIZE_EXPAND;
+ } else {
+ value ^= Control::SIZE_EXPAND;
+ }
+
+ // Keep the custom preset selected as we toggle individual flags.
+ keep_selected_preset = true;
+ emit_changed(get_edited_property(), value);
+}
+
+void EditorPropertySizeFlags::_flag_toggled() {
+ uint32_t value = 0;
+ for (int i = 0; i < flag_checks.size(); i++) {
+ if (flag_checks[i]->is_pressed()) {
+ int flag_value = flag_checks[i]->get_meta("_value");
+ value |= flag_value;
+ }
+ }
+
+ bool is_expand = flag_expand->is_visible() && flag_expand->is_pressed();
+ if (is_expand) {
+ value |= Control::SIZE_EXPAND;
+ }
+
+ // Keep the custom preset selected as we toggle individual flags.
+ keep_selected_preset = true;
+ emit_changed(get_edited_property(), value);
+}
+
+void EditorPropertySizeFlags::update_property() {
+ uint32_t value = get_edited_object()->get(get_edited_property());
+
+ for (int i = 0; i < flag_checks.size(); i++) {
+ int flag_value = flag_checks[i]->get_meta("_value");
+ if (value & flag_value) {
+ flag_checks[i]->set_pressed(true);
+ } else {
+ flag_checks[i]->set_pressed(false);
+ }
+ }
+
+ bool is_expand = value & Control::SIZE_EXPAND;
+ flag_expand->set_pressed(is_expand);
+
+ if (keep_selected_preset) {
+ keep_selected_preset = false;
+ return;
+ }
+
+ FlagPreset preset = SIZE_FLAGS_PRESET_CUSTOM;
+ if (value == Control::SIZE_FILL || value == (Control::SIZE_FILL | Control::SIZE_EXPAND)) {
+ preset = SIZE_FLAGS_PRESET_FILL;
+ } else if (value == Control::SIZE_SHRINK_BEGIN || value == (Control::SIZE_SHRINK_BEGIN | Control::SIZE_EXPAND)) {
+ preset = SIZE_FLAGS_PRESET_SHRINK_BEGIN;
+ } else if (value == Control::SIZE_SHRINK_CENTER || value == (Control::SIZE_SHRINK_CENTER | Control::SIZE_EXPAND)) {
+ preset = SIZE_FLAGS_PRESET_SHRINK_CENTER;
+ } else if (value == Control::SIZE_SHRINK_END || value == (Control::SIZE_SHRINK_END | Control::SIZE_EXPAND)) {
+ preset = SIZE_FLAGS_PRESET_SHRINK_END;
+ }
+
+ int preset_idx = flag_presets->get_item_index(preset);
+ if (preset_idx >= 0) {
+ flag_presets->select(preset_idx);
+ }
+ flag_options->set_visible(preset == SIZE_FLAGS_PRESET_CUSTOM);
+}
+
+void EditorPropertySizeFlags::setup(const Vector<String> &p_options, bool p_vertical) {
+ vertical = p_vertical;
+
+ if (p_options.size() == 0) {
+ flag_presets->clear();
+ flag_presets->add_item(TTR("Container Default"));
+ flag_presets->set_disabled(true);
+ flag_expand->set_visible(false);
+ return;
+ }
+
+ Map<int, String> flags;
+ for (int i = 0, j = 0; i < p_options.size(); i++, j++) {
+ Vector<String> text_split = p_options[i].split(":");
+ int64_t current_val = text_split[1].to_int();
+ flags[current_val] = text_split[0];
+
+ if (current_val == SIZE_EXPAND) {
+ continue;
+ }
+
+ CheckBox *cb = memnew(CheckBox);
+ cb->set_text(text_split[0]);
+ cb->set_clip_text(true);
+ cb->set_meta("_value", current_val);
+ cb->connect("pressed", callable_mp(this, &EditorPropertySizeFlags::_flag_toggled));
+ add_focusable(cb);
+
+ flag_options->add_child(cb);
+ flag_checks.append(cb);
+ }
+
+ Control *gui_base = EditorNode::get_singleton()->get_gui_base();
+ String wide_preset_icon = SNAME("ControlAlignHCenterWide");
+ String begin_preset_icon = SNAME("ControlAlignCenterLeft");
+ String end_preset_icon = SNAME("ControlAlignCenterRight");
+ if (vertical) {
+ wide_preset_icon = SNAME("ControlAlignVCenterWide");
+ begin_preset_icon = SNAME("ControlAlignCenterTop");
+ end_preset_icon = SNAME("ControlAlignCenterBottom");
+ }
+
+ flag_presets->clear();
+ if (flags.has(SIZE_FILL)) {
+ flag_presets->add_icon_item(gui_base->get_theme_icon(wide_preset_icon, SNAME("EditorIcons")), TTR("Fill"), SIZE_FLAGS_PRESET_FILL);
+ }
+ // Shrink Begin is the same as no flags at all, as such it cannot be disabled.
+ flag_presets->add_icon_item(gui_base->get_theme_icon(begin_preset_icon, SNAME("EditorIcons")), TTR("Shrink Begin"), SIZE_FLAGS_PRESET_SHRINK_BEGIN);
+ if (flags.has(SIZE_SHRINK_CENTER)) {
+ flag_presets->add_icon_item(gui_base->get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Shrink Center"), SIZE_FLAGS_PRESET_SHRINK_CENTER);
+ }
+ if (flags.has(SIZE_SHRINK_END)) {
+ flag_presets->add_icon_item(gui_base->get_theme_icon(end_preset_icon, SNAME("EditorIcons")), TTR("Shrink End"), SIZE_FLAGS_PRESET_SHRINK_END);
+ }
+ flag_presets->add_separator();
+ flag_presets->add_item(TTR("Custom"), SIZE_FLAGS_PRESET_CUSTOM);
+
+ flag_expand->set_visible(flags.has(SIZE_EXPAND));
+}
+
+EditorPropertySizeFlags::EditorPropertySizeFlags() {
+ VBoxContainer *vb = memnew(VBoxContainer);
+ add_child(vb);
+
+ flag_presets = memnew(OptionButton);
+ flag_presets->set_clip_text(true);
+ flag_presets->set_flat(true);
+ vb->add_child(flag_presets);
+ add_focusable(flag_presets);
+ set_label_reference(flag_presets);
+ flag_presets->connect("item_selected", callable_mp(this, &EditorPropertySizeFlags::_preset_selected));
+
+ flag_options = memnew(VBoxContainer);
+ flag_options->hide();
+ vb->add_child(flag_options);
+
+ flag_expand = memnew(CheckBox);
+ flag_expand->set_text(TTR("Expand"));
+ vb->add_child(flag_expand);
+ add_focusable(flag_expand);
+ flag_expand->connect("pressed", callable_mp(this, &EditorPropertySizeFlags::_expand_toggled));
+}
+
+bool EditorInspectorPluginControl::can_handle(Object *p_object) {
+ return Object::cast_to<Control>(p_object) != nullptr;
+}
+
+void EditorInspectorPluginControl::parse_group(Object *p_object, const String &p_group) {
+ Control *control = Object::cast_to<Control>(p_object);
+ if (!control || p_group != "Layout") {
+ return;
+ }
+
+ ControlPositioningWarning *pos_warning = memnew(ControlPositioningWarning);
+ pos_warning->set_control(control);
+ add_custom_control(pos_warning);
+}
+
+bool EditorInspectorPluginControl::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+ Control *control = Object::cast_to<Control>(p_object);
+ if (!control) {
+ return false;
+ }
+
+ if (p_path == "anchors_preset") {
+ EditorPropertyAnchorsPreset *prop_editor = memnew(EditorPropertyAnchorsPreset);
+ Vector<String> options = p_hint_text.split(",");
+ prop_editor->setup(options);
+ add_property_editor(p_path, prop_editor);
+
+ return true;
+ }
+
+ if (p_path == "size_flags_horizontal" || p_path == "size_flags_vertical") {
+ EditorPropertySizeFlags *prop_editor = memnew(EditorPropertySizeFlags);
+ Vector<String> options;
+ if (!p_hint_text.is_empty()) {
+ options = p_hint_text.split(",");
+ }
+ prop_editor->setup(options, p_path == "size_flags_vertical");
+ add_property_editor(p_path, prop_editor);
+
+ return true;
+ }
+
+ return false;
+}
+
+void ControlEditorToolbar::_set_anchors_and_offsets_preset(Control::LayoutPreset p_preset) {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action(TTR("Change Anchors and Offsets"));
+
+ for (Node *E : selection) {
+ Control *control = Object::cast_to<Control>(E);
+ if (control) {
+ undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
+ switch (p_preset) {
+ case PRESET_TOP_LEFT:
+ case PRESET_TOP_RIGHT:
+ case PRESET_BOTTOM_LEFT:
+ case PRESET_BOTTOM_RIGHT:
+ case PRESET_CENTER_LEFT:
+ case PRESET_CENTER_TOP:
+ case PRESET_CENTER_RIGHT:
+ case PRESET_CENTER_BOTTOM:
+ case PRESET_CENTER:
+ undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_KEEP_SIZE);
+ break;
+ case PRESET_LEFT_WIDE:
+ case PRESET_TOP_WIDE:
+ case PRESET_RIGHT_WIDE:
+ case PRESET_BOTTOM_WIDE:
+ case PRESET_VCENTER_WIDE:
+ case PRESET_HCENTER_WIDE:
+ case PRESET_WIDE:
+ undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_MINSIZE);
+ break;
+ }
+ undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
+ }
+ }
+
+ undo_redo->commit_action();
+
+ anchors_mode = false;
+ anchor_mode_button->set_pressed(anchors_mode);
+}
+
+void ControlEditorToolbar::_set_anchors_and_offsets_to_keep_ratio() {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action(TTR("Change Anchors and Offsets"));
+
+ for (Node *E : selection) {
+ Control *control = Object::cast_to<Control>(E);
+ if (control) {
+ Point2 top_left_anchor = _position_to_anchor(control, Point2());
+ Point2 bottom_right_anchor = _position_to_anchor(control, control->get_size());
+ undo_redo->add_do_method(control, "set_anchor", SIDE_LEFT, top_left_anchor.x, false, true);
+ undo_redo->add_do_method(control, "set_anchor", SIDE_RIGHT, bottom_right_anchor.x, false, true);
+ undo_redo->add_do_method(control, "set_anchor", SIDE_TOP, top_left_anchor.y, false, true);
+ undo_redo->add_do_method(control, "set_anchor", SIDE_BOTTOM, bottom_right_anchor.y, false, true);
+ undo_redo->add_do_method(control, "set_meta", "_edit_use_anchors_", true);
+
+ const bool use_anchors = control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_");
+ undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
+ if (use_anchors) {
+ undo_redo->add_undo_method(control, "set_meta", "_edit_use_anchors_", true);
+ } else {
+ undo_redo->add_undo_method(control, "remove_meta", "_edit_use_anchors_");
+ }
+
+ anchors_mode = true;
+ anchor_mode_button->set_pressed(anchors_mode);
+ }
+ }
+
+ undo_redo->commit_action();
+}
+
+void ControlEditorToolbar::_set_anchors_preset(Control::LayoutPreset p_preset) {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action(TTR("Change Anchors"));
+ for (Node *E : selection) {
+ Control *control = Object::cast_to<Control>(E);
+ if (control) {
+ undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
+ undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
+ }
+ }
+
+ undo_redo->commit_action();
+}
+
+void ControlEditorToolbar::_set_container_h_preset(Control::SizeFlags p_preset) {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action(TTR("Change Horizontal Size Flags"));
+ for (Node *E : selection) {
+ Control *control = Object::cast_to<Control>(E);
+ if (control) {
+ undo_redo->add_do_method(control, "set_h_size_flags", p_preset);
+ undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
+ }
+ }
+
+ undo_redo->commit_action();
+}
+
+void ControlEditorToolbar::_set_container_v_preset(Control::SizeFlags p_preset) {
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action(TTR("Change Horizontal Size Flags"));
+ for (Node *E : selection) {
+ Control *control = Object::cast_to<Control>(E);
+ if (control) {
+ undo_redo->add_do_method(control, "set_v_size_flags", p_preset);
+ undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
+ }
+ }
+
+ undo_redo->commit_action();
+}
+
+Vector2 ControlEditorToolbar::_anchor_to_position(const Control *p_control, Vector2 anchor) {
+ ERR_FAIL_COND_V(!p_control, Vector2());
+
+ Transform2D parent_transform = p_control->get_transform().affine_inverse();
+ Rect2 parent_rect = p_control->get_parent_anchorable_rect();
+
+ if (p_control->is_layout_rtl()) {
+ return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x - parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y));
+ } else {
+ return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y));
+ }
+}
+
+Vector2 ControlEditorToolbar::_position_to_anchor(const Control *p_control, Vector2 position) {
+ ERR_FAIL_COND_V(!p_control, Vector2());
+
+ Rect2 parent_rect = p_control->get_parent_anchorable_rect();
+
+ Vector2 output = Vector2();
+ if (p_control->is_layout_rtl()) {
+ output.x = (parent_rect.size.x == 0) ? 0.0 : (parent_rect.size.x - p_control->get_transform().xform(position).x - parent_rect.position.x) / parent_rect.size.x;
+ } else {
+ output.x = (parent_rect.size.x == 0) ? 0.0 : (p_control->get_transform().xform(position).x - parent_rect.position.x) / parent_rect.size.x;
+ }
+ output.y = (parent_rect.size.y == 0) ? 0.0 : (p_control->get_transform().xform(position).y - parent_rect.position.y) / parent_rect.size.y;
+ return output;
+}
+
+void ControlEditorToolbar::_button_toggle_anchor_mode(bool p_status) {
+ List<Control *> selection = _get_edited_controls(false, false);
+ for (Control *E : selection) {
+ if (Object::cast_to<Container>(E->get_parent())) {
+ continue;
+ }
+
+ if (p_status) {
+ E->set_meta("_edit_use_anchors_", true);
+ } else {
+ E->remove_meta("_edit_use_anchors_");
+ }
+ }
+
+ anchors_mode = p_status;
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+bool ControlEditorToolbar::_is_node_locked(const Node *p_node) {
+ return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
+}
+
+List<Control *> ControlEditorToolbar::_get_edited_controls(bool retrieve_locked, bool remove_controls_if_parent_in_selection) {
+ List<Control *> selection;
+ for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
+ Control *control = Object::cast_to<Control>(E.key);
+ if (control && control->is_visible_in_tree() && control->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retrieve_locked || !_is_node_locked(control))) {
+ selection.push_back(control);
+ }
+ }
+
+ if (remove_controls_if_parent_in_selection) {
+ List<Control *> filtered_selection;
+ for (Control *E : selection) {
+ if (!selection.find(E->get_parent())) {
+ filtered_selection.push_back(E);
+ }
+ }
+ return filtered_selection;
+ }
+
+ return selection;
+}
+
+void ControlEditorToolbar::_popup_callback(int p_op) {
+ switch (p_op) {
+ case ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT: {
+ _set_anchors_and_offsets_preset(PRESET_TOP_LEFT);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT: {
+ _set_anchors_and_offsets_preset(PRESET_TOP_RIGHT);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT: {
+ _set_anchors_and_offsets_preset(PRESET_BOTTOM_LEFT);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT: {
+ _set_anchors_and_offsets_preset(PRESET_BOTTOM_RIGHT);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT: {
+ _set_anchors_and_offsets_preset(PRESET_CENTER_LEFT);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT: {
+ _set_anchors_and_offsets_preset(PRESET_CENTER_RIGHT);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP: {
+ _set_anchors_and_offsets_preset(PRESET_CENTER_TOP);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM: {
+ _set_anchors_and_offsets_preset(PRESET_CENTER_BOTTOM);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_CENTER: {
+ _set_anchors_and_offsets_preset(PRESET_CENTER);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE: {
+ _set_anchors_and_offsets_preset(PRESET_TOP_WIDE);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE: {
+ _set_anchors_and_offsets_preset(PRESET_LEFT_WIDE);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE: {
+ _set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE: {
+ _set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE: {
+ _set_anchors_and_offsets_preset(PRESET_VCENTER_WIDE);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE: {
+ _set_anchors_and_offsets_preset(PRESET_HCENTER_WIDE);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_WIDE: {
+ _set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ } break;
+ case ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO: {
+ _set_anchors_and_offsets_to_keep_ratio();
+ } break;
+
+ case ANCHORS_PRESET_TOP_LEFT: {
+ _set_anchors_preset(PRESET_TOP_LEFT);
+ } break;
+ case ANCHORS_PRESET_TOP_RIGHT: {
+ _set_anchors_preset(PRESET_TOP_RIGHT);
+ } break;
+ case ANCHORS_PRESET_BOTTOM_LEFT: {
+ _set_anchors_preset(PRESET_BOTTOM_LEFT);
+ } break;
+ case ANCHORS_PRESET_BOTTOM_RIGHT: {
+ _set_anchors_preset(PRESET_BOTTOM_RIGHT);
+ } break;
+ case ANCHORS_PRESET_CENTER_LEFT: {
+ _set_anchors_preset(PRESET_CENTER_LEFT);
+ } break;
+ case ANCHORS_PRESET_CENTER_RIGHT: {
+ _set_anchors_preset(PRESET_CENTER_RIGHT);
+ } break;
+ case ANCHORS_PRESET_CENTER_TOP: {
+ _set_anchors_preset(PRESET_CENTER_TOP);
+ } break;
+ case ANCHORS_PRESET_CENTER_BOTTOM: {
+ _set_anchors_preset(PRESET_CENTER_BOTTOM);
+ } break;
+ case ANCHORS_PRESET_CENTER: {
+ _set_anchors_preset(PRESET_CENTER);
+ } break;
+ case ANCHORS_PRESET_TOP_WIDE: {
+ _set_anchors_preset(PRESET_TOP_WIDE);
+ } break;
+ case ANCHORS_PRESET_LEFT_WIDE: {
+ _set_anchors_preset(PRESET_LEFT_WIDE);
+ } break;
+ case ANCHORS_PRESET_RIGHT_WIDE: {
+ _set_anchors_preset(PRESET_RIGHT_WIDE);
+ } break;
+ case ANCHORS_PRESET_BOTTOM_WIDE: {
+ _set_anchors_preset(PRESET_BOTTOM_WIDE);
+ } break;
+ case ANCHORS_PRESET_VCENTER_WIDE: {
+ _set_anchors_preset(PRESET_VCENTER_WIDE);
+ } break;
+ case ANCHORS_PRESET_HCENTER_WIDE: {
+ _set_anchors_preset(PRESET_HCENTER_WIDE);
+ } break;
+ case ANCHORS_PRESET_WIDE: {
+ _set_anchors_preset(Control::PRESET_WIDE);
+ } break;
+
+ case CONTAINERS_H_PRESET_FILL: {
+ _set_container_h_preset(Control::SIZE_FILL);
+ } break;
+ case CONTAINERS_H_PRESET_FILL_EXPAND: {
+ _set_container_h_preset(Control::SIZE_EXPAND_FILL);
+ } break;
+ case CONTAINERS_H_PRESET_SHRINK_BEGIN: {
+ _set_container_h_preset(Control::SIZE_SHRINK_BEGIN);
+ } break;
+ case CONTAINERS_H_PRESET_SHRINK_CENTER: {
+ _set_container_h_preset(Control::SIZE_SHRINK_CENTER);
+ } break;
+ case CONTAINERS_H_PRESET_SHRINK_END: {
+ _set_container_h_preset(Control::SIZE_SHRINK_END);
+ } break;
+
+ case CONTAINERS_V_PRESET_FILL: {
+ _set_container_v_preset(Control::SIZE_FILL);
+ } break;
+ case CONTAINERS_V_PRESET_FILL_EXPAND: {
+ _set_container_v_preset(Control::SIZE_EXPAND_FILL);
+ } break;
+ case CONTAINERS_V_PRESET_SHRINK_BEGIN: {
+ _set_container_v_preset(Control::SIZE_SHRINK_BEGIN);
+ } break;
+ case CONTAINERS_V_PRESET_SHRINK_CENTER: {
+ _set_container_v_preset(Control::SIZE_SHRINK_CENTER);
+ } break;
+ case CONTAINERS_V_PRESET_SHRINK_END: {
+ _set_container_v_preset(Control::SIZE_SHRINK_END);
+ } break;
+ }
+}
+
+void ControlEditorToolbar::_selection_changed() {
+ // Update the anchors_mode.
+ int nb_controls = 0;
+ int nb_valid_controls = 0;
+ int nb_anchors_mode = 0;
+
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Control *control = Object::cast_to<Control>(E);
+ if (!control) {
+ continue;
+ }
+
+ nb_controls++;
+ if (Object::cast_to<Container>(control->get_parent())) {
+ continue;
+ }
+
+ nb_valid_controls++;
+ if (control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_")) {
+ nb_anchors_mode++;
+ }
+ }
+
+ anchors_mode = (nb_valid_controls == nb_anchors_mode);
+ anchor_mode_button->set_pressed(anchors_mode);
+
+ if (nb_controls > 0) {
+ set_physics_process(true);
+ } else {
+ set_physics_process(false);
+ set_visible(false);
+ }
+}
+
+void ControlEditorToolbar::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ anchor_presets_menu->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
+
+ PopupMenu *p = anchor_presets_menu->get_popup();
+ p->clear();
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")), TTR("Top Left"), ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")), TTR("Top Right"), ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")), TTR("Bottom Right"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")), TTR("Bottom Left"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT);
+ p->add_separator();
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")), TTR("Center Left"), ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")), TTR("Center Top"), ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")), TTR("Center Right"), ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")), TTR("Center Bottom"), ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Center"), ANCHORS_AND_OFFSETS_PRESET_CENTER);
+ p->add_separator();
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")), TTR("Left Wide"), ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")), TTR("Top Wide"), ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")), TTR("Right Wide"), ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")), TTR("Bottom Wide"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE);
+ p->add_separator();
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignWide"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_AND_OFFSETS_PRESET_WIDE);
+ p->add_icon_item(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")), TTR("Keep Current Ratio"), ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO);
+ p->set_item_tooltip(19, TTR("Adjust anchors and offsets to match the current rect size."));
+
+ p->add_separator();
+ p->add_submenu_item(TTR("Anchors only"), "Anchors");
+ p->set_item_icon(21, get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
+
+ anchors_popup->clear();
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT);
+ anchors_popup->add_separator();
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Center"), ANCHORS_PRESET_CENTER);
+ anchors_popup->add_separator();
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE);
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE);
+ anchors_popup->add_separator();
+ anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignWide"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_PRESET_WIDE);
+
+ anchor_mode_button->set_icon(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
+
+ container_h_presets_menu->set_icon(get_theme_icon(SNAME("Container"), SNAME("EditorIcons")));
+ container_v_presets_menu->set_icon(get_theme_icon(SNAME("Container"), SNAME("EditorIcons")));
+
+ p = container_h_presets_menu->get_popup();
+ p->clear();
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("Fill"), CONTAINERS_H_PRESET_FILL);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("Fill & Expand"), CONTAINERS_H_PRESET_FILL_EXPAND);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")), TTR("Shrink Begin"), CONTAINERS_H_PRESET_SHRINK_BEGIN);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Shrink Center"), CONTAINERS_H_PRESET_SHRINK_CENTER);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")), TTR("Shrink End"), CONTAINERS_H_PRESET_SHRINK_END);
+
+ p = container_v_presets_menu->get_popup();
+ p->clear();
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("Fill"), CONTAINERS_V_PRESET_FILL);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("Fill & Expand"), CONTAINERS_V_PRESET_FILL_EXPAND);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")), TTR("Shrink Begin"), CONTAINERS_V_PRESET_SHRINK_BEGIN);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Shrink Center"), CONTAINERS_V_PRESET_SHRINK_CENTER);
+ p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")), TTR("Shrink End"), CONTAINERS_V_PRESET_SHRINK_END);
+ } break;
+
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ bool has_control_parents = false;
+ bool has_container_parents = false;
+
+ // Update the viewport if the canvas_item changes
+ List<Control *> selection = _get_edited_controls(true);
+ for (Control *control : selection) {
+ if (Object::cast_to<Control>(control->get_parent())) {
+ has_control_parents = true;
+ }
+ if (Object::cast_to<Container>(control->get_parent())) {
+ has_container_parents = true;
+ }
+ }
+
+ // Show / Hide the control layout buttons.
+ if (selection.size() > 0) {
+ set_visible(true);
+
+ // Toggle anchor and container layout buttons depending on parents of the selected nodes.
+ // - If there are no control parents, enable everything.
+ // - If there are container parents, then enable only container buttons.
+ // - If there are NO container parents, then enable only anchor buttons.
+ bool enable_anchors = false;
+ bool enable_containers = false;
+ if (!has_control_parents) {
+ enable_anchors = true;
+ enable_containers = true;
+ } else if (has_container_parents) {
+ enable_containers = true;
+ } else {
+ enable_anchors = true;
+ }
+
+ if (enable_anchors) {
+ anchor_presets_menu->set_visible(true);
+ anchor_mode_button->set_visible(true);
+ } else {
+ anchor_presets_menu->set_visible(false);
+ anchor_mode_button->set_visible(false);
+ }
+
+ if (enable_containers) {
+ container_h_presets_menu->set_visible(true);
+ container_v_presets_menu->set_visible(true);
+ } else {
+ container_h_presets_menu->set_visible(false);
+ container_v_presets_menu->set_visible(false);
+ }
+ } else {
+ set_visible(false);
+ }
+ } break;
+ }
+}
+
+ControlEditorToolbar::ControlEditorToolbar() {
+ anchor_presets_menu = memnew(MenuButton);
+ anchor_presets_menu->set_shortcut_context(this);
+ anchor_presets_menu->set_text(TTR("Anchors"));
+ anchor_presets_menu->set_tooltip(TTR("Presets for the anchor and offset values of a Control node."));
+ add_child(anchor_presets_menu);
+ anchor_presets_menu->set_switch_on_hover(true);
+
+ PopupMenu *p = anchor_presets_menu->get_popup();
+ p->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
+
+ anchors_popup = memnew(PopupMenu);
+ p->add_child(anchors_popup);
+ anchors_popup->set_name("Anchors");
+ anchors_popup->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
+
+ anchor_mode_button = memnew(Button);
+ anchor_mode_button->set_flat(true);
+ anchor_mode_button->set_toggle_mode(true);
+ anchor_mode_button->set_tooltip(TTR("When active, moving Control nodes changes their anchors instead of their offsets."));
+ add_child(anchor_mode_button);
+ anchor_mode_button->connect("toggled", callable_mp(this, &ControlEditorToolbar::_button_toggle_anchor_mode));
+
+ add_child(memnew(VSeparator));
+
+ container_h_presets_menu = memnew(MenuButton);
+ container_h_presets_menu->set_shortcut_context(this);
+ container_h_presets_menu->set_text(TTR("Horizontal"));
+ container_h_presets_menu->set_tooltip(TTR("Horizontal sizing setting for children of a Container node."));
+ add_child(container_h_presets_menu);
+ container_h_presets_menu->set_switch_on_hover(true);
+
+ p = container_h_presets_menu->get_popup();
+ p->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
+
+ container_v_presets_menu = memnew(MenuButton);
+ container_v_presets_menu->set_shortcut_context(this);
+ container_v_presets_menu->set_text(TTR("Vertical"));
+ container_v_presets_menu->set_tooltip(TTR("Vertical sizing setting for children of a Container node."));
+ add_child(container_v_presets_menu);
+ container_v_presets_menu->set_switch_on_hover(true);
+
+ p = container_v_presets_menu->get_popup();
+ p->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
+
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ editor_selection = EditorNode::get_singleton()->get_editor_selection();
+ editor_selection->add_editor_plugin(this);
+ editor_selection->connect("selection_changed", callable_mp(this, &ControlEditorToolbar::_selection_changed));
+
+ singleton = this;
+}
+
+ControlEditorToolbar *ControlEditorToolbar::singleton = nullptr;
+
+ControlEditorPlugin::ControlEditorPlugin() {
+ toolbar = memnew(ControlEditorToolbar);
+ toolbar->hide();
+ add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
+
+ Ref<EditorInspectorPluginControl> plugin;
+ plugin.instantiate();
+ add_inspector_plugin(plugin);
+}
diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h
new file mode 100644
index 0000000000..96451f7dcf
--- /dev/null
+++ b/editor/plugins/control_editor_plugin.h
@@ -0,0 +1,250 @@
+/*************************************************************************/
+/* control_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 CONTROL_EDITOR_PLUGIN_H
+#define CONTROL_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/control.h"
+#include "scene/gui/label.h"
+#include "scene/gui/margin_container.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/texture_rect.h"
+
+class ControlPositioningWarning : public MarginContainer {
+ GDCLASS(ControlPositioningWarning, MarginContainer);
+
+ Control *control_node = nullptr;
+
+ PanelContainer *bg_panel = nullptr;
+ GridContainer *grid = nullptr;
+ TextureRect *title_icon = nullptr;
+ TextureRect *hint_icon = nullptr;
+ Label *title_label = nullptr;
+ Label *hint_label = nullptr;
+ Control *hint_filler_left = nullptr;
+ Control *hint_filler_right = nullptr;
+
+ void _update_warning();
+ void _update_toggler();
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
+protected:
+ void _notification(int p_notification);
+
+public:
+ void set_control(Control *p_node);
+
+ ControlPositioningWarning();
+};
+
+class EditorPropertyAnchorsPreset : public EditorProperty {
+ GDCLASS(EditorPropertyAnchorsPreset, EditorProperty);
+ OptionButton *options = nullptr;
+
+ void _option_selected(int p_which);
+
+protected:
+ virtual void _set_read_only(bool p_read_only) override;
+
+public:
+ void setup(const Vector<String> &p_options);
+ virtual void update_property() override;
+ EditorPropertyAnchorsPreset();
+};
+
+class EditorPropertySizeFlags : public EditorProperty {
+ GDCLASS(EditorPropertySizeFlags, EditorProperty);
+
+ enum FlagPreset {
+ SIZE_FLAGS_PRESET_FILL,
+ SIZE_FLAGS_PRESET_SHRINK_BEGIN,
+ SIZE_FLAGS_PRESET_SHRINK_CENTER,
+ SIZE_FLAGS_PRESET_SHRINK_END,
+ SIZE_FLAGS_PRESET_CUSTOM,
+ };
+
+ OptionButton *flag_presets = nullptr;
+ CheckBox *flag_expand = nullptr;
+ VBoxContainer *flag_options = nullptr;
+ Vector<CheckBox *> flag_checks;
+
+ bool vertical = false;
+
+ bool keep_selected_preset = false;
+
+ void _preset_selected(int p_which);
+ void _expand_toggled();
+ void _flag_toggled();
+
+protected:
+ virtual void _set_read_only(bool p_read_only) override;
+
+public:
+ void setup(const Vector<String> &p_options, bool p_vertical);
+ virtual void update_property() override;
+ EditorPropertySizeFlags();
+};
+
+class EditorInspectorPluginControl : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginControl, EditorInspectorPlugin);
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual void parse_group(Object *p_object, const String &p_group) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+};
+
+class ControlEditorToolbar : public HBoxContainer {
+ GDCLASS(ControlEditorToolbar, HBoxContainer);
+
+ UndoRedo *undo_redo = nullptr;
+ EditorSelection *editor_selection = nullptr;
+
+ enum MenuOption {
+ ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT,
+ ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT,
+ ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT,
+ ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT,
+ ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT,
+ ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT,
+ ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP,
+ ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM,
+ ANCHORS_AND_OFFSETS_PRESET_CENTER,
+ ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE,
+ ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE,
+ ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE,
+ ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE,
+ ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE,
+ ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE,
+ ANCHORS_AND_OFFSETS_PRESET_WIDE,
+
+ ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO,
+
+ ANCHORS_PRESET_TOP_LEFT,
+ ANCHORS_PRESET_TOP_RIGHT,
+ ANCHORS_PRESET_BOTTOM_LEFT,
+ ANCHORS_PRESET_BOTTOM_RIGHT,
+ ANCHORS_PRESET_CENTER_LEFT,
+ ANCHORS_PRESET_CENTER_RIGHT,
+ ANCHORS_PRESET_CENTER_TOP,
+ ANCHORS_PRESET_CENTER_BOTTOM,
+ ANCHORS_PRESET_CENTER,
+ ANCHORS_PRESET_TOP_WIDE,
+ ANCHORS_PRESET_LEFT_WIDE,
+ ANCHORS_PRESET_RIGHT_WIDE,
+ ANCHORS_PRESET_BOTTOM_WIDE,
+ ANCHORS_PRESET_VCENTER_WIDE,
+ ANCHORS_PRESET_HCENTER_WIDE,
+ ANCHORS_PRESET_WIDE,
+
+ // Offsets Presets are not currently in use.
+ OFFSETS_PRESET_TOP_LEFT,
+ OFFSETS_PRESET_TOP_RIGHT,
+ OFFSETS_PRESET_BOTTOM_LEFT,
+ OFFSETS_PRESET_BOTTOM_RIGHT,
+ OFFSETS_PRESET_CENTER_LEFT,
+ OFFSETS_PRESET_CENTER_RIGHT,
+ OFFSETS_PRESET_CENTER_TOP,
+ OFFSETS_PRESET_CENTER_BOTTOM,
+ OFFSETS_PRESET_CENTER,
+ OFFSETS_PRESET_TOP_WIDE,
+ OFFSETS_PRESET_LEFT_WIDE,
+ OFFSETS_PRESET_RIGHT_WIDE,
+ OFFSETS_PRESET_BOTTOM_WIDE,
+ OFFSETS_PRESET_VCENTER_WIDE,
+ OFFSETS_PRESET_HCENTER_WIDE,
+ OFFSETS_PRESET_WIDE,
+
+ CONTAINERS_H_PRESET_FILL,
+ CONTAINERS_H_PRESET_FILL_EXPAND,
+ CONTAINERS_H_PRESET_SHRINK_BEGIN,
+ CONTAINERS_H_PRESET_SHRINK_CENTER,
+ CONTAINERS_H_PRESET_SHRINK_END,
+ CONTAINERS_V_PRESET_FILL,
+ CONTAINERS_V_PRESET_FILL_EXPAND,
+ CONTAINERS_V_PRESET_SHRINK_BEGIN,
+ CONTAINERS_V_PRESET_SHRINK_CENTER,
+ CONTAINERS_V_PRESET_SHRINK_END,
+ };
+
+ MenuButton *anchor_presets_menu = nullptr;
+ PopupMenu *anchors_popup = nullptr;
+ MenuButton *container_h_presets_menu = nullptr;
+ MenuButton *container_v_presets_menu = nullptr;
+
+ Button *anchor_mode_button = nullptr;
+
+ bool anchors_mode = false;
+
+ void _set_anchors_preset(Control::LayoutPreset p_preset);
+ void _set_anchors_and_offsets_preset(Control::LayoutPreset p_preset);
+ void _set_anchors_and_offsets_to_keep_ratio();
+ void _set_container_h_preset(Control::SizeFlags p_preset);
+ void _set_container_v_preset(Control::SizeFlags p_preset);
+
+ Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor);
+ Vector2 _position_to_anchor(const Control *p_control, Vector2 position);
+
+ void _button_toggle_anchor_mode(bool p_status);
+
+ bool _is_node_locked(const Node *p_node);
+ List<Control *> _get_edited_controls(bool retrieve_locked = false, bool remove_controls_if_parent_in_selection = true);
+ void _popup_callback(int p_op);
+ void _selection_changed();
+
+protected:
+ void _notification(int p_notification);
+
+ static ControlEditorToolbar *singleton;
+
+public:
+ bool is_anchors_mode_enabled() { return anchors_mode; };
+
+ static ControlEditorToolbar *get_singleton() { return singleton; }
+
+ ControlEditorToolbar();
+};
+
+class ControlEditorPlugin : public EditorPlugin {
+ GDCLASS(ControlEditorPlugin, EditorPlugin);
+
+ ControlEditorToolbar *toolbar = nullptr;
+
+public:
+ virtual String get_name() const override { return "Control"; }
+
+ ControlEditorPlugin();
+};
+
+#endif //CONTROL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index fb9f8696fe..79025041d3 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,6 +32,8 @@
#include "canvas_item_editor_plugin.h"
#include "core/io/image_loader.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/separator.h"
#include "scene/resources/particles_material.h"
@@ -222,20 +224,21 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() {
}
void CPUParticles2DEditorPlugin::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- menu->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles2DEditorPlugin::_menu_callback));
- menu->set_icon(epoints->get_theme_icon(SNAME("CPUParticles2D"), SNAME("EditorIcons")));
- file->connect("file_selected", callable_mp(this, &CPUParticles2DEditorPlugin::_file_selected));
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ menu->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles2DEditorPlugin::_menu_callback));
+ menu->set_icon(epoints->get_theme_icon(SNAME("CPUParticles2D"), SNAME("EditorIcons")));
+ file->connect("file_selected", callable_mp(this, &CPUParticles2DEditorPlugin::_file_selected));
+ } break;
}
}
void CPUParticles2DEditorPlugin::_bind_methods() {
}
-CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) {
+CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin() {
particles = nullptr;
- editor = p_node;
- undo_redo = editor->get_undo_redo();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
toolbar = memnew(HBoxContainer);
add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h
index b188df8e96..cc59bc924f 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,12 +31,14 @@
#ifndef CPU_PARTICLES_2D_EDITOR_PLUGIN_H
#define CPU_PARTICLES_2D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/box_container.h"
-#include "scene/gui/file_dialog.h"
+
+class EditorPlugin;
+class SpinBox;
+class EditorFileDialog;
class CPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin);
@@ -53,23 +55,22 @@ class CPUParticles2DEditorPlugin : public EditorPlugin {
EMISSION_MODE_BORDER_DIRECTED
};
- CPUParticles2D *particles;
+ CPUParticles2D *particles = nullptr;
- EditorFileDialog *file;
- EditorNode *editor;
+ EditorFileDialog *file = nullptr;
- HBoxContainer *toolbar;
- MenuButton *menu;
+ HBoxContainer *toolbar = nullptr;
+ MenuButton *menu = nullptr;
- SpinBox *epoints;
+ SpinBox *epoints = nullptr;
- ConfirmationDialog *emission_mask;
- OptionButton *emission_mask_mode;
- CheckBox *emission_colors;
+ ConfirmationDialog *emission_mask = nullptr;
+ OptionButton *emission_mask_mode = nullptr;
+ CheckBox *emission_colors = nullptr;
String source_emission_file;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
void _file_selected(const String &p_file);
void _menu_callback(int p_idx);
void _generate_emission_mask();
@@ -85,7 +86,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- CPUParticles2DEditorPlugin(EditorNode *p_node);
+ CPUParticles2DEditorPlugin();
~CPUParticles2DEditorPlugin();
};
diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
index fc52cd0f99..775c2dbb2a 100644
--- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,7 +30,10 @@
#include "cpu_particles_3d_editor_plugin.h"
+#include "editor/editor_node.h"
#include "editor/plugins/node_3d_editor_plugin.h"
+#include "editor/scene_tree_editor.h"
+#include "scene/gui/menu_button.h"
void CPUParticles3DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
@@ -40,8 +43,10 @@ void CPUParticles3DEditor::_node_removed(Node *p_node) {
}
void CPUParticles3DEditor::_notification(int p_notification) {
- if (p_notification == NOTIFICATION_ENTER_TREE) {
- options->set_icon(get_theme_icon(SNAME("CPUParticles3D"), SNAME("EditorIcons")));
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE: {
+ options->set_icon(get_theme_icon(SNAME("CPUParticles3D"), SNAME("EditorIcons")));
+ } break;
}
}
@@ -119,10 +124,9 @@ void CPUParticles3DEditorPlugin::make_visible(bool p_visible) {
}
}
-CPUParticles3DEditorPlugin::CPUParticles3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+CPUParticles3DEditorPlugin::CPUParticles3DEditorPlugin() {
particles_editor = memnew(CPUParticles3DEditor);
- editor->get_main_control()->add_child(particles_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(particles_editor);
particles_editor->hide();
}
diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.h b/editor/plugins/cpu_particles_3d_editor_plugin.h
index 9dced3ea86..70f2da4b2d 100644
--- a/editor/plugins/cpu_particles_3d_editor_plugin.h
+++ b/editor/plugins/cpu_particles_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -44,7 +44,7 @@ class CPUParticles3DEditor : public GPUParticles3DEditorBase {
};
- CPUParticles3D *node;
+ CPUParticles3D *node = nullptr;
void _menu_option(int);
@@ -65,8 +65,7 @@ public:
class CPUParticles3DEditorPlugin : public EditorPlugin {
GDCLASS(CPUParticles3DEditorPlugin, EditorPlugin);
- CPUParticles3DEditor *particles_editor;
- EditorNode *editor;
+ CPUParticles3DEditor *particles_editor = nullptr;
public:
virtual String get_name() const override { return "CPUParticles3D"; }
@@ -75,7 +74,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- CPUParticles3DEditorPlugin(EditorNode *p_node);
+ CPUParticles3DEditorPlugin();
~CPUParticles3DEditorPlugin();
};
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 43eb6a7ce9..6d1a86765a 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -34,6 +34,7 @@
#include "core/core_string_names.h"
#include "core/input/input.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
CurveEditor::CurveEditor() {
@@ -96,8 +97,10 @@ Size2 CurveEditor::get_minimum_size() const {
}
void CurveEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
- _draw();
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
+ _draw();
+ } break;
}
}
@@ -115,16 +118,16 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
}
switch (mb.get_button_index()) {
- case MOUSE_BUTTON_RIGHT:
+ case MouseButton::RIGHT:
_context_click_pos = mpos;
- open_context_menu(get_global_transform().xform(mpos));
+ open_context_menu(get_screen_position() + mpos);
break;
- case MOUSE_BUTTON_MIDDLE:
+ case MouseButton::MIDDLE:
remove_point(_hover_point);
break;
- case MOUSE_BUTTON_LEFT:
+ case MouseButton::LEFT:
_dragging = true;
break;
default:
@@ -132,7 +135,7 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (!mb.is_pressed() && _dragging && mb.get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (!mb.is_pressed() && _dragging && mb.get_button_index() == MouseButton::LEFT) {
_dragging = false;
if (_has_undo_data) {
UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
@@ -210,7 +213,7 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
tangent = 9999 * (dir.y >= 0 ? 1 : -1);
}
- bool link = !Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ bool link = !Input::get_singleton()->is_key_pressed(Key::SHIFT);
if (_selected_tangent == TANGENT_LEFT) {
curve.set_point_left_tangent(_selected_point, tangent);
@@ -240,7 +243,7 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
const InputEventKey &key = **key_ref;
if (key.is_pressed() && _selected_point != -1) {
- if (key.get_keycode() == KEY_DELETE) {
+ if (key.get_keycode() == Key::KEY_DELETE) {
remove_point(_selected_point);
}
}
@@ -383,7 +386,7 @@ void CurveEditor::open_context_menu(Vector2 pos) {
_context_menu->add_submenu_item(TTR("Load Preset"), _presets_menu->get_name());
- _context_menu->set_size(Size2(0, 0));
+ _context_menu->reset_size();
_context_menu->popup();
}
@@ -460,7 +463,7 @@ void CurveEditor::remove_point(int index) {
Curve::Point p = _curve_ref->get_point(index);
ur.add_do_method(*_curve_ref, "remove_point", index);
- ur.add_undo_method(*_curve_ref, "add_point", p.pos, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode);
+ ur.add_undo_method(*_curve_ref, "add_point", p.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode);
if (index == _selected_point) {
set_selected_point(-1);
@@ -675,11 +678,11 @@ void CurveEditor::_draw() {
// X axis
float y = curve.get_min_value();
Vector2 off(0, font_height - 1);
- draw_string(font, get_view_pos(Vector2(0, y)) + off, "0.0", HALIGN_LEFT, -1, font_size, text_color);
- draw_string(font, get_view_pos(Vector2(0.25, y)) + off, "0.25", HALIGN_LEFT, -1, font_size, text_color);
- draw_string(font, get_view_pos(Vector2(0.5, y)) + off, "0.5", HALIGN_LEFT, -1, font_size, text_color);
- draw_string(font, get_view_pos(Vector2(0.75, y)) + off, "0.75", HALIGN_LEFT, -1, font_size, text_color);
- draw_string(font, get_view_pos(Vector2(1, y)) + off, "1.0", HALIGN_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(0, y)) + off, "0.0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(0.25, y)) + off, "0.25", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(0.5, y)) + off, "0.5", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(0.75, y)) + off, "0.75", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(1, y)) + off, "1.0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
}
{
@@ -688,9 +691,9 @@ void CurveEditor::_draw() {
float m1 = 0.5 * (curve.get_min_value() + curve.get_max_value());
float m2 = curve.get_max_value();
Vector2 off(1, -1);
- draw_string(font, get_view_pos(Vector2(0, m0)) + off, String::num(m0, 2), HALIGN_LEFT, -1, font_size, text_color);
- draw_string(font, get_view_pos(Vector2(0, m1)) + off, String::num(m1, 2), HALIGN_LEFT, -1, font_size, text_color);
- draw_string(font, get_view_pos(Vector2(0, m2)) + off, String::num(m2, 3), HALIGN_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(0, m0)) + off, String::num(m0, 2), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(0, m1)) + off, String::num(m1, 2), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
+ draw_string(font, get_view_pos(Vector2(0, m2)) + off, String::num(m2, 3), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
}
// Draw tangents for current point
@@ -750,10 +753,10 @@ void CurveEditor::_draw() {
if (_selected_point > 0 && _selected_point + 1 < curve.get_point_count()) {
text_color.a *= 0.4;
- draw_string(font, Vector2(50 * EDSCALE, font_height), TTR("Hold Shift to edit tangents individually"), HALIGN_LEFT, -1, font_size, text_color);
+ draw_string(font, Vector2(50 * EDSCALE, font_height), TTR("Hold Shift to edit tangents individually"), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
} else if (curve.get_point_count() == 0) {
text_color.a *= 0.4;
- draw_string(font, Vector2(50 * EDSCALE, font_height), TTR("Right click to add point"), HALIGN_LEFT, -1, font_size, text_color);
+ draw_string(font, Vector2(50 * EDSCALE, font_height), TTR("Right click to add point"), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, text_color);
}
}
@@ -773,7 +776,7 @@ void EditorInspectorPluginCurve::parse_begin(Object *p_object) {
add_custom_control(editor);
}
-CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) {
+CurveEditorPlugin::CurveEditorPlugin() {
Ref<EditorInspectorPluginCurve> curve_plugin;
curve_plugin.instantiate();
EditorInspector::add_inspector_plugin(curve_plugin);
@@ -803,11 +806,8 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons
im.create(thumbnail_size, thumbnail_size / 2, false, Image::FORMAT_RGBA8);
Color bg_color(0.1, 0.1, 0.1, 1.0);
- for (int i = 0; i < thumbnail_size; i++) {
- for (int j = 0; j < thumbnail_size / 2; j++) {
- im.set_pixel(i, j, bg_color);
- }
- }
+
+ im.fill(bg_color);
Color line_color(0.8, 0.8, 0.8, 1.0);
float range_y = curve.get_max_value() - curve.get_min_value();
diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h
index c351f6ebe9..5cf3b16a06 100644
--- a/editor/plugins/curve_editor_plugin.h
+++ b/editor/plugins/curve_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef CURVE_EDITOR_PLUGIN_H
#define CURVE_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_resource_preview.h"
#include "scene/resources/curve.h"
@@ -100,8 +99,8 @@ private:
Transform2D _world_to_view;
Ref<Curve> _curve_ref;
- PopupMenu *_context_menu;
- PopupMenu *_presets_menu;
+ PopupMenu *_context_menu = nullptr;
+ PopupMenu *_presets_menu = nullptr;
Array _undo_data;
bool _has_undo_data;
@@ -129,7 +128,7 @@ class CurveEditorPlugin : public EditorPlugin {
GDCLASS(CurveEditorPlugin, EditorPlugin);
public:
- CurveEditorPlugin(EditorNode *p_node);
+ CurveEditorPlugin();
virtual String get_name() const override { return "Curve"; }
};
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index cc916aad8b..8ea50c4529 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -36,15 +36,16 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/fileserver/editor_file_server.h"
+#include "editor/plugins/script_editor_plugin.h"
#include "scene/gui/menu_button.h"
-DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_debug_menu) {
+DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
EditorDebuggerServer::initialize();
- ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11);
- ED_SHORTCUT("debugger/step_over", TTR("Step Over"), KEY_F10);
+ ED_SHORTCUT("debugger/step_into", TTR("Step Into"), Key::F11);
+ ED_SHORTCUT("debugger/step_over", TTR("Step Over"), Key::F10);
ED_SHORTCUT("debugger/break", TTR("Break"));
- ED_SHORTCUT("debugger/continue", TTR("Continue"), KEY_F12);
+ ED_SHORTCUT("debugger/continue", TTR("Continue"), Key::F12);
ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open"));
ED_SHORTCUT("debugger/debug_with_external_editor", TTR("Debug with External Editor"));
@@ -54,7 +55,7 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d
EditorDebuggerNode *debugger = memnew(EditorDebuggerNode);
Button *db = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Debugger"), debugger);
// Add separation for the warning/error icon that is displayed later.
- db->add_theme_constant_override("hseparation", 6 * EDSCALE);
+ db->add_theme_constant_override("h_separation", 6 * EDSCALE);
debugger->set_tool_button(db);
// Main editor debug menu.
@@ -62,30 +63,24 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d
PopupMenu *p = debug_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
- p->set_item_tooltip(
- p->get_item_count() - 1,
+ p->set_item_tooltip(-1,
TTR("When this option is enabled, using one-click deploy will make the executable attempt to connect to this computer's IP so the running project can be debugged.\nThis option is intended to be used for remote debugging (typically with a mobile device).\nYou don't need to enable it to use the GDScript debugger locally."));
p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network Filesystem")), RUN_FILE_SERVER);
- p->set_item_tooltip(
- p->get_item_count() - 1,
+ p->set_item_tooltip(-1,
TTR("When this option is enabled, using one-click deploy for Android will only export an executable without the project data.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploying will use the USB cable for faster performance. This option speeds up testing for projects with large assets."));
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
- p->set_item_tooltip(
- p->get_item_count() - 1,
+ p->set_item_tooltip(-1,
TTR("When this option is enabled, collision shapes and raycast nodes (for 2D and 3D) will be visible in the running project."));
p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
- p->set_item_tooltip(
- p->get_item_count() - 1,
+ p->set_item_tooltip(-1,
TTR("When this option is enabled, navigation meshes and polygons will be visible in the running project."));
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
- p->set_item_tooltip(
- p->get_item_count() - 1,
+ p->set_item_tooltip(-1,
TTR("When this option is enabled, any changes made to the scene in the editor will be replicated in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Synchronize Script Changes")), RUN_RELOAD_SCRIPTS);
- p->set_item_tooltip(
- p->get_item_count() - 1,
+ p->set_item_tooltip(-1,
TTR("When this option is enabled, any script that is saved will be reloaded in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
// Multi-instance, start/stop
@@ -176,8 +171,10 @@ void DebuggerEditorPlugin::_menu_option(int p_option) {
}
void DebuggerEditorPlugin::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- _update_debug_options();
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ _update_debug_options();
+ } break;
}
}
diff --git a/editor/plugins/debugger_editor_plugin.h b/editor/plugins/debugger_editor_plugin.h
index a6fab01c29..10e1a27933 100644
--- a/editor/plugins/debugger_editor_plugin.h
+++ b/editor/plugins/debugger_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,7 +33,6 @@
#include "editor/editor_plugin.h"
-class EditorNode;
class EditorFileServer;
class MenuButton;
class PopupMenu;
@@ -42,9 +41,9 @@ class DebuggerEditorPlugin : public EditorPlugin {
GDCLASS(DebuggerEditorPlugin, EditorPlugin);
private:
- MenuButton *debug_menu;
- EditorFileServer *file_server;
- PopupMenu *instances_menu;
+ MenuButton *debug_menu = nullptr;
+ EditorFileServer *file_server = nullptr;
+ PopupMenu *instances_menu = nullptr;
enum MenuOptions {
RUN_FILE_SERVER,
@@ -64,7 +63,7 @@ public:
virtual String get_name() const override { return "Debugger"; }
bool has_main_screen() const override { return false; }
- DebuggerEditorPlugin(EditorNode *p_node, MenuButton *p_menu);
+ DebuggerEditorPlugin(MenuButton *p_menu);
~DebuggerEditorPlugin();
};
diff --git a/editor/plugins/editor_debugger_plugin.cpp b/editor/plugins/editor_debugger_plugin.cpp
index 5f3b11ac42..4ce3d7cfd5 100644
--- a/editor/plugins/editor_debugger_plugin.cpp
+++ b/editor/plugins/editor_debugger_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
diff --git a/editor/plugins/editor_debugger_plugin.h b/editor/plugins/editor_debugger_plugin.h
index 5995d790c5..b602c36912 100644
--- a/editor/plugins/editor_debugger_plugin.h
+++ b/editor/plugins/editor_debugger_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 4cb2c0a76b..80fc1c64d0 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,10 +30,11 @@
#include "editor_preview_plugins.h"
+#include "core/config/project_settings.h"
#include "core/io/file_access_memory.h"
#include "core/io/resource_loader.h"
#include "core/os/os.h"
-#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "scene/resources/bit_map.h"
@@ -78,7 +79,7 @@ bool EditorTexturePreviewPlugin::generate_small_preview_automatically() const {
return true;
}
-Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorTexturePreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
Ref<Image> img;
Ref<AtlasTexture> atex = p_from;
if (atex.is_valid()) {
@@ -144,7 +145,7 @@ bool EditorImagePreviewPlugin::handles(const String &p_type) const {
return p_type == "Image";
}
-Ref<Texture2D> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorImagePreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
Ref<Image> img = p_from;
if (img.is_null() || img->is_empty()) {
@@ -188,12 +189,12 @@ bool EditorImagePreviewPlugin::generate_small_preview_automatically() const {
}
////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////
+
bool EditorBitmapPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "BitMap");
}
-Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
Ref<BitMap> bm = p_from;
if (bm->get_size() == Size2()) {
@@ -260,7 +261,7 @@ bool EditorPackedScenePreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "PackedScene");
}
-Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
return generate_from_path(p_from->get_path(), p_size);
}
@@ -297,37 +298,34 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
//////////////////////////////////////////////////////////////////
-void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) {
- preview_done.set();
+void EditorMaterialPreviewPlugin::_generate_frame_started() {
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
+
+ RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_preview_done));
}
-void EditorMaterialPreviewPlugin::_bind_methods() {
- ClassDB::bind_method("_preview_done", &EditorMaterialPreviewPlugin::_preview_done);
+void EditorMaterialPreviewPlugin::_preview_done() {
+ preview_done.post();
}
bool EditorMaterialPreviewPlugin::handles(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Material"); //any material
+ return ClassDB::is_parent_class(p_type, "Material"); // Any material.
}
bool EditorMaterialPreviewPlugin::generate_small_preview_automatically() const {
return true;
}
-Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
Ref<Material> material = p_from;
ERR_FAIL_COND_V(material.is_null(), Ref<Texture2D>());
if (material->get_shader_mode() == Shader::MODE_SPATIAL) {
RS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
- RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_generate_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT);
- preview_done.clear();
- RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant());
-
- while (!preview_done.is_set()) {
- OS::get_singleton()->delay_usec(10);
- }
+ preview_done.wait();
Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
RS::get_singleton()->mesh_surface_set_material(sphere, 0, RID());
@@ -465,22 +463,18 @@ EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
-static bool _is_text_char(char32_t c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
-}
-
bool EditorScriptPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "Script");
}
-Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
Ref<Script> scr = p_from;
if (scr.is_null()) {
return Ref<Texture2D>();
}
String code = scr->get_source_code().strip_edges();
- if (code == "") {
+ if (code.is_empty()) {
return Ref<Texture2D>();
}
@@ -517,11 +511,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
}
bg_color.a = MAX(bg_color.a, 0.2); // some background
- for (int i = 0; i < thumbnail_size; i++) {
- for (int j = 0; j < thumbnail_size; j++) {
- img->set_pixel(i, j, bg_color);
- }
- }
+ img->fill(bg_color);
const int x0 = thumbnail_size / 8;
const int y0 = thumbnail_size / 8;
@@ -545,15 +535,15 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
if (in_comment) {
color = comment_color;
} else {
- if (c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t')) {
+ if (is_symbol(c)) {
//make symbol a little visible
color = symbol_color;
in_control_flow_keyword = false;
in_keyword = false;
- } else if (!prev_is_text && _is_text_char(c)) {
+ } else if (!prev_is_text && is_ascii_identifier_char(c)) {
int pos = i;
- while (_is_text_char(code[pos])) {
+ while (is_ascii_identifier_char(code[pos])) {
pos++;
}
String word = code.substr(i, pos - i);
@@ -563,7 +553,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
in_keyword = true;
}
- } else if (!_is_text_char(c)) {
+ } else if (!is_ascii_identifier_char(c)) {
in_keyword = false;
}
@@ -578,7 +568,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
img->set_pixel(col, y0 + line * 2, bg_color.blend(ul));
img->set_pixel(col, y0 + line * 2 + 1, color);
- prev_is_text = _is_text_char(c);
+ prev_is_text = is_ascii_identifier_char(c);
}
col++;
} else {
@@ -619,7 +609,7 @@ bool EditorAudioStreamPreviewPlugin::handles(const String &p_type) const {
return ClassDB::is_parent_class(p_type, "AudioStream");
}
-Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
Ref<AudioStream> stream = p_from;
ERR_FAIL_COND_V(stream.is_null(), Ref<Texture2D>());
@@ -699,19 +689,21 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
-void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) {
- preview_done.set();
+void EditorMeshPreviewPlugin::_generate_frame_started() {
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
+
+ RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_preview_done));
}
-void EditorMeshPreviewPlugin::_bind_methods() {
- ClassDB::bind_method("_preview_done", &EditorMeshPreviewPlugin::_preview_done);
+void EditorMeshPreviewPlugin::_preview_done() {
+ preview_done.post();
}
bool EditorMeshPreviewPlugin::handles(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Mesh"); //any Mesh
+ return ClassDB::is_parent_class(p_type, "Mesh"); // Any mesh.
}
-Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorMeshPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
Ref<Mesh> mesh = p_from;
ERR_FAIL_COND_V(mesh.is_null(), Ref<Texture2D>());
@@ -735,14 +727,9 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
xform.origin.z -= rot_aabb.size.z * 2;
RS::get_singleton()->instance_set_transform(mesh_instance, xform);
- RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
-
- preview_done.clear();
- RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant());
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_generate_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT);
- while (!preview_done.is_set()) {
- OS::get_singleton()->delay_usec(10);
- }
+ preview_done.wait();
Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture);
ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>());
@@ -814,12 +801,14 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
-void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) {
- preview_done.set();
+void EditorFontPreviewPlugin::_generate_frame_started() {
+ RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
+
+ RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_preview_done));
}
-void EditorFontPreviewPlugin::_bind_methods() {
- ClassDB::bind_method("_preview_done", &EditorFontPreviewPlugin::_preview_done);
+void EditorFontPreviewPlugin::_preview_done() {
+ preview_done.post();
}
bool EditorFontPreviewPlugin::handles(const String &p_type) const {
@@ -827,7 +816,8 @@ bool EditorFontPreviewPlugin::handles(const String &p_type) const {
}
Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
- RES res = ResourceLoader::load(p_path);
+ Ref<Resource> res = ResourceLoader::load(p_path);
+ ERR_FAIL_COND_V(res.is_null(), Ref<Texture2D>());
Ref<Font> sampled_font;
if (res->is_class("Font")) {
sampled_font = res->duplicate();
@@ -855,15 +845,13 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
Ref<Font> font = sampled_font;
- font->draw_string(canvas_item, pos, sample, HALIGN_LEFT, -1.f, 50, Color(1, 1, 1));
+ const Color c = GLOBAL_GET("rendering/environment/defaults/default_clear_color");
+ const float fg = c.get_luminance() < 0.5 ? 1.0 : 0.0;
+ font->draw_string(canvas_item, pos, sample, HORIZONTAL_ALIGNMENT_LEFT, -1.f, 50, Color(fg, fg, fg));
- preview_done.clear();
- RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture
- RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant());
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT);
- while (!preview_done.is_set()) {
- OS::get_singleton()->delay_usec(10);
- }
+ preview_done.wait();
RS::get_singleton()->canvas_item_clear(canvas_item);
@@ -889,7 +877,7 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
return ptex;
}
-Ref<Texture2D> EditorFontPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const {
+Ref<Texture2D> EditorFontPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
String path = p_from->get_path();
if (!FileAccess::exists(path)) {
return Ref<Texture2D>();
@@ -916,3 +904,34 @@ EditorFontPreviewPlugin::~EditorFontPreviewPlugin() {
RS::get_singleton()->free(canvas);
RS::get_singleton()->free(viewport);
}
+
+////////////////////////////////////////////////////////////////////////////
+
+static const real_t GRADIENT_PREVIEW_TEXTURE_SCALE_FACTOR = 4.0;
+
+bool EditorGradientPreviewPlugin::handles(const String &p_type) const {
+ return ClassDB::is_parent_class(p_type, "Gradient");
+}
+
+bool EditorGradientPreviewPlugin::generate_small_preview_automatically() const {
+ return true;
+}
+
+Ref<Texture2D> EditorGradientPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size) const {
+ Ref<Gradient> gradient = p_from;
+ if (gradient.is_valid()) {
+ Ref<GradientTexture1D> ptex;
+ ptex.instantiate();
+ ptex->set_width(p_size.width * GRADIENT_PREVIEW_TEXTURE_SCALE_FACTOR * EDSCALE);
+ ptex->set_gradient(gradient);
+
+ Ref<ImageTexture> itex;
+ itex.instantiate();
+ itex->create_from_image(ptex->get_image());
+ return itex;
+ }
+ return Ref<Texture2D>();
+}
+
+EditorGradientPreviewPlugin::EditorGradientPreviewPlugin() {
+}
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index 091feae5fb..f548683b70 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,9 +31,8 @@
#ifndef EDITORPREVIEWPLUGINS_H
#define EDITORPREVIEWPLUGINS_H
-#include "editor/editor_resource_preview.h"
-
#include "core/templates/safe_refcount.h"
+#include "editor/editor_resource_preview.h"
void post_process_preview(Ref<Image> p_image);
@@ -43,7 +42,7 @@ class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const override;
virtual bool generate_small_preview_automatically() const override;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorTexturePreviewPlugin();
};
@@ -54,7 +53,7 @@ class EditorImagePreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const override;
virtual bool generate_small_preview_automatically() const override;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorImagePreviewPlugin();
};
@@ -65,7 +64,7 @@ class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const override;
virtual bool generate_small_preview_automatically() const override;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorBitmapPreviewPlugin();
};
@@ -73,7 +72,7 @@ public:
class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const;
virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const;
EditorPackedScenePreviewPlugin();
@@ -92,17 +91,15 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
- mutable SafeFlag preview_done;
-
- void _preview_done(const Variant &p_udata);
+ Semaphore preview_done;
-protected:
- static void _bind_methods();
+ void _generate_frame_started();
+ void _preview_done();
public:
virtual bool handles(const String &p_type) const override;
virtual bool generate_small_preview_automatically() const override;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorMaterialPreviewPlugin();
~EditorMaterialPreviewPlugin();
@@ -111,7 +108,7 @@ public:
class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const;
EditorScriptPreviewPlugin();
};
@@ -119,7 +116,7 @@ public:
class EditorAudioStreamPreviewPlugin : public EditorResourcePreviewGenerator {
public:
virtual bool handles(const String &p_type) const;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const;
EditorAudioStreamPreviewPlugin();
};
@@ -136,16 +133,14 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
- mutable SafeFlag preview_done;
+ Semaphore preview_done;
- void _preview_done(const Variant &p_udata);
-
-protected:
- static void _bind_methods();
+ void _generate_frame_started();
+ void _preview_done();
public:
virtual bool handles(const String &p_type) const override;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorMeshPreviewPlugin();
~EditorMeshPreviewPlugin();
@@ -158,16 +153,14 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator {
RID viewport_texture;
RID canvas;
RID canvas_item;
- mutable SafeFlag preview_done;
-
- void _preview_done(const Variant &p_udata);
+ Semaphore preview_done;
-protected:
- static void _bind_methods();
+ void _generate_frame_started();
+ void _preview_done();
public:
virtual bool handles(const String &p_type) const override;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const override;
EditorFontPreviewPlugin();
@@ -177,18 +170,27 @@ public:
class EditorTileMapPatternPreviewPlugin : public EditorResourcePreviewGenerator {
GDCLASS(EditorTileMapPatternPreviewPlugin, EditorResourcePreviewGenerator);
- mutable SafeFlag preview_done;
-
- void _preview_done(const Variant &p_udata);
+ Semaphore preview_done;
-protected:
- static void _bind_methods();
+ void _generate_frame_started();
+ void _preview_done();
public:
virtual bool handles(const String &p_type) const override;
- virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
EditorTileMapPatternPreviewPlugin();
~EditorTileMapPatternPreviewPlugin();
};
+
+class EditorGradientPreviewPlugin : public EditorResourcePreviewGenerator {
+ GDCLASS(EditorGradientPreviewPlugin, EditorResourcePreviewGenerator);
+
+public:
+ virtual bool handles(const String &p_type) const override;
+ virtual bool generate_small_preview_automatically() const override;
+ virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override;
+
+ EditorGradientPreviewPlugin();
+};
#endif // EDITORPREVIEWPLUGINS_H
diff --git a/editor/plugins/font_editor_plugin.cpp b/editor/plugins/font_editor_plugin.cpp
index 52fb5b69ea..b9de621bcb 100644
--- a/editor/plugins/font_editor_plugin.cpp
+++ b/editor/plugins/font_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,14 +33,16 @@
#include "editor/editor_scale.h"
void FontDataPreview::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
- Color text_color = get_theme_color(SNAME("font_color"), SNAME("Label"));
- Color line_color = text_color;
- line_color.a *= 0.6;
- Vector2 pos = (get_size() - line->get_size()) / 2;
- line->draw(get_canvas_item(), pos, text_color);
- draw_line(Vector2(0, pos.y + line->get_line_ascent()), Vector2(pos.x - 5, pos.y + line->get_line_ascent()), line_color);
- draw_line(Vector2(pos.x + line->get_size().x + 5, pos.y + line->get_line_ascent()), Vector2(get_size().x, pos.y + line->get_line_ascent()), line_color);
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
+ Color text_color = get_theme_color(SNAME("font_color"), SNAME("Label"));
+ Color line_color = text_color;
+ line_color.a *= 0.6;
+ Vector2 pos = (get_size() - line->get_size()) / 2;
+ line->draw(get_canvas_item(), pos, text_color);
+ draw_line(Vector2(0, pos.y + line->get_line_ascent()), Vector2(pos.x - 5, pos.y + line->get_line_ascent()), line_color);
+ draw_line(Vector2(pos.x + line->get_size().x + 5, pos.y + line->get_line_ascent()), Vector2(get_size().x, pos.y + line->get_line_ascent()), line_color);
+ } break;
}
}
@@ -97,7 +99,7 @@ bool EditorInspectorPluginFont::parse_property(Object *p_object, const Variant::
/*************************************************************************/
-FontEditorPlugin::FontEditorPlugin(EditorNode *p_node) {
+FontEditorPlugin::FontEditorPlugin() {
Ref<EditorInspectorPluginFont> fd_plugin;
fd_plugin.instantiate();
EditorInspector::add_inspector_plugin(fd_plugin);
diff --git a/editor/plugins/font_editor_plugin.h b/editor/plugins/font_editor_plugin.h
index 3530815872..3f0700d880 100644
--- a/editor/plugins/font_editor_plugin.h
+++ b/editor/plugins/font_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef FONT_EDITOR_PLUGIN_H
#define FONT_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/resources/font.h"
#include "scene/resources/text_line.h"
@@ -70,7 +69,7 @@ class FontEditorPlugin : public EditorPlugin {
GDCLASS(FontEditorPlugin, EditorPlugin);
public:
- FontEditorPlugin(EditorNode *p_node);
+ FontEditorPlugin();
virtual String get_name() const override { return "Font"; }
};
diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h
new file mode 100644
index 0000000000..8ed72b1c42
--- /dev/null
+++ b/editor/plugins/gdextension_export_plugin.h
@@ -0,0 +1,138 @@
+/*************************************************************************/
+/* gdextension_export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 GDEXTENSION_EXPORT_PLUGIN_H
+#define GDEXTENSION_EXPORT_PLUGIN_H
+
+#include "editor/editor_export.h"
+
+class GDExtensionExportPlugin : public EditorExportPlugin {
+protected:
+ virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features);
+};
+
+void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) {
+ if (p_type != "NativeExtension") {
+ return;
+ }
+
+ Ref<ConfigFile> config;
+ config.instantiate();
+
+ Error err = config->load(p_path);
+
+ if (err != OK) {
+ return;
+ }
+
+ if (!config->has_section_key("configuration", "entry_symbol")) {
+ return;
+ }
+
+ String entry_symbol = config->get_value("configuration", "entry_symbol");
+
+ List<String> libraries;
+
+ config->get_section_keys("libraries", &libraries);
+
+ for (const String &E : libraries) {
+ Vector<String> tags = E.split(".");
+ bool all_tags_met = true;
+ for (int i = 0; i < tags.size(); i++) {
+ String tag = tags[i].strip_edges();
+ if (!p_features.has(tag)) {
+ all_tags_met = false;
+ break;
+ }
+ }
+
+ if (all_tags_met) {
+ String library_path = config->get_value("libraries", E);
+ if (!library_path.begins_with("res://")) {
+ print_line("Skipping export of out-of-project library " + library_path);
+ continue;
+ }
+ add_shared_object(library_path, tags);
+
+ if (p_features.has("iOS") && (library_path.ends_with(".a") || library_path.ends_with(".xcframework"))) {
+ String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n"
+ "extern void add_ios_init_callback(void (*cb)());\n"
+ "\n"
+ "extern \"C\" void $ENTRY();\n"
+ "void $ENTRY_init() {\n"
+ " if (&$ENTRY) register_dynamic_symbol((char *)\"$ENTRY\", (void *)$ENTRY);\n"
+ "}\n"
+ "struct $ENTRY_struct {\n"
+ " $ENTRY_struct() {\n"
+ " add_ios_init_callback($ENTRY_init);\n"
+ " }\n"
+ "};\n"
+ "$ENTRY_struct $ENTRY_struct_instance;\n\n";
+ additional_code = additional_code.replace("$ENTRY", entry_symbol);
+ add_ios_cpp_code(additional_code);
+
+ String linker_flags = "-Wl,-U,_" + entry_symbol;
+ add_ios_linker_flags(linker_flags);
+ }
+ break;
+ }
+ }
+
+ List<String> dependencies;
+
+ config->get_section_keys("dependencies", &dependencies);
+ for (const String &E : libraries) {
+ Vector<String> tags = E.split(".");
+ bool all_tags_met = true;
+ for (int i = 0; i < tags.size(); i++) {
+ String tag = tags[i].strip_edges();
+ if (!p_features.has(tag)) {
+ all_tags_met = false;
+ break;
+ }
+ }
+
+ if (all_tags_met) {
+ Dictionary dependency = config->get_value("dependencies", E);
+ for (const Variant *key = dependency.next(nullptr); key; key = dependency.next(key)) {
+ String library_path = *key;
+ String target_path = dependency[*key];
+ if (!library_path.begins_with("res://")) {
+ print_line("Skipping export of out-of-project library " + library_path);
+ continue;
+ }
+ add_shared_object(library_path, tags, target_path);
+ }
+ break;
+ }
+ }
+}
+
+#endif // GDEXTENSION_EXPORT_PLUGIN_H
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index 44c789b145..72caa15e9c 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,6 +32,9 @@
#include "canvas_item_editor_plugin.h"
#include "core/io/image_loader.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+#include "editor/scene_tree_dock.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/separator.h"
#include "scene/resources/particles_material.h"
@@ -57,6 +60,27 @@ void GPUParticles2DEditorPlugin::_file_selected(const String &p_file) {
emission_mask->popup_centered();
}
+void GPUParticles2DEditorPlugin::_selection_changed() {
+ List<Node *> selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list();
+
+ if (selected_particles.is_empty() && selected_nodes.is_empty()) {
+ return;
+ }
+
+ for (GPUParticles2D *SP : selected_particles) {
+ SP->set_show_visibility_rect(false);
+ }
+ selected_particles.clear();
+
+ for (Node *P : selected_nodes) {
+ GPUParticles2D *selected_particle = Object::cast_to<GPUParticles2D>(P);
+ if (selected_particle != nullptr) {
+ selected_particle->set_show_visibility_rect(true);
+ selected_particles.push_back(selected_particle);
+ }
+ }
+}
+
void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
switch (p_idx) {
case MENU_GENERATE_VISIBILITY_RECT: {
@@ -89,9 +113,9 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles2D"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", particles, cpu_particles, true, false);
+ ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", particles, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, particles, false, false);
+ ur->add_undo_method(SceneTreeDock::get_singleton(), "replace_node", cpu_particles, particles, false, false);
ur->add_undo_reference(particles);
ur->commit_action();
@@ -266,7 +290,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
{
uint8_t *tw = texdata.ptrw();
- float *twf = (float *)tw;
+ float *twf = reinterpret_cast<float *>(tw);
for (int i = 0; i < vpc; i++) {
twf[i * 2 + 0] = valid_positions[i].x;
twf[i * 2 + 1] = valid_positions[i].y;
@@ -310,7 +334,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
{
uint8_t *tw = normdata.ptrw();
- float *twf = (float *)tw;
+ float *twf = reinterpret_cast<float *>(tw);
for (int i = 0; i < vpc; i++) {
twf[i * 2 + 0] = valid_normals[i].x;
twf[i * 2 + 1] = valid_normals[i].y;
@@ -330,20 +354,22 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
void GPUParticles2DEditorPlugin::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- menu->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles2DEditorPlugin::_menu_callback));
- menu->set_icon(menu->get_theme_icon(SNAME("GPUParticles2D"), SNAME("EditorIcons")));
- file->connect("file_selected", callable_mp(this, &GPUParticles2DEditorPlugin::_file_selected));
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ menu->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles2DEditorPlugin::_menu_callback));
+ menu->set_icon(menu->get_theme_icon(SNAME("GPUParticles2D"), SNAME("EditorIcons")));
+ file->connect("file_selected", callable_mp(this, &GPUParticles2DEditorPlugin::_file_selected));
+ EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", callable_mp(this, &GPUParticles2DEditorPlugin::_selection_changed));
+ } break;
}
}
void GPUParticles2DEditorPlugin::_bind_methods() {
}
-GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin(EditorNode *p_node) {
+GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin() {
particles = nullptr;
- editor = p_node;
- undo_redo = editor->get_undo_redo();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
toolbar = memnew(HBoxContainer);
add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h
index 0b2028b745..75f68617d1 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,12 +31,13 @@
#ifndef PARTICLES_2D_EDITOR_PLUGIN_H
#define PARTICLES_2D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/gpu_particles_2d.h"
#include "scene/gui/box_container.h"
-#include "scene/gui/file_dialog.h"
+#include "scene/gui/spin_box.h"
+
+class EditorFileDialog;
class GPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin);
@@ -55,30 +56,31 @@ class GPUParticles2DEditorPlugin : public EditorPlugin {
EMISSION_MODE_BORDER_DIRECTED
};
- GPUParticles2D *particles;
+ GPUParticles2D *particles = nullptr;
+ List<GPUParticles2D *> selected_particles;
- EditorFileDialog *file;
- EditorNode *editor;
+ EditorFileDialog *file = nullptr;
- HBoxContainer *toolbar;
- MenuButton *menu;
+ HBoxContainer *toolbar = nullptr;
+ MenuButton *menu = nullptr;
- SpinBox *epoints;
+ SpinBox *epoints = nullptr;
- ConfirmationDialog *generate_visibility_rect;
- SpinBox *generate_seconds;
+ ConfirmationDialog *generate_visibility_rect = nullptr;
+ SpinBox *generate_seconds = nullptr;
- ConfirmationDialog *emission_mask;
- OptionButton *emission_mask_mode;
- CheckBox *emission_colors;
+ ConfirmationDialog *emission_mask = nullptr;
+ OptionButton *emission_mask_mode = nullptr;
+ CheckBox *emission_colors = nullptr;
String source_emission_file;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
void _file_selected(const String &p_file);
void _menu_callback(int p_idx);
void _generate_visibility_rect();
void _generate_emission_mask();
+ void _selection_changed();
protected:
void _notification(int p_what);
@@ -91,7 +93,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- GPUParticles2DEditorPlugin(EditorNode *p_node);
+ GPUParticles2DEditorPlugin();
~GPUParticles2DEditorPlugin();
};
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 5ac58795d1..4b1081ed92 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,9 @@
#include "gpu_particles_3d_editor_plugin.h"
#include "core/io/resource_loader.h"
+#include "editor/editor_node.h"
#include "editor/plugins/node_3d_editor_plugin.h"
+#include "editor/scene_tree_dock.h"
#include "scene/3d/cpu_particles_3d.h"
#include "scene/resources/particles_material.h"
@@ -164,20 +166,20 @@ void GPUParticles3DEditorBase::_node_selected(const NodePath &p_path) {
return;
}
- VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sel);
- if (!vi) {
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(sel);
+ if (!mi || mi->get_mesh().is_null()) {
EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain geometry."), sel->get_name()));
return;
}
- geometry = vi->get_faces(VisualInstance3D::FACES_SOLID);
+ geometry = mi->get_mesh()->get_faces();
if (geometry.size() == 0) {
EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain face geometry."), sel->get_name()));
return;
}
- Transform3D geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform();
+ Transform3D geom_xform = base_node->get_global_transform().affine_inverse() * mi->get_global_transform();
int gc = geometry.size();
Face3 *w = geometry.ptrw();
@@ -229,9 +231,11 @@ void GPUParticles3DEditor::_node_removed(Node *p_node) {
}
void GPUParticles3DEditor::_notification(int p_notification) {
- if (p_notification == NOTIFICATION_ENTER_TREE) {
- options->set_icon(options->get_popup()->get_theme_icon(SNAME("GPUParticles3D"), SNAME("EditorIcons")));
- get_tree()->connect("node_removed", callable_mp(this, &GPUParticles3DEditor::_node_removed));
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE: {
+ options->set_icon(options->get_popup()->get_theme_icon(SNAME("GPUParticles3D"), SNAME("EditorIcons")));
+ get_tree()->connect("node_removed", callable_mp(this, &GPUParticles3DEditor::_node_removed));
+ } break;
}
}
@@ -269,9 +273,9 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles3D"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, cpu_particles, true, false);
+ ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, node, false, false);
+ ur->add_undo_method(SceneTreeDock::get_singleton(), "replace_node", cpu_particles, node, false, false);
ur->add_undo_reference(node);
ur->commit_action();
@@ -350,7 +354,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
uint8_t *iw = point_img.ptrw();
memset(iw, 0, w * h * 3 * sizeof(float));
const Vector3 *r = points.ptr();
- float *wf = (float *)iw;
+ float *wf = reinterpret_cast<float *>(iw);
for (int i = 0; i < point_count; i++) {
wf[i * 3 + 0] = r[i].x;
wf[i * 3 + 1] = r[i].y;
@@ -379,7 +383,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
uint8_t *iw = point_img2.ptrw();
memset(iw, 0, w * h * 3 * sizeof(float));
const Vector3 *r = normals.ptr();
- float *wf = (float *)iw;
+ float *wf = reinterpret_cast<float *>(iw);
for (int i = 0; i < point_count; i++) {
wf[i * 3 + 0] = r[i].x;
wf[i * 3 + 1] = r[i].y;
@@ -455,10 +459,9 @@ void GPUParticles3DEditorPlugin::make_visible(bool p_visible) {
}
}
-GPUParticles3DEditorPlugin::GPUParticles3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+GPUParticles3DEditorPlugin::GPUParticles3DEditorPlugin() {
particles_editor = memnew(GPUParticles3DEditor);
- editor->get_main_control()->add_child(particles_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(particles_editor);
particles_editor->hide();
}
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.h b/editor/plugins/gpu_particles_3d_editor_plugin.h
index bd10895459..6ba6d102ef 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.h
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,30 +31,31 @@
#ifndef PARTICLES_EDITOR_PLUGIN_H
#define PARTICLES_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/gui/spin_box.h"
+class SceneTreeDialog;
+
class GPUParticles3DEditorBase : public Control {
GDCLASS(GPUParticles3DEditorBase, Control);
protected:
- Node3D *base_node;
- Panel *panel;
- MenuButton *options;
- HBoxContainer *particles_editor_hb;
+ Node3D *base_node = nullptr;
+ Panel *panel = nullptr;
+ MenuButton *options = nullptr;
+ HBoxContainer *particles_editor_hb = nullptr;
- SceneTreeDialog *emission_tree_dialog;
+ SceneTreeDialog *emission_tree_dialog = nullptr;
- ConfirmationDialog *emission_dialog;
- SpinBox *emission_amount;
- OptionButton *emission_fill;
+ ConfirmationDialog *emission_dialog = nullptr;
+ SpinBox *emission_amount = nullptr;
+ OptionButton *emission_fill = nullptr;
Vector<Face3> geometry;
bool _generate(Vector<Vector3> &points, Vector<Vector3> &normals);
- virtual void _generate_emission_points() = 0;
+ virtual void _generate_emission_points(){};
void _node_selected(const NodePath &p_path);
static void _bind_methods();
@@ -66,9 +67,9 @@ public:
class GPUParticles3DEditor : public GPUParticles3DEditorBase {
GDCLASS(GPUParticles3DEditor, GPUParticles3DEditorBase);
- ConfirmationDialog *generate_aabb;
- SpinBox *generate_seconds;
- GPUParticles3D *node;
+ ConfirmationDialog *generate_aabb = nullptr;
+ SpinBox *generate_seconds = nullptr;
+ GPUParticles3D *node = nullptr;
enum Menu {
MENU_OPTION_GENERATE_AABB,
@@ -100,8 +101,7 @@ public:
class GPUParticles3DEditorPlugin : public EditorPlugin {
GDCLASS(GPUParticles3DEditorPlugin, EditorPlugin);
- GPUParticles3DEditor *particles_editor;
- EditorNode *editor;
+ GPUParticles3DEditor *particles_editor = nullptr;
public:
virtual String get_name() const override { return "GPUParticles3D"; }
@@ -110,7 +110,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- GPUParticles3DEditorPlugin(EditorNode *p_node);
+ GPUParticles3DEditorPlugin();
~GPUParticles3DEditorPlugin();
};
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
index 6df2e34ceb..643a470425 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,11 +30,14 @@
#include "gpu_particles_collision_sdf_editor_plugin.h"
-void GPUParticlesCollisionSDFEditorPlugin::_bake() {
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+
+void GPUParticlesCollisionSDF3DEditorPlugin::_bake() {
if (col_sdf) {
if (col_sdf->get_texture().is_null() || !col_sdf->get_texture()->get_path().is_resource_file()) {
String path = get_tree()->get_edited_scene_root()->get_scene_file_path();
- if (path == String()) {
+ if (path.is_empty()) {
path = "res://" + col_sdf->get_name() + "_data.exr";
} else {
String ext = path.get_extension();
@@ -49,8 +52,8 @@ void GPUParticlesCollisionSDFEditorPlugin::_bake() {
}
}
-void GPUParticlesCollisionSDFEditorPlugin::edit(Object *p_object) {
- GPUParticlesCollisionSDF *s = Object::cast_to<GPUParticlesCollisionSDF>(p_object);
+void GPUParticlesCollisionSDF3DEditorPlugin::edit(Object *p_object) {
+ GPUParticlesCollisionSDF3D *s = Object::cast_to<GPUParticlesCollisionSDF3D>(p_object);
if (!s) {
return;
}
@@ -58,46 +61,52 @@ void GPUParticlesCollisionSDFEditorPlugin::edit(Object *p_object) {
col_sdf = s;
}
-bool GPUParticlesCollisionSDFEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("GPUParticlesCollisionSDF");
+bool GPUParticlesCollisionSDF3DEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("GPUParticlesCollisionSDF3D");
}
-void GPUParticlesCollisionSDFEditorPlugin::_notification(int p_what) {
- if (p_what == NOTIFICATION_PROCESS) {
- if (!col_sdf) {
- return;
- }
+void GPUParticlesCollisionSDF3DEditorPlugin::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_PROCESS: {
+ if (!col_sdf) {
+ return;
+ }
- const Vector3i size = col_sdf->get_estimated_cell_size();
- String text = vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z);
- int data_size = 2;
+ // Set information tooltip on the Bake button. This information is useful
+ // to optimize performance (video RAM size) and reduce collision tunneling (individual cell size).
- const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0);
- text += " - " + vformat(TTR("VRAM Size: %s MB"), String::num(size_mb, 2));
+ const Vector3i size = col_sdf->get_estimated_cell_size();
- if (bake_info->get_text() == text) {
- return;
- }
+ const Vector3 extents = col_sdf->get_extents();
- // Color the label depending on the estimated performance level.
- Color color;
- if (size_mb <= 16.0 + CMP_EPSILON) {
- // Fast.
- color = bake_info->get_theme_color(SNAME("success_color"), SNAME("Editor"));
- } else if (size_mb <= 64.0 + CMP_EPSILON) {
- // Medium.
- color = bake_info->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- } else {
- // Slow.
- color = bake_info->get_theme_color(SNAME("error_color"), SNAME("Editor"));
- }
- bake_info->add_theme_color_override("font_color", color);
+ int data_size = 2;
+ const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0);
+ // Add a qualitative measurement to help the user assess whether a GPUParticlesCollisionSDF3D node is using a lot of VRAM.
+ String size_quality;
+ if (size_mb < 8.0) {
+ size_quality = TTR("Low");
+ } else if (size_mb < 32.0) {
+ size_quality = TTR("Moderate");
+ } else {
+ size_quality = TTR("High");
+ }
+
+ String text;
+ text += vformat(TTR("Subdivisions: %s"), vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z)) + "\n";
+ text += vformat(TTR("Cell size: %s"), vformat(String::utf8("%.3f × %.3f × %.3f"), extents.x / size.x, extents.y / size.y, extents.z / size.z)) + "\n";
+ text += vformat(TTR("Video RAM size: %s MB (%s)"), String::num(size_mb, 2), size_quality);
+
+ // Only update the tooltip when needed to avoid constant redrawing.
+ if (bake->get_tooltip(Point2()) == text) {
+ return;
+ }
- bake_info->set_text(text);
+ bake->set_tooltip(text);
+ } break;
}
}
-void GPUParticlesCollisionSDFEditorPlugin::make_visible(bool p_visible) {
+void GPUParticlesCollisionSDF3DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
bake_hb->show();
set_process(true);
@@ -107,26 +116,26 @@ void GPUParticlesCollisionSDFEditorPlugin::make_visible(bool p_visible) {
}
}
-EditorProgress *GPUParticlesCollisionSDFEditorPlugin::tmp_progress = nullptr;
+EditorProgress *GPUParticlesCollisionSDF3DEditorPlugin::tmp_progress = nullptr;
-void GPUParticlesCollisionSDFEditorPlugin::bake_func_begin(int p_steps) {
+void GPUParticlesCollisionSDF3DEditorPlugin::bake_func_begin(int p_steps) {
ERR_FAIL_COND(tmp_progress != nullptr);
tmp_progress = memnew(EditorProgress("bake_sdf", TTR("Bake SDF"), p_steps));
}
-void GPUParticlesCollisionSDFEditorPlugin::bake_func_step(int p_step, const String &p_description) {
+void GPUParticlesCollisionSDF3DEditorPlugin::bake_func_step(int p_step, const String &p_description) {
ERR_FAIL_COND(tmp_progress == nullptr);
tmp_progress->step(p_description, p_step, false);
}
-void GPUParticlesCollisionSDFEditorPlugin::bake_func_end() {
+void GPUParticlesCollisionSDF3DEditorPlugin::bake_func_end() {
ERR_FAIL_COND(tmp_progress == nullptr);
memdelete(tmp_progress);
tmp_progress = nullptr;
}
-void GPUParticlesCollisionSDFEditorPlugin::_sdf_save_path_and_bake(const String &p_path) {
+void GPUParticlesCollisionSDF3DEditorPlugin::_sdf_save_path_and_bake(const String &p_path) {
probe_file->hide();
if (col_sdf) {
Ref<Image> bake_img = col_sdf->bake();
@@ -143,7 +152,7 @@ void GPUParticlesCollisionSDFEditorPlugin::_sdf_save_path_and_bake(const String
}
config->set_value("remap", "importer", "3d_texture");
- config->set_value("remap", "type", "StreamTexture3D");
+ config->set_value("remap", "type", "CompressedTexture3D");
if (!config->has_section_key("params", "compress/mode")) {
config->set_value("params", "compress/mode", 3); //user may want another compression, so leave it be
}
@@ -164,38 +173,33 @@ void GPUParticlesCollisionSDFEditorPlugin::_sdf_save_path_and_bake(const String
}
}
-void GPUParticlesCollisionSDFEditorPlugin::_bind_methods() {
+void GPUParticlesCollisionSDF3DEditorPlugin::_bind_methods() {
}
-GPUParticlesCollisionSDFEditorPlugin::GPUParticlesCollisionSDFEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+GPUParticlesCollisionSDF3DEditorPlugin::GPUParticlesCollisionSDF3DEditorPlugin() {
bake_hb = memnew(HBoxContainer);
bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bake_hb->hide();
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(editor->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
+ bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
bake->set_text(TTR("Bake SDF"));
- bake->connect("pressed", callable_mp(this, &GPUParticlesCollisionSDFEditorPlugin::_bake));
+ bake->connect("pressed", callable_mp(this, &GPUParticlesCollisionSDF3DEditorPlugin::_bake));
bake_hb->add_child(bake);
- bake_info = memnew(Label);
- bake_info->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- bake_info->set_clip_text(true);
- bake_hb->add_child(bake_info);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb);
col_sdf = nullptr;
probe_file = memnew(EditorFileDialog);
probe_file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
probe_file->add_filter("*.exr");
- probe_file->connect("file_selected", callable_mp(this, &GPUParticlesCollisionSDFEditorPlugin::_sdf_save_path_and_bake));
+ probe_file->connect("file_selected", callable_mp(this, &GPUParticlesCollisionSDF3DEditorPlugin::_sdf_save_path_and_bake));
get_editor_interface()->get_base_control()->add_child(probe_file);
probe_file->set_title(TTR("Select path for SDF Texture"));
- GPUParticlesCollisionSDF::bake_begin_function = bake_func_begin;
- GPUParticlesCollisionSDF::bake_step_function = bake_func_step;
- GPUParticlesCollisionSDF::bake_end_function = bake_func_end;
+ GPUParticlesCollisionSDF3D::bake_begin_function = bake_func_begin;
+ GPUParticlesCollisionSDF3D::bake_step_function = bake_func_step;
+ GPUParticlesCollisionSDF3D::bake_end_function = bake_func_end;
}
-GPUParticlesCollisionSDFEditorPlugin::~GPUParticlesCollisionSDFEditorPlugin() {
+GPUParticlesCollisionSDF3DEditorPlugin::~GPUParticlesCollisionSDF3DEditorPlugin() {
}
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h
index 5a71fc44ef..684279039a 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,22 +31,22 @@
#ifndef GPU_PARTICLES_COLLISION_SDF_EDITOR_PLUGIN_H
#define GPU_PARTICLES_COLLISION_SDF_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/gpu_particles_collision_3d.h"
#include "scene/resources/material.h"
-class GPUParticlesCollisionSDFEditorPlugin : public EditorPlugin {
- GDCLASS(GPUParticlesCollisionSDFEditorPlugin, EditorPlugin);
+struct EditorProgress;
+class EditorFileDialog;
- GPUParticlesCollisionSDF *col_sdf;
+class GPUParticlesCollisionSDF3DEditorPlugin : public EditorPlugin {
+ GDCLASS(GPUParticlesCollisionSDF3DEditorPlugin, EditorPlugin);
- HBoxContainer *bake_hb;
- Label *bake_info;
- Button *bake;
- EditorNode *editor;
+ GPUParticlesCollisionSDF3D *col_sdf = nullptr;
- EditorFileDialog *probe_file;
+ HBoxContainer *bake_hb = nullptr;
+ Button *bake = nullptr;
+
+ EditorFileDialog *probe_file = nullptr;
static EditorProgress *tmp_progress;
static void bake_func_begin(int p_steps);
@@ -61,14 +61,14 @@ protected:
void _notification(int p_what);
public:
- virtual String get_name() const override { return "GPUParticlesCollisionSDF"; }
+ virtual String get_name() const override { return "GPUParticlesCollisionSDF3D"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- GPUParticlesCollisionSDFEditorPlugin(EditorNode *p_node);
- ~GPUParticlesCollisionSDFEditorPlugin();
+ GPUParticlesCollisionSDF3DEditorPlugin();
+ ~GPUParticlesCollisionSDF3DEditorPlugin();
};
#endif // GPU_PARTICLES_COLLISION_SDF_EDITOR_PLUGIN_H
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index 355bdb69d8..1386f03662 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,6 +31,7 @@
#include "gradient_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "node_3d_editor_plugin.h"
@@ -46,17 +47,21 @@ void GradientEditor::_gradient_changed() {
editing = true;
Vector<Gradient::Point> points = gradient->get_points();
set_points(points);
+ set_interpolation_mode(gradient->get_interpolation_mode());
+ update();
editing = false;
}
void GradientEditor::_ramp_changed() {
editing = true;
UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
- undo_redo->create_action(TTR("Gradient Edited"));
+ undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets());
undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors());
+ undo_redo->add_do_method(gradient.ptr(), "set_interpolation_mode", get_interpolation_mode());
undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets());
undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors());
+ undo_redo->add_undo_method(gradient.ptr(), "set_interpolation_mode", gradient->get_interpolation_mode());
undo_redo->commit_action();
editing = false;
}
@@ -69,6 +74,14 @@ void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed));
gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed));
set_points(gradient->get_points());
+ set_interpolation_mode(gradient->get_interpolation_mode());
+}
+
+void GradientEditor::reverse_gradient() {
+ gradient->reverse();
+ set_points(gradient->get_points());
+ emit_signal(SNAME("ramp_changed"));
+ update();
}
GradientEditor::GradientEditor() {
@@ -77,6 +90,25 @@ GradientEditor::GradientEditor() {
///////////////////////
+void GradientReverseButton::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
+ Ref<Texture2D> icon = get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons"));
+ if (is_pressed()) {
+ draw_texture_rect(icon, Rect2(margin, margin, icon->get_width(), icon->get_height()), false, get_theme_color(SNAME("icon_pressed_color"), SNAME("Button")));
+ } else {
+ draw_texture_rect(icon, Rect2(margin, margin, icon->get_width(), icon->get_height()));
+ }
+ } break;
+ }
+}
+
+Size2 GradientReverseButton::get_minimum_size() const {
+ return (get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons"))->get_size() + Size2(margin * 2, margin * 2));
+}
+
+///////////////////////
+
bool EditorInspectorPluginGradient::can_handle(Object *p_object) {
return Object::cast_to<Gradient>(p_object) != nullptr;
}
@@ -85,12 +117,29 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) {
Gradient *gradient = Object::cast_to<Gradient>(p_object);
Ref<Gradient> g(gradient);
- GradientEditor *editor = memnew(GradientEditor);
+ editor = memnew(GradientEditor);
editor->set_gradient(g);
add_custom_control(editor);
+
+ int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape");
+ editor->get_picker()->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
+
+ reverse_btn = memnew(GradientReverseButton);
+
+ gradient_tools_hbox = memnew(HBoxContainer);
+ gradient_tools_hbox->add_child(reverse_btn);
+
+ add_custom_control(gradient_tools_hbox);
+
+ reverse_btn->connect("pressed", callable_mp(this, &EditorInspectorPluginGradient::_reverse_button_pressed));
+ reverse_btn->set_tooltip(TTR("Reverse/mirror gradient."));
+}
+
+void EditorInspectorPluginGradient::_reverse_button_pressed() {
+ editor->reverse_gradient();
}
-GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) {
+GradientEditorPlugin::GradientEditorPlugin() {
Ref<EditorInspectorPluginGradient> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h
index bcbb86e422..26bf76fecd 100644
--- a/editor/plugins/gradient_editor_plugin.h
+++ b/editor/plugins/gradient_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef GRADIENT_EDITOR_PLUGIN_H
#define GRADIENT_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/gui/gradient_edit.h"
@@ -50,12 +49,28 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
void set_gradient(const Ref<Gradient> &p_gradient);
+ void reverse_gradient();
GradientEditor();
};
+class GradientReverseButton : public BaseButton {
+ GDCLASS(GradientReverseButton, BaseButton);
+
+ int margin = 2;
+
+ void _notification(int p_what);
+ virtual Size2 get_minimum_size() const override;
+};
+
class EditorInspectorPluginGradient : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginGradient, EditorInspectorPlugin);
+ GradientEditor *editor = nullptr;
+ HBoxContainer *gradient_tools_hbox = nullptr;
+ GradientReverseButton *reverse_btn = nullptr;
+
+ void _reverse_button_pressed();
+
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
@@ -67,7 +82,7 @@ class GradientEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "Gradient"; }
- GradientEditorPlugin(EditorNode *p_node);
+ GradientEditorPlugin();
};
#endif // GRADIENT_EDITOR_PLUGIN_H
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..e97c611e96
--- /dev/null
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -0,0 +1,284 @@
+/*************************************************************************/
+/* gradient_texture_2d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "gradient_texture_2d_editor_plugin.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/flow_container.h"
+#include "scene/gui/separator.h"
+
+Point2 GradientTexture2DEditorRect::_get_handle_position(const Handle p_handle) {
+ // Get the handle's mouse position in pixels relative to offset.
+ return (p_handle == HANDLE_FILL_FROM ? texture->get_fill_from() : texture->get_fill_to()).clamp(Vector2(), Vector2(1, 1)) * size;
+}
+
+void GradientTexture2DEditorRect::_update_fill_position() {
+ if (handle == HANDLE_NONE) {
+ return;
+ }
+
+ // Update the texture's fill_from/fill_to property based on mouse input.
+ Vector2 percent = ((get_local_mouse_position() - offset) / size).clamp(Vector2(), Vector2(1, 1));
+ if (snap_enabled) {
+ percent = (percent - Vector2(0.5, 0.5)).snapped(Vector2(snap_size, snap_size)) + Vector2(0.5, 0.5);
+ }
+
+ String property_name = handle == HANDLE_FILL_FROM ? "fill_from" : "fill_to";
+
+ undo_redo->create_action(vformat(TTR("Set %s"), property_name), UndoRedo::MERGE_ENDS);
+ undo_redo->add_do_property(texture.ptr(), property_name, percent);
+ undo_redo->add_undo_property(texture.ptr(), property_name, handle == HANDLE_FILL_FROM ? texture->get_fill_from() : texture->get_fill_to());
+ undo_redo->commit_action();
+}
+
+void GradientTexture2DEditorRect::gui_input(const Ref<InputEvent> &p_event) {
+ // Grab/release handle.
+ const Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ Point2 mouse_position = mb->get_position() - offset;
+ if (Rect2(_get_handle_position(HANDLE_FILL_FROM).round() - handle_size / 2, handle_size).has_point(mouse_position)) {
+ handle = HANDLE_FILL_FROM;
+ } else if (Rect2(_get_handle_position(HANDLE_FILL_TO).round() - handle_size / 2, handle_size).has_point(mouse_position)) {
+ handle = HANDLE_FILL_TO;
+ } else {
+ handle = HANDLE_NONE;
+ }
+ } else {
+ _update_fill_position();
+ handle = HANDLE_NONE;
+ }
+ }
+
+ // Move handle.
+ const Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ _update_fill_position();
+ }
+}
+
+void GradientTexture2DEditorRect::set_texture(Ref<GradientTexture2D> &p_texture) {
+ texture = p_texture;
+ texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+}
+
+void GradientTexture2DEditorRect::set_snap_enabled(bool p_snap_enabled) {
+ snap_enabled = p_snap_enabled;
+ update();
+}
+
+void GradientTexture2DEditorRect::set_snap_size(float p_snap_size) {
+ snap_size = p_snap_size;
+ update();
+}
+
+void GradientTexture2DEditorRect::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ checkerboard->set_texture(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")));
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ if (texture.is_null()) {
+ return;
+ }
+
+ const Ref<Texture2D> fill_from_icon = get_theme_icon(SNAME("EditorPathSmoothHandle"), SNAME("EditorIcons"));
+ const Ref<Texture2D> fill_to_icon = get_theme_icon(SNAME("EditorPathSharpHandle"), SNAME("EditorIcons"));
+ handle_size = fill_from_icon->get_size();
+
+ const int MAX_HEIGHT = 250 * EDSCALE;
+ Size2 rect_size = get_size();
+
+ // Get the size and position to draw the texture and handles at.
+ size = Size2(texture->get_width() * MAX_HEIGHT / texture->get_height(), MAX_HEIGHT);
+ if (size.width > rect_size.width) {
+ size.width = rect_size.width;
+ size.height = texture->get_height() * rect_size.width / texture->get_width();
+ }
+ offset = Point2(Math::round((rect_size.width - size.width) / 2), 0) + handle_size / 2;
+ set_custom_minimum_size(Size2(0, size.height));
+ size -= handle_size;
+ checkerboard->set_rect(Rect2(offset, size));
+
+ draw_set_transform(offset);
+ draw_texture_rect(texture, Rect2(Point2(), size));
+
+ // Draw grid snap lines.
+ if (snap_enabled) {
+ const Color primary_line_color = Color(0.5, 0.5, 0.5, 0.9);
+ const Color line_color = Color(0.5, 0.5, 0.5, 0.5);
+
+ // Draw border and centered axis lines.
+ draw_rect(Rect2(Point2(), size), primary_line_color, false);
+ draw_line(Point2(size.width / 2, 0), Point2(size.width / 2, size.height), primary_line_color);
+ draw_line(Point2(0, size.height / 2), Point2(size.width, size.height / 2), primary_line_color);
+
+ // Draw vertical lines.
+ int prev_idx = 0;
+ for (int x = 0; x < size.width; x++) {
+ int idx = int((x / size.width - 0.5) / snap_size);
+
+ if (x > 0 && prev_idx != idx) {
+ draw_line(Point2(x, 0), Point2(x, size.height), line_color);
+ }
+
+ prev_idx = idx;
+ }
+
+ // Draw horizontal lines.
+ prev_idx = 0;
+ for (int y = 0; y < size.height; y++) {
+ int idx = int((y / size.height - 0.5) / snap_size);
+
+ if (y > 0 && prev_idx != idx) {
+ draw_line(Point2(0, y), Point2(size.width, y), line_color);
+ }
+
+ prev_idx = idx;
+ }
+ }
+
+ // Draw handles.
+ draw_texture(fill_from_icon, (_get_handle_position(HANDLE_FILL_FROM) - handle_size / 2).round());
+ draw_texture(fill_to_icon, (_get_handle_position(HANDLE_FILL_TO) - handle_size / 2).round());
+ } break;
+ }
+}
+
+GradientTexture2DEditorRect::GradientTexture2DEditorRect() {
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ checkerboard = memnew(TextureRect);
+ checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE);
+ checkerboard->set_draw_behind_parent(true);
+ add_child(checkerboard);
+}
+
+///////////////////////
+
+void GradientTexture2DEditor::_reverse_button_pressed() {
+ undo_redo->create_action(TTR("Swap GradientTexture2D Fill Points"));
+ undo_redo->add_do_property(texture.ptr(), "fill_from", texture->get_fill_to());
+ undo_redo->add_do_property(texture.ptr(), "fill_to", texture->get_fill_from());
+ undo_redo->add_undo_property(texture.ptr(), "fill_from", texture->get_fill_from());
+ undo_redo->add_undo_property(texture.ptr(), "fill_to", texture->get_fill_to());
+ undo_redo->commit_action();
+}
+
+void GradientTexture2DEditor::_set_snap_enabled(bool p_enabled) {
+ texture_editor_rect->set_snap_enabled(p_enabled);
+
+ snap_size_edit->set_visible(p_enabled);
+}
+
+void GradientTexture2DEditor::_set_snap_size(float p_snap_size) {
+ texture_editor_rect->set_snap_size(MAX(p_snap_size, 0.01));
+}
+
+void GradientTexture2DEditor::set_texture(Ref<GradientTexture2D> &p_texture) {
+ texture = p_texture;
+ texture_editor_rect->set_texture(p_texture);
+}
+
+void GradientTexture2DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ reverse_button->set_icon(get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons")));
+ snap_button->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
+ } break;
+ }
+}
+
+GradientTexture2DEditor::GradientTexture2DEditor() {
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+ HFlowContainer *toolbar = memnew(HFlowContainer);
+ add_child(toolbar);
+
+ reverse_button = memnew(Button);
+ reverse_button->set_tooltip(TTR("Swap Gradient Fill Points"));
+ toolbar->add_child(reverse_button);
+ reverse_button->connect("pressed", callable_mp(this, &GradientTexture2DEditor::_reverse_button_pressed));
+
+ toolbar->add_child(memnew(VSeparator));
+
+ snap_button = memnew(Button);
+ snap_button->set_tooltip(TTR("Toggle Grid Snap"));
+ snap_button->set_toggle_mode(true);
+ toolbar->add_child(snap_button);
+ snap_button->connect("toggled", callable_mp(this, &GradientTexture2DEditor::_set_snap_enabled));
+
+ snap_size_edit = memnew(EditorSpinSlider);
+ snap_size_edit->set_min(0.01);
+ snap_size_edit->set_max(0.5);
+ snap_size_edit->set_step(0.01);
+ snap_size_edit->set_value(0.1);
+ snap_size_edit->set_custom_minimum_size(Size2(65 * EDSCALE, 0));
+ toolbar->add_child(snap_size_edit);
+ snap_size_edit->connect("value_changed", callable_mp(this, &GradientTexture2DEditor::_set_snap_size));
+
+ texture_editor_rect = memnew(GradientTexture2DEditorRect);
+ add_child(texture_editor_rect);
+
+ set_mouse_filter(MOUSE_FILTER_STOP);
+ _set_snap_enabled(snap_button->is_pressed());
+ _set_snap_size(snap_size_edit->get_value());
+}
+
+///////////////////////
+
+bool EditorInspectorPluginGradientTexture2D::can_handle(Object *p_object) {
+ return Object::cast_to<GradientTexture2D>(p_object) != nullptr;
+}
+
+void EditorInspectorPluginGradientTexture2D::parse_begin(Object *p_object) {
+ GradientTexture2D *texture = Object::cast_to<GradientTexture2D>(p_object);
+ if (!texture) {
+ return;
+ }
+ Ref<GradientTexture2D> t(texture);
+
+ GradientTexture2DEditor *editor = memnew(GradientTexture2DEditor);
+ editor->set_texture(t);
+ add_custom_control(editor);
+}
+
+///////////////////////
+
+GradientTexture2DEditorPlugin::GradientTexture2DEditorPlugin() {
+ Ref<EditorInspectorPluginGradientTexture2D> plugin;
+ plugin.instantiate();
+ add_inspector_plugin(plugin);
+}
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.h b/editor/plugins/gradient_texture_2d_editor_plugin.h
new file mode 100644
index 0000000000..4ce64ce1dc
--- /dev/null
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.h
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* gradient_texture_2d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 GRADIENT_TEXTURE_2D_EDITOR
+#define GRADIENT_TEXTURE_2D_EDITOR
+
+#include "editor/editor_plugin.h"
+#include "editor/editor_spin_slider.h"
+
+class GradientTexture2DEditorRect : public Control {
+ GDCLASS(GradientTexture2DEditorRect, Control);
+
+ enum Handle {
+ HANDLE_NONE,
+ HANDLE_FILL_FROM,
+ HANDLE_FILL_TO
+ };
+
+ Ref<GradientTexture2D> texture;
+ UndoRedo *undo_redo = nullptr;
+ bool snap_enabled = false;
+ float snap_size = 0;
+
+ TextureRect *checkerboard = nullptr;
+
+ Handle handle = HANDLE_NONE;
+ Size2 handle_size;
+ Point2 offset;
+ Size2 size;
+
+ Point2 _get_handle_position(const Handle p_handle);
+ void _update_fill_position();
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void set_texture(Ref<GradientTexture2D> &p_texture);
+ void set_snap_enabled(bool p_snap_enabled);
+ void set_snap_size(float p_snap_size);
+
+ GradientTexture2DEditorRect();
+};
+
+class GradientTexture2DEditor : public VBoxContainer {
+ GDCLASS(GradientTexture2DEditor, VBoxContainer);
+
+ Ref<GradientTexture2D> texture;
+ UndoRedo *undo_redo = nullptr;
+
+ Button *reverse_button = nullptr;
+ Button *snap_button = nullptr;
+ EditorSpinSlider *snap_size_edit = nullptr;
+ GradientTexture2DEditorRect *texture_editor_rect = nullptr;
+
+ void _reverse_button_pressed();
+ void _set_snap_enabled(bool p_enabled);
+ void _set_snap_size(float p_snap_size);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void set_texture(Ref<GradientTexture2D> &p_texture);
+
+ GradientTexture2DEditor();
+};
+
+class EditorInspectorPluginGradientTexture2D : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginGradientTexture2D, EditorInspectorPlugin);
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual void parse_begin(Object *p_object) override;
+};
+
+class GradientTexture2DEditorPlugin : public EditorPlugin {
+ GDCLASS(GradientTexture2DEditorPlugin, EditorPlugin);
+
+public:
+ GradientTexture2DEditorPlugin();
+};
+
+#endif
diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp
index d3d2de92f5..fb0e260388 100644
--- a/editor/plugins/input_event_editor_plugin.cpp
+++ b/editor/plugins/input_event_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,6 +33,15 @@
void InputEventConfigContainer::_bind_methods() {
}
+void InputEventConfigContainer::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ open_config_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ } break;
+ }
+}
+
void InputEventConfigContainer::_configure_pressed() {
config_dialog->popup_and_configure(input_event);
}
@@ -47,12 +56,6 @@ void InputEventConfigContainer::_config_dialog_confirmed() {
_event_changed();
}
-Size2 InputEventConfigContainer::get_minimum_size() const {
- // Don't bother with a minimum x size for the control - we don't want the inspector
- // to jump in size if a long text is placed in the label (e.g. Joypad Axis description)
- return Size2(0, HBoxContainer::get_minimum_size().y);
-}
-
void InputEventConfigContainer::set_event(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
Ref<InputEventMouseButton> m = p_event;
@@ -75,29 +78,26 @@ void InputEventConfigContainer::set_event(const Ref<InputEvent> &p_event) {
}
InputEventConfigContainer::InputEventConfigContainer() {
- MarginContainer *mc = memnew(MarginContainer);
- mc->add_theme_constant_override("margin_left", 10);
- mc->add_theme_constant_override("margin_right", 10);
- mc->add_theme_constant_override("margin_top", 10);
- mc->add_theme_constant_override("margin_bottom", 10);
- add_child(mc);
-
- HBoxContainer *hb = memnew(HBoxContainer);
- mc->add_child(hb);
+ input_event_text = memnew(Label);
+ input_event_text->set_h_size_flags(SIZE_EXPAND_FILL);
+ input_event_text->set_autowrap_mode(Label::AutowrapMode::AUTOWRAP_WORD_SMART);
+ input_event_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ add_child(input_event_text);
open_config_button = memnew(Button);
open_config_button->set_text(TTR("Configure"));
open_config_button->connect("pressed", callable_mp(this, &InputEventConfigContainer::_configure_pressed));
- hb->add_child(open_config_button);
+ add_child(open_config_button);
- input_event_text = memnew(Label);
- hb->add_child(input_event_text);
+ add_child(memnew(Control));
config_dialog = memnew(InputEventConfigurationDialog);
config_dialog->connect("confirmed", callable_mp(this, &InputEventConfigContainer::_config_dialog_confirmed));
add_child(config_dialog);
}
+///////////////////////
+
bool EditorInspectorPluginInputEvent::can_handle(Object *p_object) {
Ref<InputEventKey> k = Ref<InputEventKey>(p_object);
Ref<InputEventMouseButton> m = Ref<InputEventMouseButton>(p_object);
@@ -115,7 +115,9 @@ void EditorInspectorPluginInputEvent::parse_begin(Object *p_object) {
add_custom_control(picker_controls);
}
-InputEventEditorPlugin::InputEventEditorPlugin(EditorNode *p_node) {
+///////////////////////
+
+InputEventEditorPlugin::InputEventEditorPlugin() {
Ref<EditorInspectorPluginInputEvent> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/input_event_editor_plugin.h b/editor/plugins/input_event_editor_plugin.h
index bc8293c9e5..344f176e78 100644
--- a/editor/plugins/input_event_editor_plugin.h
+++ b/editor/plugins/input_event_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,16 +33,16 @@
#include "editor/action_map_editor.h"
#include "editor/editor_inspector.h"
-#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
-class InputEventConfigContainer : public HBoxContainer {
- GDCLASS(InputEventConfigContainer, HBoxContainer);
+class InputEventConfigContainer : public VBoxContainer {
+ GDCLASS(InputEventConfigContainer, VBoxContainer);
- Label *input_event_text;
- Button *open_config_button;
+ Label *input_event_text = nullptr;
+ Button *open_config_button = nullptr;
Ref<InputEvent> input_event;
- InputEventConfigurationDialog *config_dialog;
+ InputEventConfigurationDialog *config_dialog = nullptr;
void _config_dialog_confirmed();
void _configure_pressed();
@@ -50,10 +50,10 @@ class InputEventConfigContainer : public HBoxContainer {
void _event_changed();
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
- virtual Size2 get_minimum_size() const override;
void set_event(const Ref<InputEvent> &p_event);
InputEventConfigContainer();
@@ -73,7 +73,7 @@ class InputEventEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "InputEvent"; }
- InputEventEditorPlugin(EditorNode *p_node);
+ InputEventEditorPlugin();
};
#endif // INPUT_EVENT_EDITOR_PLUGIN_H
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index 3d555d7eba..e7ef65c32b 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -96,17 +96,14 @@ void LightOccluder2DEditor::_create_resource() {
undo_redo->create_action(TTR("Create Occluder Polygon"));
undo_redo->add_do_method(node, "set_occluder_polygon", Ref<OccluderPolygon2D>(memnew(OccluderPolygon2D)));
- undo_redo->add_undo_method(node, "set_occluder_polygon", Variant(REF()));
+ undo_redo->add_undo_method(node, "set_occluder_polygon", Variant(Ref<RefCounted>()));
undo_redo->commit_action();
_menu_option(MODE_CREATE);
}
-LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) :
- AbstractPolygon2DEditor(p_editor) {
- node = nullptr;
-}
+LightOccluder2DEditor::LightOccluder2DEditor() {}
-LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) :
- AbstractPolygon2DEditorPlugin(p_node, memnew(LightOccluder2DEditor(p_node)), "LightOccluder2D") {
+LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin() :
+ AbstractPolygon2DEditorPlugin(memnew(LightOccluder2DEditor), "LightOccluder2D") {
}
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.h b/editor/plugins/light_occluder_2d_editor_plugin.h
index eb1ce04788..aeee12b5b6 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.h
+++ b/editor/plugins/light_occluder_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,7 +37,7 @@
class LightOccluder2DEditor : public AbstractPolygon2DEditor {
GDCLASS(LightOccluder2DEditor, AbstractPolygon2DEditor);
- LightOccluder2D *node;
+ LightOccluder2D *node = nullptr;
Ref<OccluderPolygon2D> _ensure_occluder() const;
@@ -56,14 +56,14 @@ protected:
virtual void _create_resource() override;
public:
- LightOccluder2DEditor(EditorNode *p_editor);
+ LightOccluder2DEditor();
};
class LightOccluder2DEditorPlugin : public AbstractPolygon2DEditorPlugin {
GDCLASS(LightOccluder2DEditorPlugin, AbstractPolygon2DEditorPlugin);
public:
- LightOccluder2DEditorPlugin(EditorNode *p_node);
+ LightOccluder2DEditorPlugin();
};
#endif // LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 123087446c..aef97f059a 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,24 +30,28 @@
#include "lightmap_gi_editor_plugin.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+
void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
if (lightmap) {
LightmapGI::BakeError err;
+ const uint64_t time_started = OS::get_singleton()->get_ticks_msec();
if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) {
err = lightmap->bake(lightmap, p_file, bake_func_step);
} else {
err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step);
}
- bake_func_end();
+ bake_func_end(time_started);
switch (err) {
case LightmapGI::BAKE_ERROR_NO_SAVE_PATH: {
String scene_path = lightmap->get_scene_file_path();
- if (scene_path == String()) {
+ if (scene_path.is_empty()) {
scene_path = lightmap->get_owner()->get_scene_file_path();
}
- if (scene_path == String()) {
+ if (scene_path.is_empty()) {
EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for lightmap images.\nSave your scene and try again."));
break;
}
@@ -104,22 +108,28 @@ bool LightmapGIEditorPlugin::bake_func_step(float p_progress, const String &p_de
return tmp_progress->step(p_description, p_progress * 1000, p_refresh);
}
-void LightmapGIEditorPlugin::bake_func_end() {
+void LightmapGIEditorPlugin::bake_func_end(uint64_t p_time_started) {
if (tmp_progress != nullptr) {
memdelete(tmp_progress);
tmp_progress = nullptr;
}
+
+ const int time_taken = (OS::get_singleton()->get_ticks_msec() - p_time_started) * 0.001;
+ print_line(vformat("Done baking lightmaps in %02d:%02d:%02d.", time_taken / 3600, (time_taken % 3600) / 60, time_taken % 60));
+ // Request attention in case the user was doing something else.
+ // Baking lightmaps is likely the editor task that can take the most time,
+ // so only request the attention for baking lightmaps.
+ DisplayServer::get_singleton()->window_request_attention();
}
void LightmapGIEditorPlugin::_bind_methods() {
ClassDB::bind_method("_bake", &LightmapGIEditorPlugin::_bake);
}
-LightmapGIEditorPlugin::LightmapGIEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+LightmapGIEditorPlugin::LightmapGIEditorPlugin() {
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(editor->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
+ bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
bake->set_text(TTR("Bake Lightmaps"));
bake->hide();
bake->connect("pressed", Callable(this, "_bake"));
@@ -128,7 +138,7 @@ LightmapGIEditorPlugin::LightmapGIEditorPlugin(EditorNode *p_node) {
file_dialog = memnew(EditorFileDialog);
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
- file_dialog->add_filter("*.lmbake ; LightMap Bake");
+ file_dialog->add_filter("*.lmbake ; " + TTR("LightMap Bake"));
file_dialog->set_title(TTR("Select lightmap bake file:"));
file_dialog->connect("file_selected", callable_mp(this, &LightmapGIEditorPlugin::_bake_select_file));
bake->add_child(file_dialog);
diff --git a/editor/plugins/lightmap_gi_editor_plugin.h b/editor/plugins/lightmap_gi_editor_plugin.h
index 12d080d6be..1202efe8fc 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.h
+++ b/editor/plugins/lightmap_gi_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,23 +31,24 @@
#ifndef BAKED_LIGHTMAP_EDITOR_PLUGIN_H
#define BAKED_LIGHTMAP_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/resources/material.h"
+struct EditorProgress;
+class EditorFileDialog;
+
class LightmapGIEditorPlugin : public EditorPlugin {
GDCLASS(LightmapGIEditorPlugin, EditorPlugin);
- LightmapGI *lightmap;
+ LightmapGI *lightmap = nullptr;
- Button *bake;
- EditorNode *editor;
+ Button *bake = nullptr;
- EditorFileDialog *file_dialog;
+ EditorFileDialog *file_dialog = nullptr;
static EditorProgress *tmp_progress;
static bool bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh);
- static void bake_func_end();
+ static void bake_func_end(uint64_t p_time_started);
void _bake_select_file(const String &p_file);
void _bake();
@@ -62,7 +63,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- LightmapGIEditorPlugin(EditorNode *p_node);
+ LightmapGIEditorPlugin();
~LightmapGIEditorPlugin();
};
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index 08c5ef02a4..31053f90b8 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -56,11 +56,8 @@ void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, con
undo_redo->add_undo_method(node, "set_points", p_previous);
}
-Line2DEditor::Line2DEditor(EditorNode *p_editor) :
- AbstractPolygon2DEditor(p_editor) {
- node = nullptr;
-}
+Line2DEditor::Line2DEditor() {}
-Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) :
- AbstractPolygon2DEditorPlugin(p_node, memnew(Line2DEditor(p_node)), "Line2D") {
+Line2DEditorPlugin::Line2DEditorPlugin() :
+ AbstractPolygon2DEditorPlugin(memnew(Line2DEditor), "Line2D") {
}
diff --git a/editor/plugins/line_2d_editor_plugin.h b/editor/plugins/line_2d_editor_plugin.h
index 769109583a..0d407b3150 100644
--- a/editor/plugins/line_2d_editor_plugin.h
+++ b/editor/plugins/line_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,7 +37,7 @@
class Line2DEditor : public AbstractPolygon2DEditor {
GDCLASS(Line2DEditor, AbstractPolygon2DEditor);
- Line2D *node;
+ Line2D *node = nullptr;
protected:
virtual Node2D *_get_node() const override;
@@ -49,14 +49,14 @@ protected:
virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) override;
public:
- Line2DEditor(EditorNode *p_editor);
+ Line2DEditor();
};
class Line2DEditorPlugin : public AbstractPolygon2DEditorPlugin {
GDCLASS(Line2DEditorPlugin, AbstractPolygon2DEditorPlugin);
public:
- Line2DEditorPlugin(EditorNode *p_node);
+ Line2DEditorPlugin();
};
#endif // LINE_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 140d2952dd..eb004568d0 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,7 @@
#include "material_editor_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/gui/subviewport_container.h"
#include "scene/resources/fog_material.h"
@@ -37,31 +38,33 @@
#include "scene/resources/sky_material.h"
void MaterialEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- //get_scene()->connect("node_removed",this,"_node_removed");
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ //get_scene()->connect("node_removed",this,"_node_removed");
- if (first_enter) {
- //it's in propertyeditor so.. could be moved around
+ if (first_enter) {
+ //it's in propertyeditor so.. could be moved around
- light_1_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons")));
- light_1_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons")));
- light_2_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons")));
- light_2_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons")));
+ light_1_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons")));
+ light_1_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons")));
+ light_2_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons")));
+ light_2_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons")));
- sphere_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewSphereOff"), SNAME("EditorIcons")));
- sphere_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewSphere"), SNAME("EditorIcons")));
- box_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewCubeOff"), SNAME("EditorIcons")));
- box_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewCube"), SNAME("EditorIcons")));
+ sphere_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewSphereOff"), SNAME("EditorIcons")));
+ sphere_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewSphere"), SNAME("EditorIcons")));
+ box_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewCubeOff"), SNAME("EditorIcons")));
+ box_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewCube"), SNAME("EditorIcons")));
- first_enter = false;
- }
- }
+ first_enter = false;
+ }
+ } break;
- if (p_what == NOTIFICATION_DRAW) {
- Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
- Size2 size = get_size();
+ case NOTIFICATION_DRAW: {
+ Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
+ Size2 size = get_size();
- draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ } break;
}
}
@@ -69,8 +72,24 @@ void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_en
material = p_material;
camera->set_environment(p_env);
if (!material.is_null()) {
- sphere_instance->set_material_override(material);
- box_instance->set_material_override(material);
+ Shader::Mode mode = p_material->get_shader_mode();
+ switch (mode) {
+ case Shader::MODE_CANVAS_ITEM:
+ layout_3d->hide();
+ layout_2d->show();
+ vc->hide();
+ rect_instance->set_material(material);
+ break;
+ case Shader::MODE_SPATIAL:
+ layout_2d->hide();
+ layout_3d->show();
+ vc->show();
+ sphere_instance->set_material_override(material);
+ box_instance->set_material_override(material);
+ break;
+ default:
+ break;
+ }
} else {
hide();
}
@@ -106,6 +125,21 @@ void MaterialEditor::_bind_methods() {
}
MaterialEditor::MaterialEditor() {
+ // canvas item
+
+ layout_2d = memnew(HBoxContainer);
+ layout_2d->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ add_child(layout_2d);
+ layout_2d->set_anchors_and_offsets_preset(PRESET_WIDE);
+
+ rect_instance = memnew(ColorRect);
+ layout_2d->add_child(rect_instance);
+ rect_instance->set_custom_minimum_size(Size2(150, 150) * EDSCALE);
+
+ layout_2d->set_visible(false);
+
+ // spatial
+
vc = memnew(SubViewportContainer);
vc->set_stretch(true);
add_child(vc);
@@ -154,12 +188,12 @@ MaterialEditor::MaterialEditor() {
set_custom_minimum_size(Size2(1, 150) * EDSCALE);
- HBoxContainer *hb = memnew(HBoxContainer);
- add_child(hb);
- hb->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2);
+ layout_3d = memnew(HBoxContainer);
+ add_child(layout_3d);
+ layout_3d->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2);
VBoxContainer *vb_shape = memnew(VBoxContainer);
- hb->add_child(vb_shape);
+ layout_3d->add_child(vb_shape);
sphere_switch = memnew(TextureButton);
sphere_switch->set_toggle_mode(true);
@@ -173,10 +207,10 @@ MaterialEditor::MaterialEditor() {
vb_shape->add_child(box_switch);
box_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed), varray(box_switch));
- hb->add_spacer();
+ layout_3d->add_spacer();
VBoxContainer *vb_light = memnew(VBoxContainer);
- hb->add_child(vb_light);
+ layout_3d->add_child(vb_light);
light_1_switch = memnew(TextureButton);
light_1_switch->set_toggle_mode(true);
@@ -207,8 +241,8 @@ bool EditorInspectorPluginMaterial::can_handle(Object *p_object) {
if (!material) {
return false;
}
-
- return material->get_shader_mode() == Shader::MODE_SPATIAL;
+ Shader::Mode mode = material->get_shader_mode();
+ return mode == Shader::MODE_SPATIAL || mode == Shader::MODE_CANVAS_ITEM;
}
void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
@@ -223,6 +257,43 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
add_custom_control(editor);
}
+void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
+ UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
+ if (!undo_redo) {
+ return;
+ }
+
+ // For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot,
+ // set the respective metallic or roughness factor to 1.0 as a convenience feature
+ BaseMaterial3D *base_material = Object::cast_to<StandardMaterial3D>(p_edited);
+ if (base_material) {
+ Texture2D *texture = Object::cast_to<Texture2D>(p_new_value);
+ if (texture) {
+ if (p_property == "roughness_texture") {
+ if (base_material->get_texture(StandardMaterial3D::TEXTURE_ROUGHNESS).is_null()) {
+ undo_redo->add_do_property(p_edited, "roughness", 1.0);
+
+ bool valid = false;
+ Variant value = p_edited->get("roughness", &valid);
+ if (valid) {
+ undo_redo->add_undo_property(p_edited, "roughness", value);
+ }
+ }
+ } else if (p_property == "metallic_texture") {
+ if (base_material->get_texture(StandardMaterial3D::TEXTURE_METALLIC).is_null()) {
+ undo_redo->add_do_property(p_edited, "metallic", 1.0);
+
+ bool valid = false;
+ Variant value = p_edited->get("metallic", &valid);
+ if (valid) {
+ undo_redo->add_undo_property(p_edited, "metallic", value);
+ }
+ }
+ }
+ }
+ }
+}
+
EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
env.instantiate();
Ref<Sky> sky = memnew(Sky());
@@ -230,9 +301,11 @@ EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() {
env->set_background(Environment::BG_COLOR);
env->set_ambient_source(Environment::AMBIENT_SOURCE_SKY);
env->set_reflection_source(Environment::REFLECTION_SOURCE_SKY);
+
+ EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &EditorInspectorPluginMaterial::_undo_redo_inspector_callback));
}
-MaterialEditorPlugin::MaterialEditorPlugin(EditorNode *p_node) {
+MaterialEditorPlugin::MaterialEditorPlugin() {
Ref<EditorInspectorPluginMaterial> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index 62549843f7..9c6247d59b 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,37 +31,41 @@
#ifndef MATERIAL_EDITOR_PLUGIN_H
#define MATERIAL_EDITOR_PLUGIN_H
-#include "editor/property_editor.h"
-#include "scene/resources/primitive_meshes.h"
-
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "editor/property_editor.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
+#include "scene/gui/color_rect.h"
#include "scene/resources/material.h"
+#include "scene/resources/primitive_meshes.h"
class SubViewportContainer;
class MaterialEditor : public Control {
GDCLASS(MaterialEditor, Control);
- SubViewportContainer *vc;
- SubViewport *viewport;
- MeshInstance3D *sphere_instance;
- MeshInstance3D *box_instance;
- DirectionalLight3D *light1;
- DirectionalLight3D *light2;
- Camera3D *camera;
+ HBoxContainer *layout_2d = nullptr;
+ ColorRect *rect_instance = nullptr;
+
+ SubViewportContainer *vc = nullptr;
+ SubViewport *viewport = nullptr;
+ MeshInstance3D *sphere_instance = nullptr;
+ MeshInstance3D *box_instance = nullptr;
+ DirectionalLight3D *light1 = nullptr;
+ DirectionalLight3D *light2 = nullptr;
+ Camera3D *camera = nullptr;
Ref<SphereMesh> sphere_mesh;
Ref<BoxMesh> box_mesh;
- TextureButton *sphere_switch;
- TextureButton *box_switch;
+ HBoxContainer *layout_3d = nullptr;
- TextureButton *light_1_switch;
- TextureButton *light_2_switch;
+ TextureButton *sphere_switch = nullptr;
+ TextureButton *box_switch = nullptr;
+
+ TextureButton *light_1_switch = nullptr;
+ TextureButton *light_2_switch = nullptr;
Ref<Material> material;
@@ -86,6 +90,8 @@ public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
+ void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
+
EditorInspectorPluginMaterial();
};
@@ -95,7 +101,7 @@ class MaterialEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "Material"; }
- MaterialEditorPlugin(EditorNode *p_node);
+ MaterialEditorPlugin();
};
class StandardMaterial3DConversionPlugin : public EditorResourceConversionPlugin {
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 8cfa1c89e8..7029768479 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -36,7 +36,7 @@ void MeshEditor::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
rot_x -= mm->get_relative().y * 0.01;
rot_y -= mm->get_relative().x * 0.01;
if (rot_x < -Math_PI / 2) {
@@ -49,18 +49,20 @@ void MeshEditor::gui_input(const Ref<InputEvent> &p_event) {
}
void MeshEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- //get_scene()->connect("node_removed",this,"_node_removed");
-
- if (first_enter) {
- //it's in propertyeditor so. could be moved around
-
- light_1_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons")));
- light_1_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons")));
- light_2_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons")));
- light_2_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons")));
- first_enter = false;
- }
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ //get_scene()->connect("node_removed",this,"_node_removed");
+
+ if (first_enter) {
+ //it's in propertyeditor so. could be moved around
+
+ light_1_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons")));
+ light_1_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons")));
+ light_2_switch->set_normal_texture(get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons")));
+ light_2_switch->set_pressed_texture(get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons")));
+ first_enter = false;
+ }
+ } break;
}
}
@@ -176,7 +178,7 @@ void EditorInspectorPluginMesh::parse_begin(Object *p_object) {
add_custom_control(editor);
}
-MeshEditorPlugin::MeshEditorPlugin(EditorNode *p_node) {
+MeshEditorPlugin::MeshEditorPlugin() {
Ref<EditorInspectorPluginMesh> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h
index 1e88b70202..3554b3c1e9 100644
--- a/editor/plugins/mesh_editor_plugin.h
+++ b/editor/plugins/mesh_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef MESH_EDITOR_PLUGIN_H
#define MESH_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
@@ -45,17 +44,17 @@ class MeshEditor : public SubViewportContainer {
float rot_x;
float rot_y;
- SubViewport *viewport;
- MeshInstance3D *mesh_instance;
- Node3D *rotation;
- DirectionalLight3D *light1;
- DirectionalLight3D *light2;
- Camera3D *camera;
+ SubViewport *viewport = nullptr;
+ MeshInstance3D *mesh_instance = nullptr;
+ Node3D *rotation = nullptr;
+ DirectionalLight3D *light1 = nullptr;
+ DirectionalLight3D *light2 = nullptr;
+ Camera3D *camera = nullptr;
Ref<Mesh> mesh;
- TextureButton *light_1_switch;
- TextureButton *light_2_switch;
+ TextureButton *light_1_switch = nullptr;
+ TextureButton *light_2_switch = nullptr;
void _button_pressed(Node *p_button);
bool first_enter;
@@ -85,7 +84,7 @@ class MeshEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "Mesh"; }
- MeshEditorPlugin(EditorNode *p_node);
+ MeshEditorPlugin();
};
#endif
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 7a85c5167b..d33803213a 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,7 @@
#include "mesh_instance_3d_editor_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/collision_shape_3d.h"
@@ -74,7 +75,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(shape);
StaticBody3D *body = memnew(StaticBody3D);
- body->add_child(cshape);
+ body->add_child(cshape, true);
Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
@@ -109,7 +110,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
CollisionShape3D *cshape = memnew(CollisionShape3D);
cshape->set_shape(shape);
StaticBody3D *body = memnew(StaticBody3D);
- body->add_child(cshape);
+ body->add_child(cshape, true);
Node *owner = instance == get_tree()->get_edited_scene_root() ? instance : instance->get_owner();
@@ -398,7 +399,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
}
if (mesh->get_surface_count() == 0) {
- err_dialog->set_text(TTR("Mesh has not surface to create outlines from."));
+ err_dialog->set_text(TTR("Mesh has no surface to create outlines from."));
err_dialog->popup_centered();
return;
} else if (mesh->get_surface_count() == 1 && mesh->surface_get_primitive_type(0) != Mesh::PRIMITIVE_TRIANGLES) {
@@ -446,16 +447,16 @@ MeshInstance3DEditor::MeshInstance3DEditor() {
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MeshInstance3D"), SNAME("EditorIcons")));
options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a StaticBody3D and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection."));
+ options->get_popup()->set_item_tooltip(-1, TTR("Creates a StaticBody3D and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection."));
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection."));
+ options->get_popup()->set_item_tooltip(-1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection."));
options->get_popup()->add_item(TTR("Create Single Convex Collision Sibling"), MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection."));
+ options->get_popup()->set_item_tooltip(-1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection."));
options->get_popup()->add_item(TTR("Create Simplified Convex Collision Sibling"), MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a simplified convex collision shape.\nThis is similar to single collision shape, but can result in a simpler geometry in some cases, at the cost of accuracy."));
+ options->get_popup()->set_item_tooltip(-1, TTR("Creates a simplified convex collision shape.\nThis is similar to single collision shape, but can result in a simpler geometry in some cases, at the cost of accuracy."));
options->get_popup()->add_item(TTR("Create Multiple Convex Collision Siblings"), MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES);
- options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between a single convex collision and a polygon-based collision."));
+ options->get_popup()->set_item_tooltip(-1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between a single convex collision and a polygon-based collision."));
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
options->get_popup()->add_separator();
@@ -515,10 +516,9 @@ void MeshInstance3DEditorPlugin::make_visible(bool p_visible) {
}
}
-MeshInstance3DEditorPlugin::MeshInstance3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+MeshInstance3DEditorPlugin::MeshInstance3DEditorPlugin() {
mesh_editor = memnew(MeshInstance3DEditor);
- editor->get_main_control()->add_child(mesh_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(mesh_editor);
mesh_editor->options->hide();
}
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h
index 98b667c978..36d8eacd98 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.h
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef MESH_INSTANCE_EDITOR_PLUGIN_H
#define MESH_INSTANCE_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/spin_box.h"
@@ -52,17 +51,17 @@ class MeshInstance3DEditor : public Control {
MENU_OPTION_DEBUG_UV2,
};
- MeshInstance3D *node;
+ MeshInstance3D *node = nullptr;
- MenuButton *options;
+ MenuButton *options = nullptr;
- ConfirmationDialog *outline_dialog;
- SpinBox *outline_size;
+ ConfirmationDialog *outline_dialog = nullptr;
+ SpinBox *outline_size = nullptr;
- AcceptDialog *err_dialog;
+ AcceptDialog *err_dialog = nullptr;
- AcceptDialog *debug_uv_dialog;
- Control *debug_uv;
+ AcceptDialog *debug_uv_dialog = nullptr;
+ Control *debug_uv = nullptr;
Vector<Vector2> uv_lines;
void _menu_option(int p_option);
@@ -85,8 +84,7 @@ public:
class MeshInstance3DEditorPlugin : public EditorPlugin {
GDCLASS(MeshInstance3DEditorPlugin, EditorPlugin);
- MeshInstance3DEditor *mesh_editor;
- EditorNode *editor;
+ MeshInstance3DEditor *mesh_editor = nullptr;
public:
virtual String get_name() const override { return "MeshInstance3D"; }
@@ -95,7 +93,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- MeshInstance3DEditorPlugin(EditorNode *p_node);
+ MeshInstance3DEditorPlugin();
~MeshInstance3DEditorPlugin();
};
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 18e7480287..423ec5f4ed 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,7 @@
#include "mesh_library_editor_plugin.h"
+#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "main/main.h"
@@ -61,7 +62,7 @@ void MeshLibraryEditor::_menu_update_confirm(bool p_apply_xforms) {
cd_update->hide();
apply_xforms = p_apply_xforms;
String existing = mesh_library->get_meta("_editor_source_scene");
- ERR_FAIL_COND(existing == "");
+ ERR_FAIL_COND(existing.is_empty());
_import_scene_cbk(existing);
}
@@ -136,9 +137,11 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
continue;
}
- //Transform3D shape_transform = sb->shape_owner_get_transform(E);
-
- //shape_transform.set_origin(shape_transform.get_origin() - phys_offset);
+ Transform3D shape_transform;
+ if (p_apply_xforms) {
+ shape_transform = mi->get_transform();
+ }
+ shape_transform *= sb->get_transform() * sb->shape_owner_get_transform(E);
for (int k = 0; k < sb->shape_owner_get_shape_count(E); k++) {
Ref<Shape3D> collision = sb->shape_owner_get_shape(E, k);
@@ -147,7 +150,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
}
MeshLibrary::ShapeData shape_data;
shape_data.shape = collision;
- shape_data.local_transform = sb->get_transform() * sb->shape_owner_get_transform(E);
+ shape_data.local_transform = shape_transform;
collisions.push_back(shape_data);
}
}
@@ -226,7 +229,7 @@ void MeshLibraryEditor::_menu_cbk(int p_option) {
mesh_library->create_item(mesh_library->get_last_unused_item_id());
} break;
case MENU_OPTION_REMOVE_ITEM: {
- String p = editor->get_inspector()->get_selected_path();
+ String p = InspectorDock::get_inspector_singleton()->get_selected_path();
if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) {
to_erase = p.get_slice("/", 3).to_int();
cd_remove->set_text(vformat(TTR("Remove item %d?"), to_erase));
@@ -251,7 +254,7 @@ void MeshLibraryEditor::_menu_cbk(int p_option) {
void MeshLibraryEditor::_bind_methods() {
}
-MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
+MeshLibraryEditor::MeshLibraryEditor() {
file = memnew(EditorFileDialog);
file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
//not for now?
@@ -268,7 +271,7 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
menu = memnew(MenuButton);
Node3DEditor::get_singleton()->add_control_to_menu_panel(menu);
menu->set_position(Point2(1, 1));
- menu->set_text(TTR("Mesh Library"));
+ menu->set_text(TTR("MeshLibrary"));
menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MeshLibrary"), SNAME("EditorIcons")));
menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM);
menu->get_popup()->add_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM);
@@ -280,15 +283,14 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
menu->get_popup()->connect("id_pressed", callable_mp(this, &MeshLibraryEditor::_menu_cbk));
menu->hide();
- editor = p_editor;
cd_remove = memnew(ConfirmationDialog);
add_child(cd_remove);
cd_remove->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_remove_confirm));
cd_update = memnew(ConfirmationDialog);
add_child(cd_update);
- cd_update->get_ok_button()->set_text("Apply without Transforms");
+ cd_update->get_ok_button()->set_text(TTR("Apply without Transforms"));
cd_update->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_update_confirm), varray(false));
- cd_update->add_button("Apply with Transforms")->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_update_confirm), varray(true));
+ cd_update->add_button(TTR("Apply with Transforms"))->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_update_confirm), varray(true));
}
void MeshLibraryEditorPlugin::edit(Object *p_node) {
@@ -314,14 +316,11 @@ void MeshLibraryEditorPlugin::make_visible(bool p_visible) {
}
}
-MeshLibraryEditorPlugin::MeshLibraryEditorPlugin(EditorNode *p_node) {
- EDITOR_DEF("editors/grid_map/preview_size", 64);
- mesh_library_editor = memnew(MeshLibraryEditor(p_node));
+MeshLibraryEditorPlugin::MeshLibraryEditorPlugin() {
+ mesh_library_editor = memnew(MeshLibraryEditor);
- p_node->get_main_control()->add_child(mesh_library_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(mesh_library_editor);
mesh_library_editor->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
mesh_library_editor->set_end(Point2(0, 22));
mesh_library_editor->hide();
-
- editor = nullptr;
}
diff --git a/editor/plugins/mesh_library_editor_plugin.h b/editor/plugins/mesh_library_editor_plugin.h
index 9e225ffb9b..f4b4288a5f 100644
--- a/editor/plugins/mesh_library_editor_plugin.h
+++ b/editor/plugins/mesh_library_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,21 +31,24 @@
#ifndef MESH_LIBRARY_EDITOR_PLUGIN_H
#define MESH_LIBRARY_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
#include "scene/resources/mesh_library.h"
+class EditorFileDialog;
+class ConfirmationDialog;
+class MenuButton;
+
class MeshLibraryEditor : public Control {
GDCLASS(MeshLibraryEditor, Control);
Ref<MeshLibrary> mesh_library;
- EditorNode *editor;
- MenuButton *menu;
- ConfirmationDialog *cd_remove;
- ConfirmationDialog *cd_update;
- EditorFileDialog *file;
- bool apply_xforms;
- int to_erase;
+ MenuButton *menu = nullptr;
+ ConfirmationDialog *cd_remove = nullptr;
+ ConfirmationDialog *cd_update = nullptr;
+ EditorFileDialog *file = nullptr;
+ bool apply_xforms = false;
+ int to_erase = 0;
enum {
MENU_OPTION_ADD_ITEM,
@@ -55,7 +58,7 @@ class MeshLibraryEditor : public Control {
MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS
};
- int option;
+ int option = 0;
void _import_scene_cbk(const String &p_str);
void _menu_cbk(int p_option);
void _menu_remove_confirm();
@@ -72,14 +75,13 @@ public:
void edit(const Ref<MeshLibrary> &p_mesh_library);
static Error update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge = true, bool p_apply_xforms = false);
- MeshLibraryEditor(EditorNode *p_editor);
+ MeshLibraryEditor();
};
class MeshLibraryEditorPlugin : public EditorPlugin {
GDCLASS(MeshLibraryEditorPlugin, EditorPlugin);
- MeshLibraryEditor *mesh_library_editor;
- EditorNode *editor;
+ MeshLibraryEditor *mesh_library_editor = nullptr;
public:
virtual String get_name() const override { return "MeshLibrary"; }
@@ -88,7 +90,7 @@ public:
virtual bool handles(Object *p_node) const override;
virtual void make_visible(bool p_visible) override;
- MeshLibraryEditorPlugin(EditorNode *p_node);
+ MeshLibraryEditorPlugin();
};
#endif // MESH_LIBRARY_EDITOR_PLUGIN_H
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index 5514bccabb..b54fa41e88 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,8 @@
#include "multimesh_editor_plugin.h"
+#include "editor/editor_node.h"
+#include "editor/scene_tree_editor.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/box_container.h"
@@ -48,7 +50,7 @@ void MultiMeshEditor::_populate() {
Ref<Mesh> mesh;
- if (mesh_source->get_text() == "") {
+ if (mesh_source->get_text().is_empty()) {
Ref<MultiMesh> multimesh;
multimesh = node->get_multimesh();
if (multimesh.is_null()) {
@@ -89,7 +91,7 @@ void MultiMeshEditor::_populate() {
}
}
- if (surface_source->get_text() == "") {
+ if (surface_source->get_text().is_empty()) {
err_dialog->set_text(TTR("No surface source specified."));
err_dialog->popup_centered();
return;
@@ -103,9 +105,9 @@ void MultiMeshEditor::_populate() {
return;
}
- GeometryInstance3D *ss_instance = Object::cast_to<MeshInstance3D>(ss_node);
+ MeshInstance3D *ss_instance = Object::cast_to<MeshInstance3D>(ss_node);
- if (!ss_instance) {
+ if (!ss_instance || !ss_instance->get_mesh().is_valid()) {
err_dialog->set_text(TTR("Surface source is invalid (no geometry)."));
err_dialog->popup_centered();
return;
@@ -113,7 +115,7 @@ void MultiMeshEditor::_populate() {
Transform3D geom_xform = node->get_global_transform().affine_inverse() * ss_instance->get_global_transform();
- Vector<Face3> geometry = ss_instance->get_faces(VisualInstance3D::FACES_SOLID);
+ Vector<Face3> geometry = ss_instance->get_mesh()->get_faces();
if (geometry.size() == 0) {
err_dialog->set_text(TTR("Surface source is invalid (no faces)."));
@@ -198,9 +200,9 @@ void MultiMeshEditor::_populate() {
Basis post_xform;
- post_xform.rotate(xform.basis.get_axis(1), -Math::random(-_rotate_random, _rotate_random) * Math_PI);
- post_xform.rotate(xform.basis.get_axis(2), -Math::random(-_tilt_random, _tilt_random) * Math_PI);
- post_xform.rotate(xform.basis.get_axis(0), -Math::random(-_tilt_random, _tilt_random) * Math_PI);
+ post_xform.rotate(xform.basis.get_column(1), -Math::random(-_rotate_random, _rotate_random) * Math_PI);
+ post_xform.rotate(xform.basis.get_column(2), -Math::random(-_tilt_random, _tilt_random) * Math_PI);
+ post_xform.rotate(xform.basis.get_column(0), -Math::random(-_tilt_random, _tilt_random) * Math_PI);
xform.basis = post_xform * xform.basis;
//xform.basis.orthonormalize();
@@ -375,10 +377,9 @@ void MultiMeshEditorPlugin::make_visible(bool p_visible) {
}
}
-MultiMeshEditorPlugin::MultiMeshEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+MultiMeshEditorPlugin::MultiMeshEditorPlugin() {
multimesh_editor = memnew(MultiMeshEditor);
- editor->get_main_control()->add_child(multimesh_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(multimesh_editor);
multimesh_editor->options->hide();
}
diff --git a/editor/plugins/multimesh_editor_plugin.h b/editor/plugins/multimesh_editor_plugin.h
index 2cdd7cf504..5773989d0d 100644
--- a/editor/plugins/multimesh_editor_plugin.h
+++ b/editor/plugins/multimesh_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,36 +31,38 @@
#ifndef MULTIMESH_EDITOR_PLUGIN_H
#define MULTIMESH_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/multimesh_instance_3d.h"
+#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
+class SceneTreeDialog;
+
class MultiMeshEditor : public Control {
GDCLASS(MultiMeshEditor, Control);
friend class MultiMeshEditorPlugin;
- AcceptDialog *err_dialog;
- MenuButton *options;
- MultiMeshInstance3D *_last_pp_node;
- bool browsing_source;
+ AcceptDialog *err_dialog = nullptr;
+ MenuButton *options = nullptr;
+ MultiMeshInstance3D *_last_pp_node = nullptr;
+ bool browsing_source = false;
- Panel *panel;
- MultiMeshInstance3D *node;
+ Panel *panel = nullptr;
+ MultiMeshInstance3D *node = nullptr;
- LineEdit *surface_source;
- LineEdit *mesh_source;
+ LineEdit *surface_source = nullptr;
+ LineEdit *mesh_source = nullptr;
- SceneTreeDialog *std;
+ SceneTreeDialog *std = nullptr;
- ConfirmationDialog *populate_dialog;
- OptionButton *populate_axis;
- HSlider *populate_rotate_random;
- HSlider *populate_tilt_random;
- SpinBox *populate_scale_random;
- SpinBox *populate_scale;
- SpinBox *populate_amount;
+ ConfirmationDialog *populate_dialog = nullptr;
+ OptionButton *populate_axis = nullptr;
+ HSlider *populate_rotate_random = nullptr;
+ HSlider *populate_tilt_random = nullptr;
+ SpinBox *populate_scale_random = nullptr;
+ SpinBox *populate_scale = nullptr;
+ SpinBox *populate_amount = nullptr;
enum Menu {
MENU_OPTION_POPULATE
@@ -83,8 +85,7 @@ public:
class MultiMeshEditorPlugin : public EditorPlugin {
GDCLASS(MultiMeshEditorPlugin, EditorPlugin);
- MultiMeshEditor *multimesh_editor;
- EditorNode *editor;
+ MultiMeshEditor *multimesh_editor = nullptr;
public:
virtual String get_name() const override { return "MultiMesh"; }
@@ -93,7 +94,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- MultiMeshEditorPlugin(EditorNode *p_node);
+ MultiMeshEditorPlugin();
~MultiMeshEditorPlugin();
};
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index 9971d3111d..8f3553b8cf 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -106,17 +106,14 @@ void NavigationPolygonEditor::_create_resource() {
undo_redo->create_action(TTR("Create Navigation Polygon"));
undo_redo->add_do_method(node, "set_navigation_polygon", Ref<NavigationPolygon>(memnew(NavigationPolygon)));
- undo_redo->add_undo_method(node, "set_navigation_polygon", Variant(REF()));
+ undo_redo->add_undo_method(node, "set_navigation_polygon", Variant(Ref<RefCounted>()));
undo_redo->commit_action();
_menu_option(MODE_CREATE);
}
-NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) :
- AbstractPolygon2DEditor(p_editor) {
- node = nullptr;
-}
+NavigationPolygonEditor::NavigationPolygonEditor() {}
-NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) :
- AbstractPolygon2DEditorPlugin(p_node, memnew(NavigationPolygonEditor(p_node)), "NavigationRegion2D") {
+NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin() :
+ AbstractPolygon2DEditorPlugin(memnew(NavigationPolygonEditor), "NavigationRegion2D") {
}
diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h
index 0f5928d416..7550b75fa3 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.h
+++ b/editor/plugins/navigation_polygon_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,7 +37,7 @@
class NavigationPolygonEditor : public AbstractPolygon2DEditor {
GDCLASS(NavigationPolygonEditor, AbstractPolygon2DEditor);
- NavigationRegion2D *node;
+ NavigationRegion2D *node = nullptr;
Ref<NavigationPolygon> _ensure_navpoly() const;
@@ -57,14 +57,14 @@ protected:
virtual void _create_resource() override;
public:
- NavigationPolygonEditor(EditorNode *p_editor);
+ NavigationPolygonEditor();
};
class NavigationPolygonEditorPlugin : public AbstractPolygon2DEditorPlugin {
GDCLASS(NavigationPolygonEditorPlugin, AbstractPolygon2DEditorPlugin);
public:
- NavigationPolygonEditorPlugin(EditorNode *p_node);
+ NavigationPolygonEditorPlugin();
};
#endif // NAVIGATIONPOLYGONEDITORPLUGIN_H
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 74fbef3caf..6829e25ef3 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,6 +33,8 @@
#include "core/math/convex_hull.h"
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/audio_stream_player_3d.h"
@@ -45,6 +47,7 @@
#include "scene/3d/gpu_particles_3d.h"
#include "scene/3d/gpu_particles_collision_3d.h"
#include "scene/3d/joint_3d.h"
+#include "scene/3d/label_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
@@ -117,52 +120,52 @@ void EditorNode3DGizmo::redraw() {
}
}
-String EditorNode3DGizmo::get_handle_name(int p_id) const {
+String EditorNode3DGizmo::get_handle_name(int p_id, bool p_secondary) const {
String ret;
- if (GDVIRTUAL_CALL(_get_handle_name, p_id, ret)) {
+ if (GDVIRTUAL_CALL(_get_handle_name, p_id, p_secondary, ret)) {
return ret;
}
ERR_FAIL_COND_V(!gizmo_plugin, "");
- return gizmo_plugin->get_handle_name(this, p_id);
+ return gizmo_plugin->get_handle_name(this, p_id, p_secondary);
}
-bool EditorNode3DGizmo::is_handle_highlighted(int p_id) const {
+bool EditorNode3DGizmo::is_handle_highlighted(int p_id, bool p_secondary) const {
bool success;
- if (GDVIRTUAL_CALL(_is_handle_highlighted, p_id, success)) {
+ if (GDVIRTUAL_CALL(_is_handle_highlighted, p_id, p_secondary, success)) {
return success;
}
ERR_FAIL_COND_V(!gizmo_plugin, false);
- return gizmo_plugin->is_handle_highlighted(this, p_id);
+ return gizmo_plugin->is_handle_highlighted(this, p_id, p_secondary);
}
-Variant EditorNode3DGizmo::get_handle_value(int p_id) const {
+Variant EditorNode3DGizmo::get_handle_value(int p_id, bool p_secondary) const {
Variant value;
- if (GDVIRTUAL_CALL(_get_handle_value, p_id, value)) {
+ if (GDVIRTUAL_CALL(_get_handle_value, p_id, p_secondary, value)) {
return value;
}
ERR_FAIL_COND_V(!gizmo_plugin, Variant());
- return gizmo_plugin->get_handle_value(this, p_id);
+ return gizmo_plugin->get_handle_value(this, p_id, p_secondary);
}
-void EditorNode3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) {
- if (GDVIRTUAL_CALL(_set_handle, p_id, p_camera, p_point)) {
+void EditorNode3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
+ if (GDVIRTUAL_CALL(_set_handle, p_id, p_secondary, p_camera, p_point)) {
return;
}
ERR_FAIL_COND(!gizmo_plugin);
- gizmo_plugin->set_handle(this, p_id, p_camera, p_point);
+ gizmo_plugin->set_handle(this, p_id, p_secondary, p_camera, p_point);
}
-void EditorNode3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cancel) {
- if (GDVIRTUAL_CALL(_commit_handle, p_id, p_restore, p_cancel)) {
+void EditorNode3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
+ if (GDVIRTUAL_CALL(_commit_handle, p_id, p_secondary, p_restore, p_cancel)) {
return;
}
ERR_FAIL_COND(!gizmo_plugin);
- gizmo_plugin->commit_handle(this, p_id, p_restore, p_cancel);
+ gizmo_plugin->commit_handle(this, p_id, p_secondary, p_restore, p_cancel);
}
int EditorNode3DGizmo::subgizmos_intersect_ray(Camera3D *p_camera, const Vector2 &p_point) const {
@@ -244,8 +247,10 @@ void EditorNode3DGizmo::Instance::create_instance(Node3D *p_base, bool p_hidden)
RS::get_singleton()->instance_geometry_set_flag(instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
}
-void EditorNode3DGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, const Ref<Material> &p_material, const Transform3D &p_xform, const Ref<SkinReference> &p_skin_reference) {
+void EditorNode3DGizmo::add_mesh(const Ref<Mesh> &p_mesh, const Ref<Material> &p_material, const Transform3D &p_xform, const Ref<SkinReference> &p_skin_reference) {
ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_COND_MSG(!p_mesh.is_valid(), "EditorNode3DGizmo.add_mesh() requires a valid Mesh resource.");
+
Instance ins;
ins.mesh = p_mesh;
@@ -322,37 +327,34 @@ void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material,
ERR_FAIL_COND(!spatial_node);
Instance ins;
- Vector<Vector3> vs;
- Vector<Vector2> uv;
- Vector<Color> colors;
-
- vs.push_back(Vector3(-p_scale, p_scale, 0));
- vs.push_back(Vector3(p_scale, p_scale, 0));
- vs.push_back(Vector3(p_scale, -p_scale, 0));
- vs.push_back(Vector3(-p_scale, -p_scale, 0));
-
- uv.push_back(Vector2(0, 0));
- uv.push_back(Vector2(1, 0));
- uv.push_back(Vector2(1, 1));
- uv.push_back(Vector2(0, 1));
-
- colors.push_back(p_modulate);
- colors.push_back(p_modulate);
- colors.push_back(p_modulate);
- colors.push_back(p_modulate);
+ Vector<Vector3> vs = {
+ Vector3(-p_scale, p_scale, 0),
+ Vector3(p_scale, p_scale, 0),
+ Vector3(p_scale, -p_scale, 0),
+ Vector3(-p_scale, -p_scale, 0)
+ };
+
+ Vector<Vector2> uv = {
+ Vector2(0, 0),
+ Vector2(1, 0),
+ Vector2(1, 1),
+ Vector2(0, 1)
+ };
+
+ Vector<Color> colors = {
+ p_modulate,
+ p_modulate,
+ p_modulate,
+ p_modulate
+ };
+
+ Vector<int> indices = { 0, 1, 2, 0, 2, 3 };
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
Array a;
a.resize(Mesh::ARRAY_MAX);
a[Mesh::ARRAY_VERTEX] = vs;
a[Mesh::ARRAY_TEX_UV] = uv;
- Vector<int> indices;
- indices.push_back(0);
- indices.push_back(1);
- indices.push_back(2);
- indices.push_back(0);
- indices.push_back(2);
- indices.push_back(3);
a[Mesh::ARRAY_INDEX] = indices;
a[Mesh::ARRAY_COLOR] = colors;
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
@@ -408,7 +410,8 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<
}
bool is_current_hover_gizmo = Node3DEditor::get_singleton()->get_current_hover_gizmo() == this;
- int current_hover_handle = Node3DEditor::get_singleton()->get_current_hover_gizmo_handle();
+ bool current_hover_handle_secondary;
+ int current_hover_handle = Node3DEditor::get_singleton()->get_current_hover_gizmo_handle(current_hover_handle_secondary);
Instance ins;
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
@@ -422,12 +425,12 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<
Color *w = colors.ptrw();
for (int i = 0; i < p_handles.size(); i++) {
Color col(1, 1, 1, 1);
- if (is_handle_highlighted(i)) {
+ if (is_handle_highlighted(i, p_secondary)) {
col = Color(0, 0, 1, 0.9);
}
int id = p_ids.is_empty() ? i : p_ids[i];
- if (!is_current_hover_gizmo || current_hover_handle != id) {
+ if (!is_current_hover_gizmo || current_hover_handle != id || p_secondary != current_hover_handle_secondary) {
col.a = 0.8;
}
@@ -473,7 +476,7 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<
}
}
-void EditorNode3DGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position, const Transform3D &p_xform) {
+void EditorNode3DGizmo::add_solid_box(const Ref<Material> &p_material, Vector3 p_size, Vector3 p_position, const Transform3D &p_xform) {
ERR_FAIL_COND(!spatial_node);
BoxMesh box_mesh;
@@ -572,8 +575,9 @@ bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector
return false;
}
-void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2 &p_point, bool p_shift_pressed, int &r_id) {
+void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2 &p_point, bool p_shift_pressed, int &r_id, bool &r_secondary) {
r_id = -1;
+ r_secondary = false;
ERR_FAIL_COND(!spatial_node);
ERR_FAIL_COND(!valid);
@@ -585,7 +589,7 @@ void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2
Transform3D camera_xform = p_camera->get_global_transform();
Transform3D t = spatial_node->get_global_transform();
if (billboard_handle) {
- t.set_look_at(t.origin, t.origin - camera_xform.basis.get_axis(2), camera_xform.basis.get_axis(1));
+ t.set_look_at(t.origin, t.origin - camera_xform.basis.get_column(2), camera_xform.basis.get_column(1));
}
float min_d = 1e20;
@@ -603,6 +607,7 @@ void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2
} else {
r_id = secondary_handle_ids[i];
}
+ r_secondary = true;
}
}
}
@@ -626,6 +631,7 @@ void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2
} else {
r_id = handle_ids[i];
}
+ r_secondary = false;
}
}
}
@@ -659,7 +665,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
Transform3D orig_camera_transform = p_camera->get_camera_transform();
if (!orig_camera_transform.origin.is_equal_approx(t.origin) &&
- ABS(orig_camera_transform.basis.get_axis(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) {
+ ABS(orig_camera_transform.basis.get_column(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) {
p_camera->look_at(t.origin);
}
@@ -683,13 +689,13 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
}
if (collision_segments.size()) {
- Plane camp(-p_camera->get_transform().basis.get_axis(2).normalized(), p_camera->get_transform().origin);
+ Plane camp(-p_camera->get_transform().basis.get_column(2).normalized(), p_camera->get_transform().origin);
int vc = collision_segments.size();
const Vector3 *vptr = collision_segments.ptr();
Transform3D t = spatial_node->get_global_transform();
if (billboard_handle) {
- t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+ t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_column(2), p_camera->get_transform().basis.get_column(1));
}
Vector3 cp;
@@ -736,7 +742,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
Transform3D gt = spatial_node->get_global_transform();
if (billboard_handle) {
- gt.set_look_at(gt.origin, gt.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
+ gt.set_look_at(gt.origin, gt.origin - p_camera->get_transform().basis.get_column(2), p_camera->get_transform().basis.get_column(1));
}
Transform3D ai = gt.affine_inverse();
@@ -837,12 +843,12 @@ void EditorNode3DGizmo::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_subgizmo_selection"), &EditorNode3DGizmo::get_subgizmo_selection);
GDVIRTUAL_BIND(_redraw);
- GDVIRTUAL_BIND(_get_handle_name, "id");
- GDVIRTUAL_BIND(_is_handle_highlighted, "id");
+ GDVIRTUAL_BIND(_get_handle_name, "id", "secondary");
+ GDVIRTUAL_BIND(_is_handle_highlighted, "id", "secondary");
- GDVIRTUAL_BIND(_get_handle_value, "id");
- GDVIRTUAL_BIND(_set_handle, "id", "camera", "point");
- GDVIRTUAL_BIND(_commit_handle, "id", "restore", "cancel");
+ GDVIRTUAL_BIND(_get_handle_value, "id", "secondary");
+ GDVIRTUAL_BIND(_set_handle, "id", "secondary", "camera", "point");
+ GDVIRTUAL_BIND(_commit_handle, "id", "secondary", "restore", "cancel");
GDVIRTUAL_BIND(_subgizmos_intersect_ray, "camera", "point");
GDVIRTUAL_BIND(_subgizmos_intersect_frustum, "camera", "frustum");
@@ -871,7 +877,7 @@ EditorNode3DGizmo::~EditorNode3DGizmo() {
/////
void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
- Color instantiated_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6));
+ Color instantiated_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instantiated");
Vector<Ref<StandardMaterial3D>> mats;
@@ -913,7 +919,7 @@ void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color
}
void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top, const Color &p_albedo) {
- Color instantiated_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6));
+ Color instantiated_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instantiated");
Vector<Ref<StandardMaterial3D>> icons;
@@ -1052,19 +1058,18 @@ void EditorNode3DGizmoPlugin::_bind_methods() {
GDVIRTUAL_BIND(_is_selectable_when_hidden);
GDVIRTUAL_BIND(_redraw, "gizmo");
- GDVIRTUAL_BIND(_get_handle_name, "gizmo", "handle_id");
- GDVIRTUAL_BIND(_is_handle_highlighted, "gizmo", "handle_id");
- GDVIRTUAL_BIND(_get_handle_value, "gizmo", "handle_id");
+ GDVIRTUAL_BIND(_get_handle_name, "gizmo", "handle_id", "secondary");
+ GDVIRTUAL_BIND(_is_handle_highlighted, "gizmo", "handle_id", "secondary");
+ GDVIRTUAL_BIND(_get_handle_value, "gizmo", "handle_id", "secondary");
- GDVIRTUAL_BIND(_set_handle, "gizmo", "handle_id", "camera", "screen_pos");
- GDVIRTUAL_BIND(_commit_handle, "gizmo", "handle_id", "restore", "cancel");
+ GDVIRTUAL_BIND(_set_handle, "gizmo", "handle_id", "secondary", "camera", "screen_pos");
+ GDVIRTUAL_BIND(_commit_handle, "gizmo", "handle_id", "secondary", "restore", "cancel");
GDVIRTUAL_BIND(_subgizmos_intersect_ray, "gizmo", "camera", "screen_pos");
GDVIRTUAL_BIND(_subgizmos_intersect_frustum, "gizmo", "camera", "frustum_planes");
GDVIRTUAL_BIND(_get_subgizmo_transform, "gizmo", "subgizmo_id");
GDVIRTUAL_BIND(_set_subgizmo_transform, "gizmo", "subgizmo_id", "transform");
GDVIRTUAL_BIND(_commit_subgizmos, "gizmo", "ids", "restores", "cancel");
- ;
}
bool EditorNode3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@@ -1108,36 +1113,36 @@ void EditorNode3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
GDVIRTUAL_CALL(_redraw, p_gizmo);
}
-bool EditorNode3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+bool EditorNode3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
bool ret;
- if (GDVIRTUAL_CALL(_is_handle_highlighted, Ref<EditorNode3DGizmo>(p_gizmo), p_id, ret)) {
+ if (GDVIRTUAL_CALL(_is_handle_highlighted, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret)) {
return ret;
}
return false;
}
-String EditorNode3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String EditorNode3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
String ret;
- if (GDVIRTUAL_CALL(_get_handle_name, Ref<EditorNode3DGizmo>(p_gizmo), p_id, ret)) {
+ if (GDVIRTUAL_CALL(_get_handle_name, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret)) {
return ret;
}
return "";
}
-Variant EditorNode3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant EditorNode3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
Variant ret;
- if (GDVIRTUAL_CALL(_get_handle_value, Ref<EditorNode3DGizmo>(p_gizmo), p_id, ret)) {
+ if (GDVIRTUAL_CALL(_get_handle_value, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret)) {
return ret;
}
return Variant();
}
-void EditorNode3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
- GDVIRTUAL_CALL(_set_handle, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_camera, p_point);
+void EditorNode3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
+ GDVIRTUAL_CALL(_set_handle, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, p_camera, p_point);
}
-void EditorNode3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
- GDVIRTUAL_CALL(_commit_handle, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_restore, p_cancel);
+void EditorNode3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
+ GDVIRTUAL_CALL(_commit_handle, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, p_restore, p_cancel);
}
int EditorNode3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
@@ -1242,7 +1247,7 @@ int Light3DGizmoPlugin::get_priority() const {
return -1;
}
-String Light3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String Light3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
if (p_id == 0) {
return "Radius";
} else {
@@ -1250,7 +1255,7 @@ String Light3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int
}
}
-Variant Light3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant Light3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
if (p_id == 0) {
return light->get_param(Light3D::PARAM_RANGE);
@@ -1289,7 +1294,7 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec
return Math::rad2deg(a);
}
-void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
Transform3D gt = light->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -1314,7 +1319,7 @@ void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
light->set_param(Light3D::PARAM_RANGE, d);
} else if (Object::cast_to<OmniLight3D>(light)) {
- Plane cp = Plane(p_camera->get_transform().basis.get_axis(2), gt.origin);
+ Plane cp = Plane(p_camera->get_transform().basis.get_column(2), gt.origin);
Vector3 inters;
if (cp.intersects_ray(ray_from, ray_dir, &inters)) {
@@ -1333,7 +1338,7 @@ void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
}
}
-void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
if (p_cancel) {
light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore);
@@ -1475,9 +1480,10 @@ void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(points_primary, material_primary, false, color);
p_gizmo->add_lines(points_secondary, material_secondary, false, color);
- Vector<Vector3> handles;
- handles.push_back(Vector3(0, 0, -r));
- handles.push_back(Vector3(w, 0, -d));
+ Vector<Vector3> handles = {
+ Vector3(0, 0, -r),
+ Vector3(w, 0, -d)
+ };
p_gizmo->add_handles(handles, get_material("handles"));
p_gizmo->add_unscaled_billboard(icon, 0.05, color);
@@ -1506,16 +1512,16 @@ int AudioStreamPlayer3DGizmoPlugin::get_priority() const {
return -1;
}
-String AudioStreamPlayer3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String AudioStreamPlayer3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
return "Emission Radius";
}
-Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
return player->get_emission_angle();
}
-void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
Transform3D gt = player->get_global_transform();
@@ -1552,7 +1558,7 @@ void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo
}
}
-void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
if (p_cancel) {
@@ -1623,7 +1629,7 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
//////
AudioListener3DGizmoPlugin::AudioListener3DGizmoPlugin() {
- create_icon_material("audio_listener_3d_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoAudioListener3D", "EditorIcons"));
+ create_icon_material("audio_listener_3d_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoAudioListener3D"), SNAME("EditorIcons")));
}
bool AudioListener3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@@ -1664,7 +1670,7 @@ int Camera3DGizmoPlugin::get_priority() const {
return -1;
}
-String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
@@ -1674,7 +1680,7 @@ String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, in
}
}
-Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
@@ -1684,7 +1690,7 @@ Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo,
}
}
-void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
Transform3D gt = camera->get_global_transform();
@@ -1713,7 +1719,7 @@ void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
}
}
-void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
@@ -1885,6 +1891,7 @@ void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
OccluderInstance3DGizmoPlugin::OccluderInstance3DGizmoPlugin() {
create_material("line_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1)));
+ create_handle_material("handles");
}
bool OccluderInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@@ -1899,6 +1906,189 @@ int OccluderInstance3DGizmoPlugin::get_priority() const {
return -1;
}
+String OccluderInstance3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ const OccluderInstance3D *cs = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+
+ Ref<Occluder3D> o = cs->get_occluder();
+ if (o.is_null()) {
+ return "";
+ }
+
+ if (Object::cast_to<SphereOccluder3D>(*o)) {
+ return "Radius";
+ }
+
+ if (Object::cast_to<BoxOccluder3D>(*o) || Object::cast_to<QuadOccluder3D>(*o)) {
+ return "Size";
+ }
+
+ return "";
+}
+
+Variant OccluderInstance3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+
+ Ref<Occluder3D> o = oi->get_occluder();
+ if (o.is_null()) {
+ return Variant();
+ }
+
+ if (Object::cast_to<SphereOccluder3D>(*o)) {
+ Ref<SphereOccluder3D> so = o;
+ return so->get_radius();
+ }
+
+ if (Object::cast_to<BoxOccluder3D>(*o)) {
+ Ref<BoxOccluder3D> bo = o;
+ return bo->get_size();
+ }
+
+ if (Object::cast_to<QuadOccluder3D>(*o)) {
+ Ref<QuadOccluder3D> qo = o;
+ return qo->get_size();
+ }
+
+ return Variant();
+}
+
+void OccluderInstance3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
+ OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+
+ Ref<Occluder3D> o = oi->get_occluder();
+ if (o.is_null()) {
+ return;
+ }
+
+ Transform3D gt = oi->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ bool snap_enabled = Node3DEditor::get_singleton()->is_snap_enabled();
+ float snap = Node3DEditor::get_singleton()->get_translate_snap();
+
+ if (Object::cast_to<SphereOccluder3D>(*o)) {
+ Ref<SphereOccluder3D> so = o;
+ Vector3 ra, rb;
+ Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
+ float d = ra.x;
+ if (snap_enabled) {
+ d = Math::snapped(d, snap);
+ }
+
+ if (d < 0.001) {
+ d = 0.001;
+ }
+
+ so->set_radius(d);
+ }
+
+ if (Object::cast_to<BoxOccluder3D>(*o)) {
+ Vector3 axis;
+ axis[p_id] = 1.0;
+ Ref<BoxOccluder3D> bo = o;
+ Vector3 ra, rb;
+ Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ float d = ra[p_id];
+ if (snap_enabled) {
+ d = Math::snapped(d, snap);
+ }
+
+ if (d < 0.001) {
+ d = 0.001;
+ }
+
+ Vector3 he = bo->get_size();
+ he[p_id] = d * 2;
+ bo->set_size(he);
+ }
+
+ if (Object::cast_to<QuadOccluder3D>(*o)) {
+ Ref<QuadOccluder3D> qo = o;
+ Plane p = Plane(Vector3(0.0f, 0.0f, 1.0f), 0.0f);
+ Vector3 intersection;
+ if (!p.intersects_segment(sg[0], sg[1], &intersection)) {
+ return;
+ }
+
+ if (p_id == 2) {
+ Vector2 s = Vector2(intersection.x, intersection.y) * 2.0f;
+ if (snap_enabled) {
+ s = s.snapped(Vector2(snap, snap));
+ }
+ s = s.max(Vector2(0.001, 0.001));
+ qo->set_size(s);
+ } else {
+ float d = intersection[p_id];
+ if (snap_enabled) {
+ d = Math::snapped(d, snap);
+ }
+
+ if (d < 0.001) {
+ d = 0.001;
+ }
+
+ Vector2 he = qo->get_size();
+ he[p_id] = d * 2.0f;
+ qo->set_size(he);
+ }
+ }
+}
+
+void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
+ OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+
+ Ref<Occluder3D> o = oi->get_occluder();
+ if (o.is_null()) {
+ return;
+ }
+
+ if (Object::cast_to<SphereOccluder3D>(*o)) {
+ Ref<SphereOccluder3D> so = o;
+ if (p_cancel) {
+ so->set_radius(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Sphere Shape Radius"));
+ ur->add_do_method(so.ptr(), "set_radius", so->get_radius());
+ ur->add_undo_method(so.ptr(), "set_radius", p_restore);
+ ur->commit_action();
+ }
+
+ if (Object::cast_to<BoxOccluder3D>(*o)) {
+ Ref<BoxOccluder3D> bo = o;
+ if (p_cancel) {
+ bo->set_size(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Box Shape Size"));
+ ur->add_do_method(bo.ptr(), "set_size", bo->get_size());
+ ur->add_undo_method(bo.ptr(), "set_size", p_restore);
+ ur->commit_action();
+ }
+
+ if (Object::cast_to<QuadOccluder3D>(*o)) {
+ Ref<QuadOccluder3D> qo = o;
+ if (p_cancel) {
+ qo->set_size(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Box Shape Size"));
+ ur->add_do_method(qo.ptr(), "set_size", qo->get_size());
+ ur->add_undo_method(qo.ptr(), "set_size", p_restore);
+ ur->commit_action();
+ }
+}
+
void OccluderInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
OccluderInstance3D *occluder_instance = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
@@ -1916,6 +2106,35 @@ void OccluderInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
}
+
+ Ref<Material> handles_material = get_material("handles");
+ if (Object::cast_to<SphereOccluder3D>(*o)) {
+ Ref<SphereOccluder3D> so = o;
+ float r = so->get_radius();
+ Vector<Vector3> handles = { Vector3(r, 0, 0) };
+ p_gizmo->add_handles(handles, handles_material);
+ }
+
+ if (Object::cast_to<BoxOccluder3D>(*o)) {
+ Ref<BoxOccluder3D> bo = o;
+
+ Vector<Vector3> handles;
+ for (int i = 0; i < 3; i++) {
+ Vector3 ax;
+ ax[i] = bo->get_size()[i] / 2;
+ handles.push_back(ax);
+ }
+
+ p_gizmo->add_handles(handles, handles_material);
+ }
+
+ if (Object::cast_to<QuadOccluder3D>(*o)) {
+ Ref<QuadOccluder3D> qo = o;
+ Vector2 size = qo->get_size();
+ Vector3 s = Vector3(size.x, size.y, 0.0f) / 2.0f;
+ Vector<Vector3> handles = { Vector3(s.x, 0.0f, 0.0f), Vector3(0.0f, s.y, 0.0f), Vector3(s.x, s.y, 0.0f) };
+ p_gizmo->add_handles(handles, handles_material);
+ }
}
/////
@@ -1952,6 +2171,38 @@ void Sprite3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///
+Label3DGizmoPlugin::Label3DGizmoPlugin() {
+}
+
+bool Label3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Label3D>(p_spatial) != nullptr;
+}
+
+String Label3DGizmoPlugin::get_gizmo_name() const {
+ return "Label3D";
+}
+
+int Label3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+bool Label3DGizmoPlugin::can_be_hidden() const {
+ return false;
+}
+
+void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ Label3D *label = Object::cast_to<Label3D>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<TriangleMesh> tm = label->generate_triangle_mesh();
+ if (tm.is_valid()) {
+ p_gizmo->add_collision_triangles(tm);
+ }
+}
+
+///
+
Position3DGizmoPlugin::Position3DGizmoPlugin() {
pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
cursor_points = Vector<Vector3>();
@@ -2033,7 +2284,7 @@ void Position3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
////
PhysicalBone3DGizmoPlugin::PhysicalBone3DGizmoPlugin() {
- create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
+ create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
}
bool PhysicalBone3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@@ -2166,7 +2417,7 @@ void PhysicalBone3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
/////
RayCast3DGizmoPlugin::RayCast3DGizmoPlugin() {
- const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
const float gizmo_value = gizmo_color.get_v();
const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
@@ -2208,10 +2459,10 @@ void SpringArm3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
- Vector<Vector3> lines;
-
- lines.push_back(Vector3());
- lines.push_back(Vector3(0, 0, 1.0) * spring_arm->get_length());
+ Vector<Vector3> lines = {
+ Vector3(),
+ Vector3(0, 0, 1.0) * spring_arm->get_length()
+ };
Ref<StandardMaterial3D> material = get_material("shape_material", p_gizmo);
@@ -2220,7 +2471,7 @@ void SpringArm3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
SpringArm3DGizmoPlugin::SpringArm3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
}
@@ -2239,7 +2490,7 @@ int SpringArm3DGizmoPlugin::get_priority() const {
/////
VehicleWheel3DGizmoPlugin::VehicleWheel3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
}
@@ -2310,7 +2561,7 @@ void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///////////
SoftDynamicBody3DGizmoPlugin::SoftDynamicBody3DGizmoPlugin() {
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
create_handle_material("handles");
}
@@ -2368,21 +2619,21 @@ void SoftDynamicBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_triangles(tm);
}
-String SoftDynamicBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String SoftDynamicBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
return "SoftDynamicBody3D pin point";
}
-Variant SoftDynamicBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant SoftDynamicBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
return Variant(soft_body->is_point_pinned(p_id));
}
-void SoftDynamicBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void SoftDynamicBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
soft_body->pin_point_toggle(p_id);
}
-bool SoftDynamicBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+bool SoftDynamicBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
return soft_body->is_point_pinned(p_id);
}
@@ -2409,7 +2660,7 @@ int VisibleOnScreenNotifier3DGizmoPlugin::get_priority() const {
return -1;
}
-String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
return "Size X";
@@ -2428,12 +2679,12 @@ String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DG
return "";
}
-Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node());
return notifier->get_aabb();
}
-void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node());
Transform3D gt = notifier->get_global_transform();
@@ -2485,7 +2736,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p
}
}
-void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node());
if (p_cancel) {
@@ -2579,7 +2830,7 @@ void CPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
GPUParticles3DGizmoPlugin::GPUParticles3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
create_material("particles_material", gizmo_color);
- gizmo_color.a = 0.1;
+ gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0);
create_material("particles_solid_material", gizmo_color);
create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoGPUParticles3D"), SNAME("EditorIcons")));
create_handle_material("handles");
@@ -2601,7 +2852,7 @@ bool GPUParticles3DGizmoPlugin::is_selectable_when_hidden() const {
return true;
}
-String GPUParticles3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String GPUParticles3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
return "Size X";
@@ -2620,12 +2871,12 @@ String GPUParticles3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_giz
return "";
}
-Variant GPUParticles3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant GPUParticles3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
return particles->get_visibility_aabb();
}
-void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
Transform3D gt = particles->get_global_transform();
@@ -2676,7 +2927,7 @@ void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int
}
}
-void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
if (p_cancel) {
@@ -2762,35 +3013,35 @@ int GPUParticlesCollision3DGizmoPlugin::get_priority() const {
return -1;
}
-String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
const Node3D *cs = p_gizmo->get_spatial_node();
- if (Object::cast_to<GPUParticlesCollisionSphere>(cs) || Object::cast_to<GPUParticlesAttractorSphere>(cs)) {
+ if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
return "Radius";
}
- if (Object::cast_to<GPUParticlesCollisionBox>(cs) || Object::cast_to<GPUParticlesAttractorBox>(cs) || Object::cast_to<GPUParticlesAttractorVectorField>(cs) || Object::cast_to<GPUParticlesCollisionSDF>(cs) || Object::cast_to<GPUParticlesCollisionHeightField>(cs)) {
+ if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
return "Extents";
}
return "";
}
-Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
const Node3D *cs = p_gizmo->get_spatial_node();
- if (Object::cast_to<GPUParticlesCollisionSphere>(cs) || Object::cast_to<GPUParticlesAttractorSphere>(cs)) {
+ if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
return p_gizmo->get_spatial_node()->call("get_radius");
}
- if (Object::cast_to<GPUParticlesCollisionBox>(cs) || Object::cast_to<GPUParticlesAttractorBox>(cs) || Object::cast_to<GPUParticlesAttractorVectorField>(cs) || Object::cast_to<GPUParticlesCollisionSDF>(cs) || Object::cast_to<GPUParticlesCollisionHeightField>(cs)) {
+ if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
return Vector3(p_gizmo->get_spatial_node()->call("get_extents"));
}
return Variant();
}
-void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Node3D *sn = p_gizmo->get_spatial_node();
Transform3D gt = sn->get_global_transform();
@@ -2801,7 +3052,7 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g
Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
- if (Object::cast_to<GPUParticlesCollisionSphere>(sn) || Object::cast_to<GPUParticlesAttractorSphere>(sn)) {
+ if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
float d = ra.x;
@@ -2816,7 +3067,7 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g
sn->call("set_radius", d);
}
- if (Object::cast_to<GPUParticlesCollisionBox>(sn) || Object::cast_to<GPUParticlesAttractorBox>(sn) || Object::cast_to<GPUParticlesAttractorVectorField>(sn) || Object::cast_to<GPUParticlesCollisionSDF>(sn) || Object::cast_to<GPUParticlesCollisionHeightField>(sn)) {
+ if (Object::cast_to<GPUParticlesCollisionBox3D>(sn) || Object::cast_to<GPUParticlesAttractorBox3D>(sn) || Object::cast_to<GPUParticlesAttractorVectorField3D>(sn) || Object::cast_to<GPUParticlesCollisionSDF3D>(sn) || Object::cast_to<GPUParticlesCollisionHeightField3D>(sn)) {
Vector3 axis;
axis[p_id] = 1.0;
Vector3 ra, rb;
@@ -2836,10 +3087,10 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g
}
}
-void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
Node3D *sn = p_gizmo->get_spatial_node();
- if (Object::cast_to<GPUParticlesCollisionSphere>(sn) || Object::cast_to<GPUParticlesAttractorSphere>(sn)) {
+ if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
if (p_cancel) {
sn->call("set_radius", p_restore);
return;
@@ -2852,7 +3103,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
ur->commit_action();
}
- if (Object::cast_to<GPUParticlesCollisionBox>(sn) || Object::cast_to<GPUParticlesAttractorBox>(sn) || Object::cast_to<GPUParticlesAttractorVectorField>(sn) || Object::cast_to<GPUParticlesCollisionSDF>(sn) || Object::cast_to<GPUParticlesCollisionHeightField>(sn)) {
+ if (Object::cast_to<GPUParticlesCollisionBox3D>(sn) || Object::cast_to<GPUParticlesAttractorBox3D>(sn) || Object::cast_to<GPUParticlesAttractorVectorField3D>(sn) || Object::cast_to<GPUParticlesCollisionSDF3D>(sn) || Object::cast_to<GPUParticlesCollisionHeightField3D>(sn)) {
if (p_cancel) {
sn->call("set_extents", p_restore);
return;
@@ -2869,7 +3120,6 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Node3D *cs = p_gizmo->get_spatial_node();
- print_line("redraw request " + itos(cs != nullptr));
p_gizmo->clear();
const Ref<Material> material =
@@ -2879,7 +3129,7 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<Material> handles_material = get_material("handles");
- if (Object::cast_to<GPUParticlesCollisionSphere>(cs) || Object::cast_to<GPUParticlesAttractorSphere>(cs)) {
+ if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
float r = cs->call("get_radius");
Vector<Vector3> points;
@@ -2921,7 +3171,7 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_handles(handles, handles_material);
}
- if (Object::cast_to<GPUParticlesCollisionBox>(cs) || Object::cast_to<GPUParticlesAttractorBox>(cs) || Object::cast_to<GPUParticlesAttractorVectorField>(cs) || Object::cast_to<GPUParticlesCollisionSDF>(cs) || Object::cast_to<GPUParticlesCollisionHeightField>(cs)) {
+ if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
Vector<Vector3> lines;
AABB aabb;
aabb.position = -cs->call("get_extents").operator Vector3();
@@ -2946,9 +3196,9 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_segments(lines);
p_gizmo->add_handles(handles, handles_material);
- GPUParticlesCollisionSDF *col_sdf = Object::cast_to<GPUParticlesCollisionSDF>(cs);
+ GPUParticlesCollisionSDF3D *col_sdf = Object::cast_to<GPUParticlesCollisionSDF3D>(cs);
if (col_sdf) {
- static const int subdivs[GPUParticlesCollisionSDF::RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
+ static const int subdivs[GPUParticlesCollisionSDF3D::RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
int subdiv = subdivs[col_sdf->get_resolution()];
float cell_size = aabb.get_longest_axis_size() / subdiv;
@@ -2960,13 +3210,8 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
continue;
}
- Vector2 dir;
- dir[j] = 1.0;
- Vector2 ta, tb;
int j_n1 = (j + 1) % 3;
int j_n2 = (j + 2) % 3;
- ta[j_n1] = 1.0;
- tb[j_n2] = 1.0;
for (int k = 0; k < 4; k++) {
Vector3 from = aabb.position, to = aabb.position;
@@ -3026,7 +3271,7 @@ int ReflectionProbeGizmoPlugin::get_priority() const {
return -1;
}
-String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
return "Extents X";
@@ -3045,12 +3290,12 @@ String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gi
return "";
}
-Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
return AABB(probe->get_extents(), probe->get_origin_offset());
}
-void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
Transform3D gt = probe->get_global_transform();
@@ -3107,7 +3352,7 @@ void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, in
}
}
-void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
AABB restore = p_restore;
@@ -3211,7 +3456,7 @@ int DecalGizmoPlugin::get_priority() const {
return -1;
}
-String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
return "Extents X";
@@ -3224,12 +3469,12 @@ String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p
return "";
}
-Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
return decal->get_extents();
}
-void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
Transform3D gt = decal->get_global_transform();
@@ -3260,7 +3505,7 @@ void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Ca
decal->set_extents(extents);
}
-void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
Vector3 restore = p_restore;
@@ -3351,7 +3596,7 @@ int VoxelGIGizmoPlugin::get_priority() const {
return -1;
}
-String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
return "Extents X";
@@ -3364,12 +3609,12 @@ String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int
return "";
}
-Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
return probe->get_extents();
}
-void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
Transform3D gt = probe->get_global_transform();
@@ -3400,7 +3645,7 @@ void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
probe->set_extents(extents);
}
-void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
Vector3 restore = p_restore;
@@ -3452,13 +3697,8 @@ void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
continue;
}
- Vector2 dir;
- dir[j] = 1.0;
- Vector2 ta, tb;
int j_n1 = (j + 1) % 3;
int j_n2 = (j + 2) % 3;
- ta[j_n1] = 1.0;
- tb[j_n2] = 1.0;
for (int k = 0; k < 4; k++) {
Vector3 from = aabb.position, to = aabb.position;
@@ -3520,20 +3760,6 @@ LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() {
create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("GizmoLightmapGI"), SNAME("EditorIcons")));
}
-String LightmapGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- return "";
-}
-
-Variant LightmapGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- return Variant();
-}
-
-void LightmapGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
-}
-
-void LightmapGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
-}
-
bool LightmapGIGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<LightmapGI>(p_spatial) != nullptr;
}
@@ -3702,20 +3928,6 @@ LightmapProbeGizmoPlugin::LightmapProbeGizmoPlugin() {
create_material("lightprobe_lines", gizmo_color);
}
-String LightmapProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- return "";
-}
-
-Variant LightmapProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- return Variant();
-}
-
-void LightmapProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
-}
-
-void LightmapProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
-}
-
bool LightmapProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<LightmapProbe>(p_spatial) != nullptr;
}
@@ -3792,7 +4004,7 @@ void LightmapProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
////
CollisionObject3DGizmoPlugin::CollisionObject3DGizmoPlugin() {
- const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
const float gizmo_value = gizmo_color.get_v();
const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
@@ -3842,7 +4054,7 @@ void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
////
CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() {
- const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
const float gizmo_value = gizmo_color.get_v();
const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
@@ -3862,7 +4074,7 @@ int CollisionShape3DGizmoPlugin::get_priority() const {
return -1;
}
-String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
const CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
Ref<Shape3D> s = cs->get_shape();
@@ -3893,7 +4105,7 @@ String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
return "";
}
-Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
Ref<Shape3D> s = cs->get_shape();
@@ -3929,7 +4141,7 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p
return Variant();
}
-void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
Ref<Shape3D> s = cs->get_shape();
@@ -4043,7 +4255,7 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
}
}
-void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
Ref<Shape3D> s = cs->get_shape();
@@ -4295,9 +4507,10 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_segments(collision_segments);
- Vector<Vector3> handles;
- handles.push_back(Vector3(cs2->get_radius(), 0, 0));
- handles.push_back(Vector3(0, cs2->get_height() * 0.5, 0));
+ Vector<Vector3> handles = {
+ Vector3(cs2->get_radius(), 0, 0),
+ Vector3(0, cs2->get_height() * 0.5, 0)
+ };
p_gizmo->add_handles(handles, handles_material);
}
@@ -4351,16 +4564,16 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_segments(collision_segments);
- Vector<Vector3> handles;
- handles.push_back(Vector3(cs2->get_radius(), 0, 0));
- handles.push_back(Vector3(0, cs2->get_height() * 0.5, 0));
+ Vector<Vector3> handles = {
+ Vector3(cs2->get_radius(), 0, 0),
+ Vector3(0, cs2->get_height() * 0.5, 0)
+ };
p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<WorldBoundaryShape3D>(*s)) {
Ref<WorldBoundaryShape3D> wbs = s;
const Plane &p = wbs->get_plane();
- Vector<Vector3> points;
Vector3 n1 = p.get_any_perpendicular_normal();
Vector3 n2 = p.normal.cross(n1).normalized();
@@ -4372,16 +4585,18 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p.normal * p.d + n1 * -10.0 + n2 * 10.0,
};
- points.push_back(pface[0]);
- points.push_back(pface[1]);
- points.push_back(pface[1]);
- points.push_back(pface[2]);
- points.push_back(pface[2]);
- points.push_back(pface[3]);
- points.push_back(pface[3]);
- points.push_back(pface[0]);
- points.push_back(p.normal * p.d);
- points.push_back(p.normal * p.d + p.normal * 3);
+ Vector<Vector3> points = {
+ pface[0],
+ pface[1],
+ pface[1],
+ pface[2],
+ pface[2],
+ pface[3],
+ pface[3],
+ pface[0],
+ p.normal * p.d,
+ p.normal * p.d + p.normal * 3
+ };
p_gizmo->add_lines(points, material);
p_gizmo->add_collision_segments(points);
@@ -4418,9 +4633,10 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (Object::cast_to<SeparationRayShape3D>(*s)) {
Ref<SeparationRayShape3D> rs = s;
- Vector<Vector3> points;
- points.push_back(Vector3());
- points.push_back(Vector3(0, 0, rs->get_length()));
+ Vector<Vector3> points = {
+ Vector3(),
+ Vector3(0, 0, rs->get_length())
+ };
p_gizmo->add_lines(points, material);
p_gizmo->add_collision_segments(points);
Vector<Vector3> handles;
@@ -4439,7 +4655,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
/////
CollisionPolygon3DGizmoPlugin::CollisionPolygon3DGizmoPlugin() {
- const Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
const float gizmo_value = gizmo_color.get_v();
const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
@@ -4616,7 +4832,7 @@ Basis JointGizmosDrawer::look_body(const Transform3D &p_joint_transform, const T
v_y.normalize();
Basis base;
- base.set(v_x, v_y, v_z);
+ base.set_columns(v_x, v_y, v_z);
// Absorb current joint transform
base = p_joint_transform.basis.inverse() * base;
@@ -4641,7 +4857,7 @@ Basis JointGizmosDrawer::look_body_toward_x(const Transform3D &p_joint_transform
const Vector3 &p_eye(p_joint_transform.origin);
const Vector3 &p_target(p_body_transform.origin);
- const Vector3 p_front(p_joint_transform.basis.get_axis(0));
+ const Vector3 p_front(p_joint_transform.basis.get_column(0));
Vector3 v_x, v_y, v_z;
@@ -4660,7 +4876,7 @@ Basis JointGizmosDrawer::look_body_toward_x(const Transform3D &p_joint_transform
v_x.normalize();
Basis base;
- base.set(v_x, v_y, v_z);
+ base.set_columns(v_x, v_y, v_z);
// Absorb current joint transform
base = p_joint_transform.basis.inverse() * base;
@@ -4672,7 +4888,7 @@ Basis JointGizmosDrawer::look_body_toward_y(const Transform3D &p_joint_transform
const Vector3 &p_eye(p_joint_transform.origin);
const Vector3 &p_target(p_body_transform.origin);
- const Vector3 p_up(p_joint_transform.basis.get_axis(1));
+ const Vector3 p_up(p_joint_transform.basis.get_column(1));
Vector3 v_x, v_y, v_z;
@@ -4691,7 +4907,7 @@ Basis JointGizmosDrawer::look_body_toward_y(const Transform3D &p_joint_transform
v_y.normalize();
Basis base;
- base.set(v_x, v_y, v_z);
+ base.set_columns(v_x, v_y, v_z);
// Absorb current joint transform
base = p_joint_transform.basis.inverse() * base;
@@ -4703,7 +4919,7 @@ Basis JointGizmosDrawer::look_body_toward_z(const Transform3D &p_joint_transform
const Vector3 &p_eye(p_joint_transform.origin);
const Vector3 &p_target(p_body_transform.origin);
- const Vector3 p_lateral(p_joint_transform.basis.get_axis(2));
+ const Vector3 p_lateral(p_joint_transform.basis.get_column(2));
Vector3 v_x, v_y, v_z;
@@ -4722,7 +4938,7 @@ Basis JointGizmosDrawer::look_body_toward_z(const Transform3D &p_joint_transform
v_x.normalize();
Basis base;
- base.set(v_x, v_y, v_z);
+ base.set_columns(v_x, v_y, v_z);
// Absorb current joint transform
base = p_joint_transform.basis.inverse() * base;
@@ -4836,7 +5052,7 @@ void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_ba
////
Joint3DGizmoPlugin::Joint3DGizmoPlugin() {
- create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)));
+ create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint"));
create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)));
create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)));
@@ -5297,15 +5513,15 @@ int FogVolumeGizmoPlugin::get_priority() const {
return -1;
}
-String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
return "Extents";
}
-Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
return Vector3(p_gizmo->get_spatial_node()->call("get_extents"));
}
-void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Node3D *sn = p_gizmo->get_spatial_node();
Transform3D gt = sn->get_global_transform();
@@ -5334,7 +5550,7 @@ void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id
sn->call("set_extents", he);
}
-void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
Node3D *sn = p_gizmo->get_spatial_node();
if (p_cancel) {
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 56e4ad5518..f859ceda3b 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -45,7 +45,7 @@ class EditorNode3DGizmo : public Node3DGizmo {
struct Instance {
RID instance;
- Ref<ArrayMesh> mesh;
+ Ref<Mesh> mesh;
Ref<Material> material;
Ref<SkinReference> skin_reference;
bool extra_margin = false;
@@ -70,22 +70,21 @@ class EditorNode3DGizmo : public Node3DGizmo {
bool valid;
bool hidden;
Vector<Instance> instances;
- Node3D *spatial_node;
+ Node3D *spatial_node = nullptr;
void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Node3D>(p_node)); }
protected:
static void _bind_methods();
- EditorNode3DGizmoPlugin *gizmo_plugin;
+ EditorNode3DGizmoPlugin *gizmo_plugin = nullptr;
GDVIRTUAL0(_redraw)
- GDVIRTUAL1RC(String, _get_handle_name, int)
- GDVIRTUAL1RC(bool, _is_handle_highlighted, int)
-
- GDVIRTUAL1RC(Variant, _get_handle_value, int)
- GDVIRTUAL3(_set_handle, int, const Camera3D *, Vector2)
- GDVIRTUAL3(_commit_handle, int, Variant, bool)
+ GDVIRTUAL2RC(String, _get_handle_name, int, bool)
+ GDVIRTUAL2RC(bool, _is_handle_highlighted, int, bool)
+ GDVIRTUAL2RC(Variant, _get_handle_value, int, bool)
+ GDVIRTUAL4(_set_handle, int, bool, const Camera3D *, Vector2)
+ GDVIRTUAL4(_commit_handle, int, bool, Variant, bool)
GDVIRTUAL2RC(int, _subgizmos_intersect_ray, const Camera3D *, Vector2)
GDVIRTUAL2RC(Vector<int>, _subgizmos_intersect_frustum, const Camera3D *, TypedArray<Plane>)
@@ -95,18 +94,18 @@ protected:
public:
void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false, const Color &p_modulate = Color(1, 1, 1));
void add_vertices(const Vector<Vector3> &p_vertices, const Ref<Material> &p_material, Mesh::PrimitiveType p_primitive_type, bool p_billboard = false, const Color &p_modulate = Color(1, 1, 1));
- void add_mesh(const Ref<ArrayMesh> &p_mesh, const Ref<Material> &p_material = Ref<Material>(), const Transform3D &p_xform = Transform3D(), const Ref<SkinReference> &p_skin_reference = Ref<SkinReference>());
+ void add_mesh(const Ref<Mesh> &p_mesh, const Ref<Material> &p_material = Ref<Material>(), const Transform3D &p_xform = Transform3D(), const Ref<SkinReference> &p_skin_reference = Ref<SkinReference>());
void add_collision_segments(const Vector<Vector3> &p_lines);
void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh);
void add_unscaled_billboard(const Ref<Material> &p_material, real_t p_scale = 1, const Color &p_modulate = Color(1, 1, 1));
void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, const Vector<int> &p_ids = Vector<int>(), bool p_billboard = false, bool p_secondary = false);
- void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3(), const Transform3D &p_xform = Transform3D());
+ void add_solid_box(const Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3(), const Transform3D &p_xform = Transform3D());
- virtual bool is_handle_highlighted(int p_id) const;
- virtual String get_handle_name(int p_id) const;
- virtual Variant get_handle_value(int p_id) const;
- virtual void set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_id, const Variant &p_restore, bool p_cancel = false);
+ virtual bool is_handle_highlighted(int p_id, bool p_secondary) const;
+ virtual String get_handle_name(int p_id, bool p_secondary) const;
+ virtual Variant get_handle_value(int p_id, bool p_secondary) const;
+ virtual void set_handle(int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point);
+ virtual void commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false);
virtual int subgizmos_intersect_ray(Camera3D *p_camera, const Vector2 &p_point) const;
virtual Vector<int> subgizmos_intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum) const;
@@ -121,7 +120,7 @@ public:
Node3D *get_spatial_node() const { return spatial_node; }
Ref<EditorNode3DGizmoPlugin> get_plugin() const { return gizmo_plugin; }
bool intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum);
- void handles_intersect_ray(Camera3D *p_camera, const Vector2 &p_point, bool p_shift_pressed, int &r_id);
+ void handles_intersect_ray(Camera3D *p_camera, const Vector2 &p_point, bool p_shift_pressed, int &r_id, bool &r_secondary);
bool intersect_ray(Camera3D *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal);
bool is_subgizmo_selected(int p_id) const;
Vector<int> get_subgizmo_selection() const;
@@ -167,12 +166,12 @@ protected:
GDVIRTUAL0RC(bool, _is_selectable_when_hidden)
GDVIRTUAL1(_redraw, Ref<EditorNode3DGizmo>)
- GDVIRTUAL2RC(String, _get_handle_name, Ref<EditorNode3DGizmo>, int)
- GDVIRTUAL2RC(bool, _is_handle_highlighted, Ref<EditorNode3DGizmo>, int)
- GDVIRTUAL2RC(Variant, _get_handle_value, Ref<EditorNode3DGizmo>, int)
+ GDVIRTUAL3RC(String, _get_handle_name, Ref<EditorNode3DGizmo>, int, bool)
+ GDVIRTUAL3RC(bool, _is_handle_highlighted, Ref<EditorNode3DGizmo>, int, bool)
+ GDVIRTUAL3RC(Variant, _get_handle_value, Ref<EditorNode3DGizmo>, int, bool)
- GDVIRTUAL4(_set_handle, Ref<EditorNode3DGizmo>, int, const Camera3D *, Vector2)
- GDVIRTUAL4(_commit_handle, Ref<EditorNode3DGizmo>, int, Variant, bool)
+ GDVIRTUAL5(_set_handle, Ref<EditorNode3DGizmo>, int, bool, const Camera3D *, Vector2)
+ GDVIRTUAL5(_commit_handle, Ref<EditorNode3DGizmo>, int, bool, Variant, bool)
GDVIRTUAL3RC(int, _subgizmos_intersect_ray, Ref<EditorNode3DGizmo>, const Camera3D *, Vector2)
GDVIRTUAL3RC(Vector<int>, _subgizmos_intersect_frustum, Ref<EditorNode3DGizmo>, const Camera3D *, TypedArray<Plane>)
@@ -194,11 +193,11 @@ public:
virtual bool is_selectable_when_hidden() const;
virtual void redraw(EditorNode3DGizmo *p_gizmo);
- virtual bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const;
- virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const;
- virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const;
- virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point);
- virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false);
+ virtual bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const;
+ virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const;
+ virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const;
+ virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point);
+ virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false);
virtual int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const;
virtual Vector<int> subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const;
@@ -223,10 +222,10 @@ public:
String get_gizmo_name() const override;
int get_priority() const override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
Light3DGizmoPlugin();
@@ -240,10 +239,10 @@ public:
String get_gizmo_name() const override;
int get_priority() const override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
AudioStreamPlayer3DGizmoPlugin();
@@ -270,10 +269,10 @@ public:
String get_gizmo_name() const override;
int get_priority() const override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
Camera3DGizmoPlugin();
@@ -301,6 +300,11 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
+
OccluderInstance3DGizmoPlugin();
};
@@ -317,6 +321,19 @@ public:
Sprite3DGizmoPlugin();
};
+class Label3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(Label3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ int get_priority() const override;
+ bool can_be_hidden() const override;
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ Label3DGizmoPlugin();
+};
+
class Position3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Position3DGizmoPlugin, EditorNode3DGizmoPlugin);
@@ -390,10 +407,10 @@ public:
bool is_selectable_when_hidden() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
- bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
+ bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
SoftDynamicBody3DGizmoPlugin();
};
@@ -407,10 +424,10 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
VisibleOnScreenNotifier3DGizmoPlugin();
};
@@ -437,10 +454,10 @@ public:
bool is_selectable_when_hidden() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
GPUParticles3DGizmoPlugin();
};
@@ -454,10 +471,10 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
GPUParticlesCollision3DGizmoPlugin();
};
@@ -471,10 +488,10 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
ReflectionProbeGizmoPlugin();
};
@@ -488,10 +505,10 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
DecalGizmoPlugin();
};
@@ -505,10 +522,10 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
VoxelGIGizmoPlugin();
};
@@ -522,11 +539,6 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
-
LightmapGIGizmoPlugin();
};
@@ -539,11 +551,6 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
-
LightmapProbeGizmoPlugin();
};
@@ -568,10 +575,10 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
CollisionShape3DGizmoPlugin();
};
@@ -624,7 +631,7 @@ public:
class Joint3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Joint3DGizmoPlugin, EditorNode3DGizmoPlugin);
- Timer *update_timer;
+ Timer *update_timer = nullptr;
uint64_t update_idx = 0;
void incremental_update_gizmos();
@@ -678,10 +685,10 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
FogVolumeGizmoPlugin();
};
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index b99ccc1012..e0fc42165b 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
+#include "core/input/input_map.h"
#include "core/math/camera_matrix.h"
#include "core/math/math_funcs.h"
#include "core/os/keyboard.h"
@@ -42,6 +43,7 @@
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/node_3d_editor_gizmos.h"
#include "editor/plugins/script_editor_plugin.h"
+#include "editor/scene_tree_dock.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/light_3d.h"
@@ -54,55 +56,59 @@
#include "scene/resources/packed_scene.h"
#include "scene/resources/surface_tool.h"
-#define DISTANCE_DEFAULT 4
+constexpr real_t DISTANCE_DEFAULT = 4;
-#define GIZMO_ARROW_SIZE 0.35
-#define GIZMO_RING_HALF_WIDTH 0.1
-#define GIZMO_PLANE_SIZE 0.2
-#define GIZMO_PLANE_DST 0.3
-#define GIZMO_CIRCLE_SIZE 1.1
-#define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
-#define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
+constexpr real_t GIZMO_ARROW_SIZE = 0.35;
+constexpr real_t GIZMO_RING_HALF_WIDTH = 0.1;
+constexpr real_t GIZMO_PLANE_SIZE = 0.2;
+constexpr real_t GIZMO_PLANE_DST = 0.3;
+constexpr real_t GIZMO_CIRCLE_SIZE = 1.1;
+constexpr real_t GIZMO_SCALE_OFFSET = GIZMO_CIRCLE_SIZE + 0.3;
+constexpr real_t GIZMO_ARROW_OFFSET = GIZMO_CIRCLE_SIZE + 0.3;
-#define ZOOM_FREELOOK_MIN 0.01
-#define ZOOM_FREELOOK_MULTIPLIER 1.08
-#define ZOOM_FREELOOK_INDICATOR_DELAY_S 1.5
+constexpr real_t ZOOM_FREELOOK_MIN = 0.01;
+constexpr real_t ZOOM_FREELOOK_MULTIPLIER = 1.08;
+constexpr real_t ZOOM_FREELOOK_INDICATOR_DELAY_S = 1.5;
#ifdef REAL_T_IS_DOUBLE
-#define ZOOM_FREELOOK_MAX 1'000'000'000'000
+constexpr double ZOOM_FREELOOK_MAX = 1'000'000'000'000;
#else
-#define ZOOM_FREELOOK_MAX 10'000
+constexpr float ZOOM_FREELOOK_MAX = 10'000;
#endif
-#define MIN_Z 0.01
-#define MAX_Z 1000000.0
+constexpr real_t MIN_Z = 0.01;
+constexpr real_t MAX_Z = 1000000.0;
-#define MIN_FOV 0.01
-#define MAX_FOV 179
+constexpr real_t MIN_FOV = 0.01;
+constexpr real_t MAX_FOV = 179;
void ViewportRotationControl::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- axis_menu_options.clear();
- axis_menu_options.push_back(Node3DEditorViewport::VIEW_RIGHT);
- axis_menu_options.push_back(Node3DEditorViewport::VIEW_TOP);
- axis_menu_options.push_back(Node3DEditorViewport::VIEW_REAR);
- axis_menu_options.push_back(Node3DEditorViewport::VIEW_LEFT);
- axis_menu_options.push_back(Node3DEditorViewport::VIEW_BOTTOM);
- axis_menu_options.push_back(Node3DEditorViewport::VIEW_FRONT);
-
- axis_colors.clear();
- axis_colors.push_back(get_theme_color(SNAME("axis_x_color"), SNAME("Editor")));
- axis_colors.push_back(get_theme_color(SNAME("axis_y_color"), SNAME("Editor")));
- axis_colors.push_back(get_theme_color(SNAME("axis_z_color"), SNAME("Editor")));
- update();
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ axis_menu_options.clear();
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_RIGHT);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_TOP);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_REAR);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_LEFT);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_BOTTOM);
+ axis_menu_options.push_back(Node3DEditorViewport::VIEW_FRONT);
+
+ axis_colors.clear();
+ axis_colors.push_back(get_theme_color(SNAME("axis_x_color"), SNAME("Editor")));
+ axis_colors.push_back(get_theme_color(SNAME("axis_y_color"), SNAME("Editor")));
+ axis_colors.push_back(get_theme_color(SNAME("axis_z_color"), SNAME("Editor")));
+ update();
- if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) {
- connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited));
- }
- }
+ if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) {
+ connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited));
+ }
+ } break;
- if (p_what == NOTIFICATION_DRAW && viewport != nullptr) {
- _draw();
+ case NOTIFICATION_DRAW: {
+ if (viewport != nullptr) {
+ _draw();
+ }
+ } break;
}
}
@@ -139,7 +145,7 @@ void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) {
// Draw the axis letter for the positive axes.
const String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z");
- draw_char(get_theme_font(SNAME("rotation_control"), SNAME("EditorFonts")), p_axis.screen_point + Vector2i(-4, 5) * EDSCALE, axis_name, "", get_theme_font_size(SNAME("rotation_control_size"), SNAME("EditorFonts")), Color(0.0, 0.0, 0.0, alpha));
+ draw_char(get_theme_font(SNAME("rotation_control"), SNAME("EditorFonts")), p_axis.screen_point + Vector2i(Math::round(-4.0 * EDSCALE), Math::round(5.0 * EDSCALE)), axis_name, "", get_theme_font_size(SNAME("rotation_control_size"), SNAME("EditorFonts")), Color(0.0, 0.0, 0.0, alpha));
} else {
// Draw an outline around the negative axes.
draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c);
@@ -153,7 +159,7 @@ void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) {
const Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse();
for (int i = 0; i < 3; ++i) {
- Vector3 axis_3d = camera_basis.get_axis(i);
+ Vector3 axis_3d = camera_basis.get_column(i);
Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * radius;
if (Math::abs(axis_3d.z) < 1.0) {
@@ -185,7 +191,7 @@ void ViewportRotationControl::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
Vector2 pos = mb->get_position();
if (mb->is_pressed()) {
if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
@@ -199,7 +205,7 @@ void ViewportRotationControl::gui_input(const Ref<InputEvent> &p_event) {
orbiting = false;
if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
- Input::get_singleton()->warp_mouse_position(orbiting_mouse_start);
+ Input::get_singleton()->warp_mouse(orbiting_mouse_start);
}
}
}
@@ -363,7 +369,7 @@ Transform3D Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) co
}
int Node3DEditorViewport::get_selected_count() const {
- Map<Node *, Object *> &selection = editor_selection->get_selection();
+ const Map<Node *, Object *> &selection = editor_selection->get_selection();
int count = 0;
@@ -384,6 +390,27 @@ int Node3DEditorViewport::get_selected_count() const {
return count;
}
+void Node3DEditorViewport::cancel_transform() {
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ sp->set_global_transform(se->original);
+ }
+
+ finish_transform();
+ set_message(TTR("Transform Aborted."), 3);
+}
+
float Node3DEditorViewport::get_znear() const {
return CLAMP(spatial_editor->get_znear(), MIN_Z, MAX_Z);
}
@@ -413,7 +440,7 @@ Vector3 Node3DEditorViewport::_get_ray_pos(const Vector2 &p_pos) const {
}
Vector3 Node3DEditorViewport::_get_camera_normal() const {
- return -_get_camera_transform().basis.get_axis(2);
+ return -_get_camera_transform().basis.get_column(2);
}
Vector3 Node3DEditorViewport::_get_ray(const Vector2 &p_pos) const {
@@ -423,6 +450,7 @@ Vector3 Node3DEditorViewport::_get_ray(const Vector2 &p_pos) const {
void Node3DEditorViewport::_clear_selected() {
_edit.gizmo = Ref<EditorNode3DGizmo>();
_edit.gizmo_handle = -1;
+ _edit.gizmo_handle_secondary = false;
_edit.gizmo_initial_value = Variant();
Node3D *selected = spatial_editor->get_single_selected_node();
@@ -450,7 +478,7 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) {
if (!p_allow_locked) {
// Replace the node by the group if grouped
- while (node && node != editor->get_edited_scene()->get_parent()) {
+ while (node && node != EditorNode::get_singleton()->get_edited_scene()->get_parent()) {
Node3D *selected_tmp = Object::cast_to<Node3D>(node);
if (selected_tmp && node->has_meta("_edit_group_")) {
selected = selected_tmp;
@@ -470,12 +498,12 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) {
if (!editor_selection->is_selected(selected)) {
editor_selection->clear();
editor_selection->add_node(selected);
- editor->edit_node(selected);
+ EditorNode::get_singleton()->edit_node(selected);
}
}
if (editor_selection->get_selected_node_list().size() == 1) {
- editor->edit_node(editor_selection->get_selected_node_list()[0]);
+ EditorNode::get_singleton()->edit_node(editor_selection->get_selected_node_list()[0]);
}
}
}
@@ -761,7 +789,7 @@ void Node3DEditorViewport::_select_region() {
// Replace the node by the group if grouped
if (item->is_class("Node3D")) {
Node3D *sel = Object::cast_to<Node3D>(item);
- while (item && item != editor->get_edited_scene()->get_parent()) {
+ while (item && item != EditorNode::get_singleton()->get_edited_scene()->get_parent()) {
Node3D *selected_tmp = Object::cast_to<Node3D>(item);
if (selected_tmp && item->has_meta("_edit_group_")) {
sel = selected_tmp;
@@ -795,7 +823,7 @@ void Node3DEditorViewport::_select_region() {
}
if (editor_selection->get_selected_node_list().size() == 1) {
- editor->edit_node(editor_selection->get_selected_node_list()[0]);
+ EditorNode::get_singleton()->edit_node(editor_selection->get_selected_node_list()[0]);
}
}
@@ -860,10 +888,11 @@ void Node3DEditorViewport::_update_name() {
}
view_menu->set_text(name);
- view_menu->set_size(Vector2(0, 0)); // resets the button size
+ view_menu->reset_size();
}
void Node3DEditorViewport::_compute_edit(const Point2 &p_point) {
+ _edit.original_local = spatial_editor->are_local_coords_enabled();
_edit.click_ray = _get_ray(p_point);
_edit.click_ray_pos = _get_ray_pos(p_point);
_edit.plane = TRANSFORM_VIEW;
@@ -901,36 +930,36 @@ void Node3DEditorViewport::_compute_edit(const Point2 &p_point) {
}
}
-static int _get_key_modifier_setting(const String &p_property) {
+static Key _get_key_modifier_setting(const String &p_property) {
switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
case 0:
- return 0;
+ return Key::NONE;
case 1:
- return KEY_SHIFT;
+ return Key::SHIFT;
case 2:
- return KEY_ALT;
+ return Key::ALT;
case 3:
- return KEY_META;
+ return Key::META;
case 4:
- return KEY_CTRL;
+ return Key::CTRL;
}
- return 0;
+ return Key::NONE;
}
-static int _get_key_modifier(Ref<InputEventWithModifiers> e) {
+static Key _get_key_modifier(Ref<InputEventWithModifiers> e) {
if (e->is_shift_pressed()) {
- return KEY_SHIFT;
+ return Key::SHIFT;
}
if (e->is_alt_pressed()) {
- return KEY_ALT;
+ return Key::ALT;
}
if (e->is_ctrl_pressed()) {
- return KEY_CTRL;
+ return Key::CTRL;
}
if (e->is_meta_pressed()) {
- return KEY_META;
+ return Key::META;
}
- return 0;
+ return Key::NONE;
}
bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only) {
@@ -954,7 +983,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
real_t col_d = 1e20;
for (int i = 0; i < 3; i++) {
- const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
+ const Vector3 grabber_pos = gt.origin + gt.basis.get_column(i).normalized() * gizmo_scale * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE;
Vector3 r;
@@ -974,15 +1003,15 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
col_d = 1e20;
for (int i = 0; i < 3; i++) {
- Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
- Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
+ Vector3 ivec2 = gt.basis.get_column((i + 1) % 3).normalized();
+ Vector3 ivec3 = gt.basis.get_column((i + 2) % 3).normalized();
// Allow some tolerance to make the plane easier to click,
// even if the click is actually slightly outside the plane.
const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gizmo_scale * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667);
Vector3 r;
- Plane plane(gt.basis.get_axis(i).normalized(), gt.origin);
+ Plane plane(gt.basis.get_column(i).normalized(), gt.origin);
if (plane.intersects_ray(ray_pos, ray, &r)) {
const real_t dist = r.distance_to(grabber_pos);
@@ -1017,24 +1046,40 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
int col_axis = -1;
- float col_d = 1e20;
- for (int i = 0; i < 3; i++) {
- Plane plane(gt.basis.get_axis(i).normalized(), gt.origin);
- Vector3 r;
- if (!plane.intersects_ray(ray_pos, ray, &r)) {
- continue;
+ Vector3 hit_position;
+ Vector3 hit_normal;
+ real_t ray_length = gt.origin.distance_to(ray_pos) + (GIZMO_CIRCLE_SIZE * gizmo_scale) * 4.0f;
+ if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * ray_length, gt.origin, gizmo_scale * (GIZMO_CIRCLE_SIZE), &hit_position, &hit_normal)) {
+ if (hit_normal.dot(_get_camera_normal()) < 0.05) {
+ hit_position = gt.xform_inv(hit_position).abs();
+ int min_axis = hit_position.min_axis_index();
+ if (hit_position[min_axis] < gizmo_scale * GIZMO_RING_HALF_WIDTH) {
+ col_axis = min_axis;
+ }
}
+ }
+
+ if (col_axis == -1) {
+ float col_d = 1e20;
- const real_t dist = r.distance_to(gt.origin);
- const Vector3 r_dir = (r - gt.origin).normalized();
+ for (int i = 0; i < 3; i++) {
+ Plane plane(gt.basis.get_column(i).normalized(), gt.origin);
+ Vector3 r;
+ if (!plane.intersects_ray(ray_pos, ray, &r)) {
+ continue;
+ }
+
+ const real_t dist = r.distance_to(gt.origin);
+ const Vector3 r_dir = (r - gt.origin).normalized();
- if (_get_camera_normal().dot(r_dir) <= 0.005) {
- if (dist > gizmo_scale * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gizmo_scale * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
- const real_t d = ray_pos.distance_to(r);
- if (d < col_d) {
- col_d = d;
- col_axis = i;
+ if (_get_camera_normal().dot(r_dir) <= 0.005) {
+ if (dist > gizmo_scale * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gizmo_scale * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
+ const real_t d = ray_pos.distance_to(r);
+ if (d < col_d) {
+ col_d = d;
+ col_axis = i;
+ }
}
}
}
@@ -1058,7 +1103,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
float col_d = 1e20;
for (int i = 0; i < 3; i++) {
- const Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gizmo_scale * GIZMO_SCALE_OFFSET;
+ const Vector3 grabber_pos = gt.origin + gt.basis.get_column(i).normalized() * gizmo_scale * GIZMO_SCALE_OFFSET;
const real_t grabber_radius = gizmo_scale * GIZMO_ARROW_SIZE;
Vector3 r;
@@ -1078,15 +1123,15 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
col_d = 1e20;
for (int i = 0; i < 3; i++) {
- const Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
- const Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
+ const Vector3 ivec2 = gt.basis.get_column((i + 1) % 3).normalized();
+ const Vector3 ivec3 = gt.basis.get_column((i + 2) % 3).normalized();
// Allow some tolerance to make the plane easier to click,
// even if the click is actually slightly outside the plane.
const Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gizmo_scale * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST * 0.6667);
Vector3 r;
- Plane plane(gt.basis.get_axis(i).normalized(), gt.origin);
+ Plane plane(gt.basis.get_column(i).normalized(), gt.origin);
if (plane.intersects_ray(ray_pos, ray, &r)) {
const real_t dist = r.distance_to(grabber_pos);
@@ -1138,68 +1183,62 @@ void Node3DEditorViewport::_transform_gizmo_apply(Node3D *p_node, const Transfor
}
}
-Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local) {
+Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal) {
switch (p_mode) {
case TRANSFORM_SCALE: {
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ p_motion.snap(Vector3(p_extra, p_extra, p_extra));
+ }
+ Transform3D s;
if (p_local) {
- Basis g = p_original.basis.orthonormalized();
- Vector3 local_motion = g.inverse().xform(p_motion);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- local_motion.snap(Vector3(p_extra, p_extra, p_extra));
- }
-
- Transform3D local_t;
- local_t.basis = p_original_local.basis.scaled_local(local_motion + Vector3(1, 1, 1));
- local_t.origin = p_original_local.origin;
- return local_t;
+ s.basis = p_original_local.basis.scaled_local(p_motion + Vector3(1, 1, 1));
+ s.origin = p_original_local.origin;
} else {
+ s.basis.scale(p_motion + Vector3(1, 1, 1));
Transform3D base = Transform3D(Basis(), _edit.center);
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- p_motion.snap(Vector3(p_extra, p_extra, p_extra));
+ s = base * (s * (base.inverse() * p_original));
+
+ // Recalculate orthogonalized scale without moving origin.
+ if (p_orthogonal) {
+ s.basis = p_original_local.basis.scaled_orthogonal(p_motion + Vector3(1, 1, 1));
+ // The scaled_orthogonal() does not require orthogonal Basis,
+ // but it may make a bit skew by precision problems.
+ s.basis.orthogonalize();
}
-
- Transform3D global_t;
- global_t.basis.scale(p_motion + Vector3(1, 1, 1));
- return base * (global_t * (base.inverse() * p_original));
}
+
+ return s;
}
case TRANSFORM_TRANSLATE: {
- if (p_local) {
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- Basis g = p_original.basis.orthonormalized();
- Vector3 local_motion = g.inverse().xform(p_motion);
- local_motion.snap(Vector3(p_extra, p_extra, p_extra));
-
- p_motion = g.xform(local_motion);
- }
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ p_motion.snap(Vector3(p_extra, p_extra, p_extra));
+ }
- } else {
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- p_motion.snap(Vector3(p_extra, p_extra, p_extra));
- }
+ if (p_local) {
+ p_motion = p_original.basis.xform(p_motion);
}
// Apply translation
Transform3D t = p_original;
t.origin += p_motion;
+
return t;
}
case TRANSFORM_ROTATE: {
+ Transform3D r;
+
if (p_local) {
- Transform3D r;
Vector3 axis = p_original_local.basis.xform(p_motion);
r.basis = Basis(axis.normalized(), p_extra) * p_original_local.basis;
r.origin = p_original_local.origin;
- return r;
} else {
- Transform3D r;
Basis local = p_original.basis * p_original_local.basis.inverse();
Vector3 axis = local.xform_inv(p_motion);
r.basis = local * Basis(axis.normalized(), p_extra) * p_original_local.basis;
r.origin = Basis(p_motion, p_extra).xform(p_original.origin - _edit.center) + _edit.center;
- return r;
}
+
+ return r;
}
default: {
ERR_FAIL_V_MSG(Transform3D(), "Invalid mode in '_compute_transform'");
@@ -1208,7 +1247,7 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const
}
void Node3DEditorViewport::_surface_mouse_enter() {
- if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) {
+ if (!surface->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) {
surface->grab_focus();
}
}
@@ -1232,13 +1271,13 @@ bool Node3DEditorViewport ::_is_node_locked(const Node *p_node) {
void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
_find_items_at_pos(b->get_position(), selection_results, spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT);
- Node *scene = editor->get_edited_scene();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
for (int i = 0; i < selection_results.size(); i++) {
Node3D *item = selection_results[i].item;
if (item != scene && item->get_owner() != scene && item != scene->get_deepest_editable_node(item)) {
//invalid result
- selection_results.remove(i);
+ selection_results.remove_at(i);
i--;
}
}
@@ -1267,7 +1306,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
if (_is_node_locked(spat)) {
locked = 1;
} else {
- Node *ed_scene = editor->get_edited_scene();
+ Node *ed_scene = EditorNode::get_singleton()->get_edited_scene();
Node *node = spat;
while (node && node != ed_scene->get_parent()) {
@@ -1291,7 +1330,8 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_class() + "\nPath: " + node_path);
}
- selection_menu->set_position(get_screen_transform().xform(b->get_position()));
+ selection_menu->set_position(get_screen_position() + b->get_position());
+ selection_menu->reset_size();
selection_menu->popup();
}
}
@@ -1303,7 +1343,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
EditorPlugin::AfterGUIInput after = EditorPlugin::AFTER_GUI_INPUT_PASS;
{
- EditorNode *en = editor;
+ EditorNode *en = EditorNode::get_singleton();
EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding();
if (!force_input_forwarding_list->is_empty()) {
EditorPlugin::AfterGUIInput discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
@@ -1316,7 +1356,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
{
- EditorNode *en = editor;
+ EditorNode *en = EditorNode::get_singleton();
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
if (!over_plugin_list->is_empty()) {
EditorPlugin::AfterGUIInput discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
@@ -1336,7 +1376,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
const real_t zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) {
- case MOUSE_BUTTON_WHEEL_UP: {
+ case MouseButton::WHEEL_UP: {
if (b->is_alt_pressed()) {
scale_fov(-0.05);
} else {
@@ -1347,7 +1387,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
} break;
- case MOUSE_BUTTON_WHEEL_DOWN: {
+ case MouseButton::WHEEL_DOWN: {
if (b->is_alt_pressed()) {
scale_fov(0.05);
} else {
@@ -1358,12 +1398,12 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
} break;
- case MOUSE_BUTTON_RIGHT: {
+ case MouseButton::RIGHT: {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if (b->is_pressed() && _edit.gizmo.is_valid()) {
//restore
- _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true);
+ _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, true);
_edit.gizmo = Ref<EditorNode3DGizmo>();
}
@@ -1379,43 +1419,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
if (_edit.mode != TRANSFORM_NONE && b->is_pressed()) {
- //cancel motion
- _edit.mode = TRANSFORM_NONE;
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (se->gizmo.is_valid()) {
- Vector<int> ids;
- Vector<Transform3D> restore;
-
- for (const KeyValue<int, Transform3D> &GE : se->subgizmos) {
- ids.push_back(GE.key);
- restore.push_back(GE.value);
- }
-
- se->gizmo->commit_subgizmos(ids, restore, true);
- spatial_editor->update_transform_gizmo();
- } else {
- sp->set_global_transform(se->original);
- }
- }
- surface->update();
- set_message(TTR("Transform Aborted."), 3);
+ cancel_transform();
}
if (b->is_pressed()) {
- const int mod = _get_key_modifier(b);
+ const Key mod = _get_key_modifier(b);
if (!orthogonal) {
if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
set_freelook_active(true);
@@ -1432,7 +1440,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} break;
- case MOUSE_BUTTON_MIDDLE: {
+ case MouseButton::MIDDLE: {
if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) {
switch (_edit.plane) {
case TRANSFORM_VIEW: {
@@ -1463,8 +1471,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
} break;
- case MOUSE_BUTTON_LEFT: {
+ case MouseButton::LEFT: {
if (b->is_pressed()) {
+ clicked_wants_append = b->is_shift_pressed();
+
+ if (_edit.mode != TRANSFORM_NONE && _edit.instant) {
+ commit_transform();
+ break; // just commit the edit, stop processing the event so we don't deselect the object
+ }
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->is_alt_pressed()) {
break;
@@ -1479,6 +1493,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.original_mouse_pos = b->get_position();
_edit.snap = spatial_editor->is_snap_enabled();
_edit.mode = TRANSFORM_NONE;
+ _edit.original = spatial_editor->get_gizmo_transform(); // To prevent to break when flipping with scale.
bool can_select_gizmos = spatial_editor->get_single_selected_node();
@@ -1500,11 +1515,13 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
int gizmo_handle = -1;
- seg->handles_intersect_ray(camera, _edit.mouse_pos, b->is_shift_pressed(), gizmo_handle);
+ bool gizmo_secondary = false;
+ seg->handles_intersect_ray(camera, _edit.mouse_pos, b->is_shift_pressed(), gizmo_handle, gizmo_secondary);
if (gizmo_handle != -1) {
_edit.gizmo = seg;
_edit.gizmo_handle = gizmo_handle;
- _edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle);
+ _edit.gizmo_handle_secondary = gizmo_secondary;
+ _edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle, gizmo_secondary);
intersected_handle = true;
break;
}
@@ -1568,42 +1585,24 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
clicked = ObjectID();
if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
- /* HANDLE ROTATION */
- if (get_selected_count() == 0) {
- break; //bye
- }
- //handle rotate
- _edit.mode = TRANSFORM_ROTATE;
- _compute_edit(b->get_position());
+ begin_transform(TRANSFORM_ROTATE, false);
break;
}
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
- if (get_selected_count() == 0) {
- break; //bye
- }
- //handle translate
- _edit.mode = TRANSFORM_TRANSLATE;
- _compute_edit(b->get_position());
+ begin_transform(TRANSFORM_TRANSLATE, false);
break;
}
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) {
- if (get_selected_count() == 0) {
- break; //bye
- }
- //handle scale
- _edit.mode = TRANSFORM_SCALE;
- _compute_edit(b->get_position());
+ begin_transform(TRANSFORM_SCALE, false);
break;
}
if (after != EditorPlugin::AFTER_GUI_INPUT_DESELECT) {
- clicked = _select_ray(b->get_position());
-
//clicking is always deferred to either move or release
-
- clicked_wants_append = b->is_shift_pressed();
+ clicked = _select_ray(b->get_position());
+ selection_in_progress = true;
if (clicked.is_null()) {
//default to regionselect
@@ -1616,12 +1615,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
surface->update();
} else {
if (_edit.gizmo.is_valid()) {
- _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false);
+ _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, false);
_edit.gizmo = Ref<EditorNode3DGizmo>();
break;
}
if (after != EditorPlugin::AFTER_GUI_INPUT_DESELECT) {
+ selection_in_progress = false;
+
if (clicked.is_valid()) {
_select_clicked(false);
}
@@ -1649,32 +1650,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
se->gizmo->commit_subgizmos(ids, restore, false);
spatial_editor->update_transform_gizmo();
} else {
- static const char *_transform_name[4] = {
- TTRC("None"),
- TTRC("Rotate"),
- // TRANSLATORS: This refers to the movement that changes the position of an object.
- TTRC("Translate"),
- TTRC("Scale"),
- };
- undo_redo->create_action(TTRGET(_transform_name[_edit.mode]));
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
-
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
- Node3D *sp = Object::cast_to<Node3D>(E->get());
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *sel_item = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!sel_item) {
- continue;
- }
-
- undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
- undo_redo->add_undo_method(sp, "set_global_transform", sel_item->original);
- }
- undo_redo->commit_action();
+ commit_transform();
}
_edit.mode = TRANSFORM_NONE;
set_message("");
@@ -1698,6 +1674,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Ref<EditorNode3DGizmo> found_gizmo;
int found_handle = -1;
+ bool found_handle_secondary = false;
for (int i = 0; i < gizmos.size(); i++) {
Ref<EditorNode3DGizmo> seg = gizmos[i];
@@ -1705,7 +1682,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
continue;
}
- seg->handles_intersect_ray(camera, _edit.mouse_pos, false, found_handle);
+ seg->handles_intersect_ray(camera, _edit.mouse_pos, false, found_handle, found_handle_secondary);
if (found_handle != -1) {
found_gizmo = seg;
@@ -1717,14 +1694,16 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
spatial_editor->select_gizmo_highlight_axis(-1);
}
- if (found_gizmo != spatial_editor->get_current_hover_gizmo() || found_handle != spatial_editor->get_current_hover_gizmo_handle()) {
+ bool current_hover_handle_secondary = false;
+ int curreny_hover_handle = spatial_editor->get_current_hover_gizmo_handle(current_hover_handle_secondary);
+ if (found_gizmo != spatial_editor->get_current_hover_gizmo() || found_handle != curreny_hover_handle || found_handle_secondary != current_hover_handle_secondary) {
spatial_editor->set_current_hover_gizmo(found_gizmo);
- spatial_editor->set_current_hover_gizmo_handle(found_handle);
+ spatial_editor->set_current_hover_gizmo_handle(found_handle, found_handle_secondary);
spatial_editor->get_single_selected_node()->update_gizmos();
}
}
- if (spatial_editor->get_current_hover_gizmo().is_null() && !(m->get_button_mask() & 1) && !_edit.gizmo.is_valid()) {
+ if (spatial_editor->get_current_hover_gizmo().is_null() && (m->get_button_mask() & MouseButton::MASK_LEFT) == MouseButton::NONE && !_edit.gizmo.is_valid()) {
_transform_gizmo_select(_edit.mouse_pos, true);
}
@@ -1732,12 +1711,12 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
NavigationMode nav_mode = NAVIGATION_NONE;
if (_edit.gizmo.is_valid()) {
- _edit.gizmo->set_handle(_edit.gizmo_handle, camera, m->get_position());
- Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle);
- String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
+ _edit.gizmo->set_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, camera, m->get_position());
+ Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle, _edit.gizmo_handle_secondary);
+ String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle, _edit.gizmo_handle_secondary);
set_message(n + ": " + String(v));
- } else if (m->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ } else if ((m->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE || _edit.instant) {
if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) {
nav_mode = NAVIGATION_ORBIT;
} else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_shift_pressed()) {
@@ -1748,11 +1727,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_ORBIT;
} else {
const bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 8 * EDSCALE;
- if (clicked.is_valid() && movement_threshold_passed) {
- _compute_edit(_edit.mouse_pos);
- clicked = ObjectID();
- _edit.mode = TRANSFORM_TRANSLATE;
+ // enable region-select if nothing has been selected yet or multi-select (shift key) is active
+ if (selection_in_progress && movement_threshold_passed) {
+ if (get_selected_count() == 0 || clicked_wants_append) {
+ cursor.region_select = true;
+ cursor.region_begin = _edit.original_mouse_pos;
+ clicked = ObjectID();
+ }
}
if (cursor.region_select) {
@@ -1761,328 +1743,19 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
return;
}
+ if (clicked.is_valid() && movement_threshold_passed) {
+ _compute_edit(_edit.original_mouse_pos);
+ clicked = ObjectID();
+ _edit.mode = TRANSFORM_TRANSLATE;
+ }
+
if (_edit.mode == TRANSFORM_NONE) {
return;
}
- Vector3 ray_pos = _get_ray_pos(m->get_position());
- Vector3 ray = _get_ray(m->get_position());
- double snap = EDITOR_GET("interface/inspector/default_float_step");
- int snap_step_decimals = Math::range_step_decimals(snap);
-
- switch (_edit.mode) {
- case TRANSFORM_SCALE: {
- Vector3 motion_mask;
- Plane plane;
- bool plane_mv = false;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- motion_mask = Vector3(0, 0, 0);
- plane = Plane(_get_camera_normal(), _edit.center);
- break;
- case TRANSFORM_X_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Y_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Z_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_YZ:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XZ:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(0);
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XY:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2), _edit.center);
- plane_mv = true;
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
- break;
- }
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
- break;
- }
-
- Vector3 motion = intersection - click;
- if (_edit.plane != TRANSFORM_VIEW) {
- if (!plane_mv) {
- motion = motion_mask.dot(motion) * motion_mask;
-
- } else {
- // Alternative planar scaling mode
- if (_get_key_modifier(m) != KEY_SHIFT) {
- motion = motion_mask.dot(motion) * motion_mask;
- }
- }
-
- } else {
- const real_t center_click_dist = click.distance_to(_edit.center);
- const real_t center_inters_dist = intersection.distance_to(_edit.center);
- if (center_click_dist == 0) {
- break;
- }
-
- const real_t scale = center_inters_dist - center_click_dist;
- motion = Vector3(scale, scale, scale);
- }
-
- motion /= click.distance_to(_edit.center);
-
- // Disable local transformation for TRANSFORM_VIEW
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_scale_snap() / 100;
- }
- Vector3 motion_snapped = motion;
- motion_snapped.snap(Vector3(snap, snap, snap));
- // This might not be necessary anymore after issue #288 is solved (in 4.0?).
- set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- if (se->gizmo.is_valid()) {
- for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
- Transform3D xform = GE.value;
- Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords);
- if (!local_coords) {
- new_xform = se->original.affine_inverse() * new_xform;
- }
- se->gizmo->set_subgizmo_transform(GE.key, new_xform);
- }
- } else {
- Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords);
- _transform_gizmo_apply(se->sp, new_xform, local_coords);
- }
- }
-
- spatial_editor->update_transform_gizmo();
- surface->update();
-
- } break;
-
- case TRANSFORM_TRANSLATE: {
- Vector3 motion_mask;
- Plane plane;
- bool plane_mv = false;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- plane = Plane(_get_camera_normal(), _edit.center);
- break;
- case TRANSFORM_X_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Y_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_Z_AXIS:
- motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
- plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
- break;
- case TRANSFORM_YZ:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XZ:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1), _edit.center);
- plane_mv = true;
- break;
- case TRANSFORM_XY:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2), _edit.center);
- plane_mv = true;
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
- break;
- }
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
- break;
- }
-
- Vector3 motion = intersection - click;
- if (_edit.plane != TRANSFORM_VIEW) {
- if (!plane_mv) {
- motion = motion_mask.dot(motion) * motion_mask;
- }
- }
-
- // Disable local transformation for TRANSFORM_VIEW
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_translate_snap();
- }
- Vector3 motion_snapped = motion;
- motion_snapped.snap(Vector3(snap, snap, snap));
- set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- if (se->gizmo.is_valid()) {
- for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
- Transform3D xform = GE.value;
- Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original * xform, xform, motion, snap, local_coords);
- new_xform = se->original.affine_inverse() * new_xform;
- se->gizmo->set_subgizmo_transform(GE.key, new_xform);
- }
- } else {
- Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original, se->original_local, motion, snap, local_coords);
- _transform_gizmo_apply(se->sp, new_xform, false);
- }
- }
-
- spatial_editor->update_transform_gizmo();
- surface->update();
-
- } break;
-
- case TRANSFORM_ROTATE: {
- Plane plane;
- Vector3 axis;
-
- switch (_edit.plane) {
- case TRANSFORM_VIEW:
- plane = Plane(_get_camera_normal(), _edit.center);
- break;
- case TRANSFORM_X_AXIS:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(0), _edit.center);
- axis = Vector3(1, 0, 0);
- break;
- case TRANSFORM_Y_AXIS:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(1), _edit.center);
- axis = Vector3(0, 1, 0);
- break;
- case TRANSFORM_Z_AXIS:
- plane = Plane(spatial_editor->get_gizmo_transform().basis.get_axis(2), _edit.center);
- axis = Vector3(0, 0, 1);
- break;
- case TRANSFORM_YZ:
- case TRANSFORM_XZ:
- case TRANSFORM_XY:
- break;
- }
-
- Vector3 intersection;
- if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
- break;
- }
-
- Vector3 click;
- if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
- break;
- }
-
- Vector3 y_axis = (click - _edit.center).normalized();
- Vector3 x_axis = plane.normal.cross(y_axis).normalized();
-
- double angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
-
- if (_edit.snap || spatial_editor->is_snap_enabled()) {
- snap = spatial_editor->get_rotate_snap();
- }
- angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
- angle -= Math::fmod(angle, snap);
- set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
- angle = Math::deg2rad(angle);
-
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
-
- List<Node *> &selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E);
- if (!sp) {
- continue;
- }
-
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
-
- if (sp->has_meta("_edit_lock_")) {
- continue;
- }
-
- Vector3 compute_axis = local_coords ? axis : plane.normal;
- if (se->gizmo.is_valid()) {
- for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
- Transform3D xform = GE.value;
-
- Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original * xform, xform, compute_axis, angle, local_coords);
- if (!local_coords) {
- new_xform = se->original.affine_inverse() * new_xform;
- }
- se->gizmo->set_subgizmo_transform(GE.key, new_xform);
- }
- } else {
- Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original, se->original_local, compute_axis, angle, local_coords);
- _transform_gizmo_apply(se->sp, new_xform, local_coords);
- }
- }
-
- spatial_editor->update_transform_gizmo();
- surface->update();
-
- } break;
- default: {
- }
- }
+ update_transform(m->get_position(), _get_key_modifier(m) == Key::SHIFT);
}
- } else if ((m->get_button_mask() & MOUSE_BUTTON_MASK_RIGHT) || freelook_active) {
+ } else if ((m->get_button_mask() & MouseButton::MASK_RIGHT) != MouseButton::NONE || freelook_active) {
if (nav_scheme == NAVIGATION_MAYA && m->is_alt_pressed()) {
nav_mode = NAVIGATION_ZOOM;
} else if (freelook_active) {
@@ -2091,14 +1764,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_PAN;
}
- } else if (m->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
- const int mod = _get_key_modifier(m);
+ } else if ((m->get_button_mask() & MouseButton::MASK_MIDDLE) != MouseButton::NONE) {
+ const Key mod = _get_key_modifier(m);
if (nav_scheme == NAVIGATION_GODOT) {
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
nav_mode = NAVIGATION_ZOOM;
- } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
+ } else if (mod == Key::ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
// Always allow Alt as a modifier to better support graphic tablets.
nav_mode = NAVIGATION_ORBIT;
}
@@ -2109,14 +1782,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} else if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_3_button_mouse")) {
// Handle trackpad (no external mouse) use case
- const int mod = _get_key_modifier(m);
+ const Key mod = _get_key_modifier(m);
- if (mod) {
+ if (mod != Key::NONE) {
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
nav_mode = NAVIGATION_ZOOM;
- } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
+ } else if (mod == Key::ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
// Always allow Alt as a modifier to better support graphic tablets.
nav_mode = NAVIGATION_ORBIT;
}
@@ -2164,13 +1837,13 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
NavigationMode nav_mode = NAVIGATION_NONE;
if (nav_scheme == NAVIGATION_GODOT) {
- const int mod = _get_key_modifier(pan_gesture);
+ const Key mod = _get_key_modifier(pan_gesture);
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
nav_mode = NAVIGATION_ZOOM;
- } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
+ } else if (mod == Key::ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
// Always allow Alt as a modifier to better support graphic tablets.
nav_mode = NAVIGATION_ORBIT;
}
@@ -2215,12 +1888,62 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_numpad")) {
- const uint32_t code = k->get_keycode();
- if (code >= KEY_0 && code <= KEY_9) {
- k->set_keycode(code - KEY_0 + KEY_KP_0);
+ const Key code = k->get_keycode();
+ if (code >= Key::KEY_0 && code <= Key::KEY_9) {
+ k->set_keycode(code - Key::KEY_0 + Key::KP_0);
}
}
+ if (_edit.mode == TRANSFORM_NONE) {
+ if (k->get_keycode() == Key::ESCAPE && !cursor.region_select) {
+ _clear_selected();
+ return;
+ }
+ } else {
+ // We're actively transforming, handle keys specially
+ TransformPlane new_plane = TRANSFORM_VIEW;
+ String new_message;
+ if (ED_IS_SHORTCUT("spatial_editor/lock_transform_x", p_event)) {
+ new_plane = TRANSFORM_X_AXIS;
+ new_message = TTR("X-Axis Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_y", p_event)) {
+ new_plane = TRANSFORM_Y_AXIS;
+ new_message = TTR("Y-Axis Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_z", p_event)) {
+ new_plane = TRANSFORM_Z_AXIS;
+ new_message = TTR("Z-Axis Transform.");
+ } else if (_edit.mode != TRANSFORM_ROTATE) { // rotating on a plane doesn't make sense
+ if (ED_IS_SHORTCUT("spatial_editor/lock_transform_yz", p_event)) {
+ new_plane = TRANSFORM_YZ;
+ new_message = TTR("YZ-Plane Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_xz", p_event)) {
+ new_plane = TRANSFORM_XZ;
+ new_message = TTR("XZ-Plane Transform.");
+ } else if (ED_IS_SHORTCUT("spatial_editor/lock_transform_xy", p_event)) {
+ new_plane = TRANSFORM_XY;
+ new_message = TTR("XY-Plane Transform.");
+ }
+ }
+
+ if (new_plane != TRANSFORM_VIEW) {
+ if (new_plane != _edit.plane) {
+ // lock me once and get a global constraint
+ _edit.plane = new_plane;
+ spatial_editor->set_local_coords_enabled(false);
+ } else if (!spatial_editor->are_local_coords_enabled()) {
+ // lock me twice and get a local constraint
+ spatial_editor->set_local_coords_enabled(true);
+ } else {
+ // lock me thrice and we're back where we started
+ _edit.plane = TRANSFORM_VIEW;
+ spatial_editor->set_local_coords_enabled(false);
+ }
+ update_transform(_edit.mouse_pos, Input::get_singleton()->is_key_pressed(Key::SHIFT));
+ set_message(new_message, 2);
+ accept_event();
+ return;
+ }
+ }
if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
if (_edit.mode != TRANSFORM_NONE) {
_edit.snap = !_edit.snap;
@@ -2245,12 +1968,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_menu_option(VIEW_RIGHT);
}
if (ED_IS_SHORTCUT("spatial_editor/orbit_view_down", p_event)) {
- cursor.x_rot -= Math_PI / 12.0;
+ // Clamp rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
+ cursor.x_rot = CLAMP(cursor.x_rot - Math_PI / 12.0, -1.57, 1.57);
view_type = VIEW_TYPE_USER;
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/orbit_view_up", p_event)) {
- cursor.x_rot += Math_PI / 12.0;
+ // Clamp rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
+ cursor.x_rot = CLAMP(cursor.x_rot + Math_PI / 12.0, -1.57, 1.57);
view_type = VIEW_TYPE_USER;
_update_name();
}
@@ -2309,16 +2034,30 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
set_message(TTR("Animation Key Inserted."));
}
+ if (ED_IS_SHORTCUT("spatial_editor/cancel_transform", p_event) && _edit.mode != TRANSFORM_NONE) {
+ cancel_transform();
+ }
+ if (!is_freelook_active()) {
+ if (ED_IS_SHORTCUT("spatial_editor/instant_translate", p_event)) {
+ begin_transform(TRANSFORM_TRANSLATE, true);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/instant_rotate", p_event)) {
+ begin_transform(TRANSFORM_ROTATE, true);
+ }
+ if (ED_IS_SHORTCUT("spatial_editor/instant_scale", p_event)) {
+ begin_transform(TRANSFORM_SCALE, true);
+ }
+ }
// Freelook doesn't work in orthogonal mode.
if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
set_freelook_active(!is_freelook_active());
- } else if (k->get_keycode() == KEY_ESCAPE) {
+ } else if (k->get_keycode() == Key::ESCAPE) {
set_freelook_active(false);
}
- if (k->get_keycode() == KEY_SPACE) {
+ if (k->get_keycode() == Key::SPACE) {
if (!k->is_pressed()) {
emit_signal(SNAME("toggle_maximize_view"), this);
}
@@ -2348,9 +2087,8 @@ void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const
const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
real_t pan_speed = 1 / 150.0;
- int pan_speed_modifier = 10;
if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) {
- pan_speed *= pan_speed_modifier;
+ pan_speed *= 10;
}
Transform3D camera_transform;
@@ -2373,9 +2111,8 @@ void Node3DEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const
const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
real_t zoom_speed = 1 / 80.0;
- int zoom_speed_modifier = 10;
if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) {
- zoom_speed *= zoom_speed_modifier;
+ zoom_speed *= 10;
}
NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int();
@@ -2436,7 +2173,8 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
_menu_option(VIEW_PERSPECTIVE);
}
- const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_sensitivity");
+ // Scale mouse sensitivity with camera FOV scale when zoomed in to make it easier to point at things.
+ const real_t degrees_per_pixel = real_t(EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_sensitivity")) * MIN(1.0, cursor.fov_scale);
const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
@@ -2546,7 +2284,7 @@ void Node3DEditorViewport::scale_freelook_speed(real_t scale) {
Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const {
Point2i relative;
- if (bool(EDITOR_DEF("editors/3d/navigation/warped_mouse_panning", false))) {
+ if (bool(EDITOR_GET("editors/3d/navigation/warped_mouse_panning"))) {
relative = Input::get_singleton()->warp_mouse_motion(p_ev_mouse_motion, surface->get_global_rect());
} else {
relative = p_ev_mouse_motion->get_relative();
@@ -2554,26 +2292,6 @@ Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouse
return relative;
}
-static bool is_shortcut_pressed(const String &p_path) {
- Ref<Shortcut> shortcut = ED_GET_SHORTCUT(p_path);
- if (shortcut.is_null()) {
- return false;
- }
-
- const Array shortcuts = shortcut->get_events();
- Ref<InputEventKey> k;
- if (shortcuts.size() > 0) {
- k = shortcuts.front();
- }
-
- if (k.is_null()) {
- return false;
- }
- const Input &input = *Input::get_singleton();
- Key keycode = k->get_keycode();
- return input.is_key_pressed(keycode);
-}
-
void Node3DEditorViewport::_update_freelook(real_t delta) {
if (!is_freelook_active()) {
return;
@@ -2603,31 +2321,34 @@ void Node3DEditorViewport::_update_freelook(real_t delta) {
Vector3 direction;
- if (is_shortcut_pressed("spatial_editor/freelook_left")) {
+ // Use actions from the inputmap, as this is the only way to reliably detect input in this method.
+ // See #54469 for more discussion and explanation.
+ Input *inp = Input::get_singleton();
+ if (inp->is_action_pressed("spatial_editor/freelook_left")) {
direction -= right;
}
- if (is_shortcut_pressed("spatial_editor/freelook_right")) {
+ if (inp->is_action_pressed("spatial_editor/freelook_right")) {
direction += right;
}
- if (is_shortcut_pressed("spatial_editor/freelook_forward")) {
+ if (inp->is_action_pressed("spatial_editor/freelook_forward")) {
direction += forward;
}
- if (is_shortcut_pressed("spatial_editor/freelook_backwards")) {
+ if (inp->is_action_pressed("spatial_editor/freelook_backwards")) {
direction -= forward;
}
- if (is_shortcut_pressed("spatial_editor/freelook_up")) {
+ if (inp->is_action_pressed("spatial_editor/freelook_up")) {
direction += up;
}
- if (is_shortcut_pressed("spatial_editor/freelook_down")) {
+ if (inp->is_action_pressed("spatial_editor/freelook_down")) {
direction -= up;
}
real_t speed = freelook_speed;
- if (is_shortcut_pressed("spatial_editor/freelook_speed_modifier")) {
+ if (inp->is_action_pressed("spatial_editor/freelook_speed_modifier")) {
speed *= 3.0;
}
- if (is_shortcut_pressed("spatial_editor/freelook_slow_modifier")) {
+ if (inp->is_action_pressed("spatial_editor/freelook_slow_modifier")) {
speed *= 0.333333;
}
@@ -2684,307 +2405,310 @@ void Node3DEditorViewport::_project_settings_changed() {
const bool use_occlusion_culling = GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling");
viewport->set_use_occlusion_culling(use_occlusion_culling);
- const float lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels");
- viewport->set_lod_threshold(lod_threshold);
+ const float mesh_lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels");
+ viewport->set_mesh_lod_threshold(mesh_lod_threshold);
}
void Node3DEditorViewport::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- EditorNode::get_singleton()->connect("project_settings_changed", callable_mp(this, &Node3DEditorViewport::_project_settings_changed));
- }
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ EditorNode::get_singleton()->connect("project_settings_changed", callable_mp(this, &Node3DEditorViewport::_project_settings_changed));
+ } break;
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- bool visible = is_visible_in_tree();
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ bool visible = is_visible_in_tree();
- set_process(visible);
+ set_process(visible);
- if (visible) {
- orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
- _update_name();
- _update_camera(0);
- } else {
- set_freelook_active(false);
- }
- call_deferred(SNAME("update_transform_gizmo_view"));
- rotation_control->set_visible(EditorSettings::get_singleton()->get("editors/3d/navigation/show_viewport_rotation_gizmo"));
- }
+ if (visible) {
+ orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
+ _update_name();
+ _update_camera(0);
+ } else {
+ set_freelook_active(false);
+ }
+ call_deferred(SNAME("update_transform_gizmo_view"));
+ rotation_control->set_visible(EditorSettings::get_singleton()->get("editors/3d/navigation/show_viewport_rotation_gizmo"));
+ } break;
- if (p_what == NOTIFICATION_RESIZED) {
- call_deferred(SNAME("update_transform_gizmo_view"));
- }
+ case NOTIFICATION_RESIZED: {
+ call_deferred(SNAME("update_transform_gizmo_view"));
+ } break;
- if (p_what == NOTIFICATION_PROCESS) {
- real_t delta = get_process_delta_time();
+ case NOTIFICATION_PROCESS: {
+ real_t delta = get_process_delta_time();
- if (zoom_indicator_delay > 0) {
- zoom_indicator_delay -= delta;
- if (zoom_indicator_delay <= 0) {
- surface->update();
- zoom_limit_label->hide();
+ if (zoom_indicator_delay > 0) {
+ zoom_indicator_delay -= delta;
+ if (zoom_indicator_delay <= 0) {
+ surface->update();
+ zoom_limit_label->hide();
+ }
}
- }
- _update_freelook(delta);
+ _update_freelook(delta);
- Node *scene_root = editor->get_scene_tree_dock()->get_editor_data()->get_edited_scene_root();
- if (previewing_cinema && scene_root != nullptr) {
- Camera3D *cam = scene_root->get_viewport()->get_camera_3d();
- if (cam != nullptr && cam != previewing) {
- //then switch the viewport's camera to the scene's viewport camera
- if (previewing != nullptr) {
- previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ Node *scene_root = SceneTreeDock::get_singleton()->get_editor_data()->get_edited_scene_root();
+ if (previewing_cinema && scene_root != nullptr) {
+ Camera3D *cam = scene_root->get_viewport()->get_camera_3d();
+ if (cam != nullptr && cam != previewing) {
+ //then switch the viewport's camera to the scene's viewport camera
+ if (previewing != nullptr) {
+ previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ }
+ previewing = cam;
+ previewing->connect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
+ RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera());
+ surface->update();
}
- previewing = cam;
- previewing->connect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
- RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera());
- surface->update();
}
- }
- _update_camera(delta);
+ _update_camera(delta);
- Map<Node *, Object *> &selection = editor_selection->get_selection();
+ const Map<Node *, Object *> &selection = editor_selection->get_selection();
- bool changed = false;
- bool exist = false;
+ bool changed = false;
+ bool exist = false;
- for (const KeyValue<Node *, Object *> &E : selection) {
- Node3D *sp = Object::cast_to<Node3D>(E.key);
- if (!sp) {
- continue;
- }
+ for (const KeyValue<Node *, Object *> &E : selection) {
+ Node3D *sp = Object::cast_to<Node3D>(E.key);
+ if (!sp) {
+ continue;
+ }
- Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
- if (!se) {
- continue;
- }
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
- Transform3D t = sp->get_global_gizmo_transform();
- VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sp);
- AABB new_aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
+ Transform3D t = sp->get_global_gizmo_transform();
+ VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sp);
+ AABB new_aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
- exist = true;
- if (se->last_xform == t && se->aabb == new_aabb && !se->last_xform_dirty) {
- continue;
- }
- changed = true;
- se->last_xform_dirty = false;
- se->last_xform = t;
+ exist = true;
+ if (se->last_xform == t && se->aabb == new_aabb && !se->last_xform_dirty) {
+ continue;
+ }
+ changed = true;
+ se->last_xform_dirty = false;
+ se->last_xform = t;
- se->aabb = new_aabb;
+ se->aabb = new_aabb;
- Transform3D t_offset = t;
+ Transform3D t_offset = t;
- // apply AABB scaling before item's global transform
- {
- const Vector3 offset(0.005, 0.005, 0.005);
- Basis aabb_s;
- aabb_s.scale(se->aabb.size + offset);
- t.translate(se->aabb.position - offset / 2);
- t.basis = t.basis * aabb_s;
- }
- {
- const Vector3 offset(0.01, 0.01, 0.01);
- Basis aabb_s;
- aabb_s.scale(se->aabb.size + offset);
- t_offset.translate(se->aabb.position - offset / 2);
- t_offset.basis = t_offset.basis * aabb_s;
+ // apply AABB scaling before item's global transform
+ {
+ const Vector3 offset(0.005, 0.005, 0.005);
+ Basis aabb_s;
+ aabb_s.scale(se->aabb.size + offset);
+ t.translate(se->aabb.position - offset / 2);
+ t.basis = t.basis * aabb_s;
+ }
+ {
+ const Vector3 offset(0.01, 0.01, 0.01);
+ Basis aabb_s;
+ aabb_s.scale(se->aabb.size + offset);
+ t_offset.translate(se->aabb.position - offset / 2);
+ t_offset.basis = t_offset.basis * aabb_s;
+ }
+
+ RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance, t);
+ RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance_offset, t_offset);
+ RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance_xray, t);
+ RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance_xray_offset, t_offset);
}
- RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance, t);
- RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance_offset, t_offset);
- RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance_xray, t);
- RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance_xray_offset, t_offset);
- }
+ if (changed || (spatial_editor->is_gizmo_visible() && !exist)) {
+ spatial_editor->update_transform_gizmo();
+ }
- if (changed || (spatial_editor->is_gizmo_visible() && !exist)) {
- spatial_editor->update_transform_gizmo();
- }
+ if (message_time > 0) {
+ if (message != last_message) {
+ surface->update();
+ last_message = message;
+ }
- if (message_time > 0) {
- if (message != last_message) {
- surface->update();
- last_message = message;
+ message_time -= get_physics_process_delta_time();
+ if (message_time < 0) {
+ surface->update();
+ }
}
- message_time -= get_physics_process_delta_time();
- if (message_time < 0) {
- surface->update();
+ bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
+ if (show_info != info_label->is_visible()) {
+ info_label->set_visible(show_info);
}
- }
-
- bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
- if (show_info != info_label->is_visible()) {
- info_label->set_visible(show_info);
- }
- Camera3D *current_camera;
+ Camera3D *current_camera;
- if (previewing) {
- current_camera = previewing;
- } else {
- current_camera = camera;
- }
-
- if (show_info) {
- const String viewport_size = vformat(String::utf8("%d × %d"), viewport->get_size().x, viewport->get_size().y);
- String text;
- text += vformat(TTR("X: %s\n"), rtos(current_camera->get_position().x).pad_decimals(1));
- text += vformat(TTR("Y: %s\n"), rtos(current_camera->get_position().y).pad_decimals(1));
- text += vformat(TTR("Z: %s\n"), rtos(current_camera->get_position().z).pad_decimals(1));
- text += "\n";
- text += vformat(
- TTR("Size: %s (%.1fMP)\n"),
- viewport_size,
- viewport->get_size().x * viewport->get_size().y * 0.000001);
-
- text += "\n";
- text += vformat(TTR("Objects: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_OBJECTS_IN_FRAME));
- text += vformat(TTR("Primitives: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_PRIMITIVES_IN_FRAME));
- text += vformat(TTR("Draw Calls: %d"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME));
-
- info_label->set_text(text);
- }
-
- // FPS Counter.
- bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
-
- if (show_fps != fps_label->is_visible()) {
- cpu_time_label->set_visible(show_fps);
- gpu_time_label->set_visible(show_fps);
- fps_label->set_visible(show_fps);
- RS::get_singleton()->viewport_set_measure_render_time(viewport->get_viewport_rid(), show_fps);
- for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
- cpu_time_history[i] = 0;
- gpu_time_history[i] = 0;
- }
- cpu_time_history_index = 0;
- gpu_time_history_index = 0;
- }
- if (show_fps) {
- cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid());
- cpu_time_history_index = (cpu_time_history_index + 1) % FRAME_TIME_HISTORY;
- double cpu_time = 0.0;
- for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
- cpu_time += cpu_time_history[i];
- }
- cpu_time /= FRAME_TIME_HISTORY;
- // Prevent unrealistically low values.
- cpu_time = MAX(0.01, cpu_time);
-
- gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid());
- gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY;
- double gpu_time = 0.0;
- for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
- gpu_time += gpu_time_history[i];
- }
- gpu_time /= FRAME_TIME_HISTORY;
- // Prevent division by zero for the FPS counter (and unrealistically low values).
- // This limits the reported FPS to 100000.
- gpu_time = MAX(0.01, gpu_time);
-
- // Color labels depending on performance level ("good" = green, "OK" = yellow, "bad" = red).
- // Middle point is at 15 ms.
- cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), rtos(cpu_time).pad_decimals(1)));
- cpu_time_label->add_theme_color_override(
- "font_color",
- frame_time_gradient->get_color_at_offset(
- Math::range_lerp(cpu_time, 0, 30, 0, 1)));
-
- gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), rtos(gpu_time).pad_decimals(1)));
- // Middle point is at 15 ms.
- gpu_time_label->add_theme_color_override(
- "font_color",
- frame_time_gradient->get_color_at_offset(
- Math::range_lerp(gpu_time, 0, 30, 0, 1)));
-
- const double fps = 1000.0 / gpu_time;
- fps_label->set_text(vformat(TTR("FPS: %d"), fps));
- // Middle point is at 60 FPS.
- fps_label->add_theme_color_override(
- "font_color",
- frame_time_gradient->get_color_at_offset(
- Math::range_lerp(fps, 110, 10, 0, 1)));
- }
-
- bool show_cinema = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
- cinema_label->set_visible(show_cinema);
- if (show_cinema) {
- float cinema_half_width = cinema_label->get_size().width / 2.0f;
- cinema_label->set_anchor_and_offset(SIDE_LEFT, 0.5f, -cinema_half_width);
- }
-
- if (lock_rotation) {
- float locked_half_width = locked_label->get_size().width / 2.0f;
- locked_label->set_anchor_and_offset(SIDE_LEFT, 0.5f, -locked_half_width);
- }
- }
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
- surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw));
- surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput));
- surface->connect("mouse_entered", callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter));
- surface->connect("mouse_exited", callable_mp(this, &Node3DEditorViewport::_surface_mouse_exit));
- surface->connect("focus_entered", callable_mp(this, &Node3DEditorViewport::_surface_focus_enter));
- surface->connect("focus_exited", callable_mp(this, &Node3DEditorViewport::_surface_focus_exit));
-
- _init_gizmo_instance(index);
- }
-
- if (p_what == NOTIFICATION_EXIT_TREE) {
- _finish_gizmo_instances();
- }
+ if (previewing) {
+ current_camera = previewing;
+ } else {
+ current_camera = camera;
+ }
+
+ if (show_info) {
+ const String viewport_size = vformat(String::utf8("%d × %d"), viewport->get_size().x, viewport->get_size().y);
+ String text;
+ text += vformat(TTR("X: %s\n"), rtos(current_camera->get_position().x).pad_decimals(1));
+ text += vformat(TTR("Y: %s\n"), rtos(current_camera->get_position().y).pad_decimals(1));
+ text += vformat(TTR("Z: %s\n"), rtos(current_camera->get_position().z).pad_decimals(1));
+ text += "\n";
+ text += vformat(
+ TTR("Size: %s (%.1fMP)\n"),
+ viewport_size,
+ viewport->get_size().x * viewport->get_size().y * 0.000001);
+
+ text += "\n";
+ text += vformat(TTR("Objects: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_OBJECTS_IN_FRAME));
+ text += vformat(TTR("Primitive Indices: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_PRIMITIVES_IN_FRAME));
+ text += vformat(TTR("Draw Calls: %d"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME));
+
+ info_label->set_text(text);
+ }
+
+ // FPS Counter.
+ bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
+
+ if (show_fps != fps_label->is_visible()) {
+ cpu_time_label->set_visible(show_fps);
+ gpu_time_label->set_visible(show_fps);
+ fps_label->set_visible(show_fps);
+ RS::get_singleton()->viewport_set_measure_render_time(viewport->get_viewport_rid(), show_fps);
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ cpu_time_history[i] = 0;
+ gpu_time_history[i] = 0;
+ }
+ cpu_time_history_index = 0;
+ gpu_time_history_index = 0;
+ }
+ if (show_fps) {
+ cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid());
+ cpu_time_history_index = (cpu_time_history_index + 1) % FRAME_TIME_HISTORY;
+ double cpu_time = 0.0;
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ cpu_time += cpu_time_history[i];
+ }
+ cpu_time /= FRAME_TIME_HISTORY;
+ // Prevent unrealistically low values.
+ cpu_time = MAX(0.01, cpu_time);
+
+ gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid());
+ gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY;
+ double gpu_time = 0.0;
+ for (int i = 0; i < FRAME_TIME_HISTORY; i++) {
+ gpu_time += gpu_time_history[i];
+ }
+ gpu_time /= FRAME_TIME_HISTORY;
+ // Prevent division by zero for the FPS counter (and unrealistically low values).
+ // This limits the reported FPS to 100000.
+ gpu_time = MAX(0.01, gpu_time);
+
+ // Color labels depending on performance level ("good" = green, "OK" = yellow, "bad" = red).
+ // Middle point is at 15 ms.
+ cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), rtos(cpu_time).pad_decimals(2)));
+ cpu_time_label->add_theme_color_override(
+ "font_color",
+ frame_time_gradient->get_color_at_offset(
+ Math::range_lerp(cpu_time, 0, 30, 0, 1)));
+
+ gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), rtos(gpu_time).pad_decimals(2)));
+ // Middle point is at 15 ms.
+ gpu_time_label->add_theme_color_override(
+ "font_color",
+ frame_time_gradient->get_color_at_offset(
+ Math::range_lerp(gpu_time, 0, 30, 0, 1)));
+
+ const double fps = 1000.0 / gpu_time;
+ fps_label->set_text(vformat(TTR("FPS: %d"), fps));
+ // Middle point is at 60 FPS.
+ fps_label->add_theme_color_override(
+ "font_color",
+ frame_time_gradient->get_color_at_offset(
+ Math::range_lerp(fps, 110, 10, 0, 1)));
+ }
+
+ bool show_cinema = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
+ cinema_label->set_visible(show_cinema);
+ if (show_cinema) {
+ float cinema_half_width = cinema_label->get_size().width / 2.0f;
+ cinema_label->set_anchor_and_offset(SIDE_LEFT, 0.5f, -cinema_half_width);
+ }
- if (p_what == NOTIFICATION_THEME_CHANGED) {
- view_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
- preview_camera->set_icon(get_theme_icon(SNAME("Camera3D"), SNAME("EditorIcons")));
+ if (lock_rotation) {
+ float locked_half_width = locked_label->get_size().width / 2.0f;
+ locked_label->set_anchor_and_offset(SIDE_LEFT, 0.5f, -locked_half_width);
+ }
+ } break;
- view_menu->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- view_menu->add_theme_style_override("hover", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- view_menu->add_theme_style_override("pressed", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- view_menu->add_theme_style_override("focus", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- view_menu->add_theme_style_override("disabled", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ case NOTIFICATION_ENTER_TREE: {
+ surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw));
+ surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput));
+ surface->connect("mouse_entered", callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter));
+ surface->connect("mouse_exited", callable_mp(this, &Node3DEditorViewport::_surface_mouse_exit));
+ surface->connect("focus_entered", callable_mp(this, &Node3DEditorViewport::_surface_focus_enter));
+ surface->connect("focus_exited", callable_mp(this, &Node3DEditorViewport::_surface_focus_exit));
+
+ _init_gizmo_instance(index);
+ } break;
- preview_camera->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- preview_camera->add_theme_style_override("hover", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- preview_camera->add_theme_style_override("pressed", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- preview_camera->add_theme_style_override("focus", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- preview_camera->add_theme_style_override("disabled", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
-
- frame_time_gradient->set_color(0, get_theme_color(SNAME("success_color"), SNAME("Editor")));
- frame_time_gradient->set_color(1, get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- frame_time_gradient->set_color(2, get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ case NOTIFICATION_EXIT_TREE: {
+ _finish_gizmo_instances();
+ } break;
- info_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- cpu_time_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- gpu_time_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- fps_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- cinema_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- locked_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
- }
+ case NOTIFICATION_THEME_CHANGED: {
+ view_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ preview_camera->set_icon(get_theme_icon(SNAME("Camera3D"), SNAME("EditorIcons")));
+ Control *gui_base = EditorNode::get_singleton()->get_gui_base();
+
+ view_menu->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ view_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ view_menu->add_theme_style_override("pressed", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ view_menu->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ view_menu->add_theme_style_override("disabled", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+
+ preview_camera->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ preview_camera->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ preview_camera->add_theme_style_override("pressed", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ preview_camera->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ preview_camera->add_theme_style_override("disabled", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+
+ frame_time_gradient->set_color(0, get_theme_color(SNAME("success_color"), SNAME("Editor")));
+ frame_time_gradient->set_color(1, get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ frame_time_gradient->set_color(2, get_theme_color(SNAME("error_color"), SNAME("Editor")));
+
+ info_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ cpu_time_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ gpu_time_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ fps_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ cinema_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ locked_label->add_theme_style_override("normal", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), SNAME("EditorStyles")));
+ } break;
+ }
}
-static void draw_indicator_bar(Control &surface, real_t fill, const Ref<Texture2D> icon, const Ref<Font> font, int font_size, const String &text) {
+static void draw_indicator_bar(Control &p_surface, real_t p_fill, const Ref<Texture2D> p_icon, const Ref<Font> p_font, int p_font_size, const String &p_text, const Color &p_color) {
// Adjust bar size from control height
- const Vector2 surface_size = surface.get_size();
+ const Vector2 surface_size = p_surface.get_size();
const real_t h = surface_size.y / 2.0;
const real_t y = (surface_size.y - h) / 2.0;
const Rect2 r(10 * EDSCALE, y, 6 * EDSCALE, h);
- const real_t sy = r.size.y * fill;
+ const real_t sy = r.size.y * p_fill;
// Note: because this bar appears over the viewport, it has to stay readable for any background color
// Draw both neutral dark and bright colors to account this
- surface.draw_rect(r, Color(1, 1, 1, 0.2));
- surface.draw_rect(Rect2(r.position.x, r.position.y + r.size.y - sy, r.size.x, sy), Color(1, 1, 1, 0.6));
- surface.draw_rect(r.grow(1), Color(0, 0, 0, 0.7), false, Math::round(EDSCALE));
+ p_surface.draw_rect(r, p_color * Color(1, 1, 1, 0.2));
+ p_surface.draw_rect(Rect2(r.position.x, r.position.y + r.size.y - sy, r.size.x, sy), p_color * Color(1, 1, 1, 0.6));
+ p_surface.draw_rect(r.grow(1), Color(0, 0, 0, 0.7), false, Math::round(EDSCALE));
- const Vector2 icon_size = icon->get_size();
+ const Vector2 icon_size = p_icon->get_size();
const Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2 * EDSCALE);
- surface.draw_texture(icon, icon_pos);
+ p_surface.draw_texture(p_icon, icon_pos, p_color);
// Draw text below the bar (for speed/zoom information).
- surface.draw_string(font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), text, HALIGN_LEFT, -1.f, font_size);
+ p_surface.draw_string(p_font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), p_text, HORIZONTAL_ALIGNMENT_LEFT, -1.f, p_font_size, p_color, Math::round(2 * EDSCALE), Color(0, 0, 0));
}
void Node3DEditorViewport::_draw() {
@@ -2993,7 +2717,7 @@ void Node3DEditorViewport::_draw() {
over_plugin_list->forward_spatial_draw_over_viewport(surface);
}
- EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
+ EditorPluginList *force_over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_force_over();
if (!force_over_plugin_list->is_empty()) {
force_over_plugin_list->forward_spatial_force_draw_over_viewport(surface);
}
@@ -3024,12 +2748,12 @@ void Node3DEditorViewport::_draw() {
Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
Point2 msgpos = Point2(5, get_size().y - 20);
- font->draw_string(ci, msgpos + Point2(1, 1), message, HALIGN_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
- font->draw_string(ci, msgpos + Point2(-1, -1), message, HALIGN_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
- font->draw_string(ci, msgpos, message, HALIGN_LEFT, -1, font_size, Color(1, 1, 1, 1));
+ font->draw_string(ci, msgpos + Point2(1, 1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
+ font->draw_string(ci, msgpos + Point2(-1, -1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
+ font->draw_string(ci, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1));
}
- if (_edit.mode == TRANSFORM_ROTATE) {
+ if (_edit.mode == TRANSFORM_ROTATE && _edit.show_rotation_line) {
Point2 center = _point_to_screen(_edit.center);
Color handle_color;
@@ -3057,7 +2781,7 @@ void Node3DEditorViewport::_draw() {
Math::round(2 * EDSCALE));
}
if (previewing) {
- Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
float aspect = ss.aspect();
Size2 s = get_size();
@@ -3092,7 +2816,7 @@ void Node3DEditorViewport::_draw() {
real_t scale_length = (max_speed - min_speed);
if (!Math::is_zero_approx(scale_length)) {
- real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length);
+ real_t logscale_t = 1.0 - Math::log1p(freelook_speed - min_speed) / Math::log1p(scale_length);
// Display the freelook speed to help the user get a better sense of scale.
const int precision = freelook_speed < 1.0 ? 2 : 1;
@@ -3102,7 +2826,8 @@ void Node3DEditorViewport::_draw() {
get_theme_icon(SNAME("ViewportSpeed"), SNAME("EditorIcons")),
get_theme_font(SNAME("font"), SNAME("Label")),
get_theme_font_size(SNAME("font_size"), SNAME("Label")),
- vformat("%s u/s", String::num(freelook_speed).pad_decimals(precision)));
+ vformat("%s u/s", String::num(freelook_speed).pad_decimals(precision)),
+ Color(1.0, 0.95, 0.7));
}
} else {
@@ -3114,7 +2839,7 @@ void Node3DEditorViewport::_draw() {
real_t scale_length = (max_distance - min_distance);
if (!Math::is_zero_approx(scale_length)) {
- real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length);
+ real_t logscale_t = 1.0 - Math::log1p(cursor.distance - min_distance) / Math::log1p(scale_length);
// Display the zoom center distance to help the user get a better sense of scale.
const int precision = cursor.distance < 1.0 ? 2 : 1;
@@ -3124,7 +2849,8 @@ void Node3DEditorViewport::_draw() {
get_theme_icon(SNAME("ViewportZoom"), SNAME("EditorIcons")),
get_theme_font(SNAME("font"), SNAME("Label")),
get_theme_font_size(SNAME("font_size"), SNAME("Label")),
- vformat("%s u", String::num(cursor.distance).pad_decimals(precision)));
+ vformat("%s u", String::num(cursor.distance).pad_decimals(precision)),
+ Color(0.7, 0.95, 1.0));
}
}
}
@@ -3264,7 +2990,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
bool current = view_menu->get_popup()->is_item_checked(idx);
current = !current;
if (current) {
- camera->set_environment(RES());
+ camera->set_environment(Ref<Resource>());
} else {
camera->set_environment(Node3DEditor::get_singleton()->get_viewport_environment());
}
@@ -3387,6 +3113,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
case VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION:
case VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE:
case VIEW_DISPLAY_DEBUG_SSAO:
+ case VIEW_DISPLAY_DEBUG_SSIL:
case VIEW_DISPLAY_DEBUG_PSSM_SPLITS:
case VIEW_DISPLAY_DEBUG_DECAL_ATLAS:
case VIEW_DISPLAY_DEBUG_SDFGI:
@@ -3413,6 +3140,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
+ VIEW_DISPLAY_DEBUG_SSIL,
VIEW_DISPLAY_DEBUG_GI_BUFFER,
VIEW_DISPLAY_DEBUG_DISABLE_LOD,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
@@ -3441,6 +3169,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_VOXEL_GI_EMISSION,
Viewport::DEBUG_DRAW_SCENE_LUMINANCE,
Viewport::DEBUG_DRAW_SSAO,
+ Viewport::DEBUG_DRAW_SSIL,
Viewport::DEBUG_DRAW_GI_BUFFER,
Viewport::DEBUG_DRAW_DISABLE_LOD,
Viewport::DEBUG_DRAW_PSSM_SPLITS,
@@ -3534,6 +3263,13 @@ void Node3DEditorViewport::_init_gizmo_instance(int p_idx) {
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
RS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
RS::get_singleton()->instance_geometry_set_flag(scale_plane_gizmo_instance[i], RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
+
+ axis_gizmo_instance[i] = RS::get_singleton()->instance_create();
+ RS::get_singleton()->instance_set_base(axis_gizmo_instance[i], spatial_editor->get_axis_gizmo(i)->get_rid());
+ RS::get_singleton()->instance_set_scenario(axis_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_visible(axis_gizmo_instance[i], true);
+ RS::get_singleton()->instance_geometry_set_cast_shadows_setting(axis_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF);
+ RS::get_singleton()->instance_set_layer_mask(axis_gizmo_instance[i], layer);
}
// Rotation white outline
@@ -3553,6 +3289,7 @@ void Node3DEditorViewport::_finish_gizmo_instances() {
RS::get_singleton()->free(rotate_gizmo_instance[i]);
RS::get_singleton()->free(scale_gizmo_instance[i]);
RS::get_singleton()->free(scale_plane_gizmo_instance[i]);
+ RS::get_singleton()->free(axis_gizmo_instance[i]);
}
// Rotation white outline
RS::get_singleton()->free(rotate_gizmo_instance[3]);
@@ -3618,7 +3355,7 @@ void Node3DEditorViewport::_selection_result_pressed(int p_result) {
void Node3DEditorViewport::_selection_menu_hide() {
selection_results.clear();
selection_menu->clear();
- selection_menu->set_size(Vector2(0, 0));
+ selection_menu->reset_size();
}
void Node3DEditorViewport::set_can_preview(Camera3D *p_preview) {
@@ -3645,14 +3382,15 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
+ RenderingServer::get_singleton()->instance_set_visible(axis_gizmo_instance[i], false);
}
// Rotation white outline
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], false);
return;
}
- const Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
- const Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
+ const Vector3 camz = -camera_xform.get_basis().get_column(2).normalized();
+ const Vector3 camy = -camera_xform.get_basis().get_column(1).normalized();
const Plane p = Plane(camz, camera_xform.origin);
const real_t gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
const real_t d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
@@ -3669,8 +3407,6 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
subviewport_container->get_stretch_shrink();
Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
- xform.basis.scale(scale);
-
// if the determinant is zero, we should disable the gizmo from being rendered
// this prevents supplying bad values to the renderer and then having to filter it out again
if (xform.basis.determinant() == 0) {
@@ -3687,18 +3423,34 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
}
for (int i = 0; i < 3; i++) {
- RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
+ Transform3D axis_angle = Transform3D();
+ if (xform.basis.get_column(i).normalized().dot(xform.basis.get_column((i + 1) % 3).normalized()) < 1.0) {
+ axis_angle = axis_angle.looking_at(xform.basis.get_column(i).normalized(), xform.basis.get_column((i + 1) % 3).normalized());
+ }
+ axis_angle.basis.scale(scale);
+ axis_angle.origin = xform.origin;
+ RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE));
- RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE));
- RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE));
- RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
- RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
+ RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE));
+ RenderingServer::get_singleton()->instance_set_transform(axis_gizmo_instance[i], xform);
}
+
+ bool show_axes = spatial_editor->is_gizmo_visible() && _edit.mode != TRANSFORM_NONE;
+ RenderingServer *rs = RenderingServer::get_singleton();
+ rs->instance_set_visible(axis_gizmo_instance[0], show_axes && (_edit.plane == TRANSFORM_X_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_XZ));
+ rs->instance_set_visible(axis_gizmo_instance[1], show_axes && (_edit.plane == TRANSFORM_Y_AXIS || _edit.plane == TRANSFORM_XY || _edit.plane == TRANSFORM_YZ));
+ rs->instance_set_visible(axis_gizmo_instance[2], show_axes && (_edit.plane == TRANSFORM_Z_AXIS || _edit.plane == TRANSFORM_XZ || _edit.plane == TRANSFORM_YZ));
+
// Rotation white outline
+ xform.orthonormalize();
+ xform.basis.scale(scale);
RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform);
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE));
}
@@ -3890,7 +3642,7 @@ void Node3DEditorViewport::focus_selection() {
Vector3 center;
int count = 0;
- List<Node *> &selection = editor_selection->get_selected_node_list();
+ const List<Node *> &selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
Node3D *sp = Object::cast_to<Node3D>(E);
@@ -3936,9 +3688,13 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const
Vector3 point = world_pos + world_ray * MAX_DISTANCE;
PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world_3d()->get_direct_space_state();
- PhysicsDirectSpaceState3D::RayResult result;
- if (ss->intersect_ray(world_pos, world_pos + world_ray * MAX_DISTANCE, result)) {
+ PhysicsDirectSpaceState3D::RayParameters ray_params;
+ ray_params.from = world_pos;
+ ray_params.to = world_pos + world_ray * MAX_DISTANCE;
+
+ PhysicsDirectSpaceState3D::RayResult result;
+ if (ss->intersect_ray(ray_params, result)) {
point = result.position;
}
@@ -3958,7 +3714,7 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, boo
if (child) {
AABB child_bounds = _calculate_spatial_bounds(child, false);
- if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Node3D")) {
+ if (bounds.size == Vector3() && Object::cast_to<Node3D>(p_parent)) {
bounds = child_bounds;
} else {
bounds.merge_with(child_bounds);
@@ -3966,7 +3722,7 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, boo
}
}
- if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Node3D")) {
+ if (bounds.size == Vector3() && !Object::cast_to<Node3D>(p_parent)) {
bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
}
@@ -3977,10 +3733,41 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, boo
return bounds;
}
+Node *Node3DEditorViewport::_sanitize_preview_node(Node *p_node) const {
+ Node3D *node_3d = Object::cast_to<Node3D>(p_node);
+ if (node_3d == nullptr) {
+ Node3D *replacement_node = memnew(Node3D);
+ replacement_node->set_name(p_node->get_name());
+ p_node->replace_by(replacement_node);
+ memdelete(p_node);
+ p_node = replacement_node;
+ } else {
+ VisualInstance3D *visual_instance = Object::cast_to<VisualInstance3D>(node_3d);
+ if (visual_instance == nullptr) {
+ Node3D *replacement_node = memnew(Node3D);
+ replacement_node->set_name(node_3d->get_name());
+ replacement_node->set_visible(node_3d->is_visible());
+ replacement_node->set_transform(node_3d->get_transform());
+ replacement_node->set_rotation_edit_mode(node_3d->get_rotation_edit_mode());
+ replacement_node->set_rotation_order(node_3d->get_rotation_order());
+ replacement_node->set_as_top_level(node_3d->is_set_as_top_level());
+ p_node->replace_by(replacement_node);
+ memdelete(p_node);
+ p_node = replacement_node;
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _sanitize_preview_node(p_node->get_child(i));
+ }
+
+ return p_node;
+}
+
void Node3DEditorViewport::_create_preview(const Vector<String> &files) const {
for (int i = 0; i < files.size(); i++) {
String path = files[i];
- RES res = ResourceLoader::load(path);
+ Ref<Resource> res = ResourceLoader::load(path);
ERR_CONTINUE(res.is_null());
Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
@@ -3993,11 +3780,12 @@ void Node3DEditorViewport::_create_preview(const Vector<String> &files) const {
if (scene.is_valid()) {
Node *instance = scene->instantiate();
if (instance) {
+ instance = _sanitize_preview_node(instance);
preview_node->add_child(instance);
}
}
}
- editor->get_scene_root()->add_child(preview_node);
+ EditorNode::get_singleton()->get_scene_root()->add_child(preview_node);
}
}
*preview_bounds = _calculate_spatial_bounds(preview_node);
@@ -4010,7 +3798,7 @@ void Node3DEditorViewport::_remove_preview() {
node->queue_delete();
preview_node->remove_child(node);
}
- editor->get_scene_root()->remove_child(preview_node);
+ EditorNode::get_singleton()->get_scene_root()->remove_child(preview_node);
}
}
@@ -4030,7 +3818,7 @@ bool Node3DEditorViewport::_cyclical_dependency_exists(const String &p_target_sc
}
bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
- RES res = ResourceLoader::load(path);
+ Ref<Resource> res = ResourceLoader::load(path);
ERR_FAIL_COND_V(res.is_null(), false);
Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
@@ -4042,7 +3830,23 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
if (mesh != nullptr) {
MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
mesh_instance->set_mesh(mesh);
- mesh_instance->set_name(path.get_file().get_basename());
+
+ // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
+ String name = path.get_file().get_basename();
+ switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) {
+ case NAME_CASING_PASCAL_CASE:
+ name = name.capitalize().replace(" ", "");
+ break;
+ case NAME_CASING_CAMEL_CASE:
+ name = name.capitalize().replace(" ", "");
+ name[0] = name.to_lower()[0];
+ break;
+ case NAME_CASING_SNAKE_CASE:
+ name = name.capitalize().replace(" ", "_").to_lower();
+ break;
+ }
+ mesh_instance->set_name(name);
+
instantiated_scene = mesh_instance;
} else {
if (!scene.is_valid()) { // invalid scene
@@ -4057,8 +3861,8 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
return false;
}
- if (editor->get_edited_scene()->get_scene_file_path() != "") { // cyclical instancing
- if (_cyclical_dependency_exists(editor->get_edited_scene()->get_scene_file_path(), instantiated_scene)) {
+ if (!EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path().is_empty()) { // cyclical instancing
+ if (_cyclical_dependency_exists(EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path(), instantiated_scene)) {
memdelete(instantiated_scene);
return false;
}
@@ -4068,15 +3872,15 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
}
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene);
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true);
+ editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene());
editor_data->get_undo_redo().add_do_reference(instantiated_scene);
editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
String new_name = parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name);
+ editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene);
if (node3d) {
@@ -4104,7 +3908,7 @@ void Node3DEditorViewport::_perform_drop_data() {
for (int i = 0; i < selected_files.size(); i++) {
String path = selected_files[i];
- RES res = ResourceLoader::load(path);
+ Ref<Resource> res = ResourceLoader::load(path);
if (res.is_null()) {
continue;
}
@@ -4145,27 +3949,19 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
ResourceLoader::get_recognized_extensions_for_type("Mesh", &mesh_extensions);
for (int i = 0; i < files.size(); i++) {
+ // Check if dragged files with mesh or scene extension can be created at least once.
if (mesh_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
- RES res = ResourceLoader::load(files[i]);
+ Ref<Resource> res = ResourceLoader::load(files[i]);
if (res.is_null()) {
continue;
}
-
- String type = res->get_class();
- if (type == "PackedScene") {
- Ref<PackedScene> sdata = ResourceLoader::load(files[i]);
- Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ Ref<PackedScene> scn = res;
+ if (scn.is_valid()) {
+ Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instantiated_scene) {
continue;
}
memdelete(instantiated_scene);
- } else if (ClassDB::is_parent_class(type, "Mesh")) {
- Ref<Mesh> mesh = ResourceLoader::load(files[i]);
- if (!mesh.is_valid()) {
- continue;
- }
- } else {
- continue;
}
can_instantiate = true;
break;
@@ -4192,8 +3988,8 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
return;
}
- bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);
+ bool is_shift = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
selected_files.clear();
Dictionary d = p_data;
@@ -4201,8 +3997,8 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
selected_files = d["files"];
}
- List<Node *> selected_nodes = editor->get_editor_selection()->get_selected_node_list();
- Node *root_node = editor->get_edited_scene();
+ List<Node *> selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list();
+ Node *root_node = EditorNode::get_singleton()->get_edited_scene();
if (selected_nodes.size() == 1) {
Node *selected_node = selected_nodes[0];
target_node = root_node;
@@ -4215,10 +4011,9 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
if (root_node) {
target_node = root_node;
} else {
- accept->set_text(TTR("Cannot drag and drop into scene with no root node."));
- accept->popup_centered();
- _remove_preview();
- return;
+ // Create a root node so we can add child nodes to it.
+ SceneTreeDock::get_singleton()->add_root_node(memnew(Node3D));
+ target_node = get_tree()->get_edited_scene_root();
}
} else {
accept->set_text(TTR("Cannot drag and drop into multiple selected nodes."));
@@ -4232,20 +4027,430 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
_perform_drop_data();
}
-Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
+void Node3DEditorViewport::begin_transform(TransformMode p_mode, bool instant) {
+ if (get_selected_count() > 0) {
+ _edit.mode = p_mode;
+ _compute_edit(_edit.mouse_pos);
+ _edit.instant = instant;
+ _edit.snap = spatial_editor->is_snap_enabled();
+ }
+}
+
+void Node3DEditorViewport::commit_transform() {
+ ERR_FAIL_COND(_edit.mode == TRANSFORM_NONE);
+ static const char *_transform_name[4] = {
+ TTRC("None"),
+ TTRC("Rotate"),
+ // TRANSLATORS: This refers to the movement that changes the position of an object.
+ TTRC("Translate"),
+ TTRC("Scale"),
+ };
+ undo_redo->create_action(_transform_name[_edit.mode]);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+ Node3D *sp = Object::cast_to<Node3D>(E->get());
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
+ undo_redo->add_undo_method(sp, "set_global_transform", se->original);
+ }
+ undo_redo->commit_action();
+
+ finish_transform();
+ set_message("");
+}
+
+void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
+ Vector3 ray_pos = _get_ray_pos(p_mousepos);
+ Vector3 ray = _get_ray(p_mousepos);
+ double snap = EDITOR_GET("interface/inspector/default_float_step");
+ int snap_step_decimals = Math::range_step_decimals(snap);
+
+ switch (_edit.mode) {
+ case TRANSFORM_SCALE: {
+ Vector3 motion_mask;
+ Plane plane;
+ bool plane_mv = false;
+
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ motion_mask = Vector3(0, 0, 0);
+ plane = Plane(_get_camera_normal(), _edit.center);
+ break;
+ case TRANSFORM_X_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(0).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Y_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(1).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Z_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(2).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_YZ:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_column(1).normalized();
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(0).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XZ:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_column(0).normalized();
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(1).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XY:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(0).normalized() + spatial_editor->get_gizmo_transform().basis.get_column(1).normalized();
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(2).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
+ break;
+ }
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
+ break;
+ }
+
+ Vector3 motion = intersection - click;
+ if (_edit.plane != TRANSFORM_VIEW) {
+ if (!plane_mv) {
+ motion = motion_mask.dot(motion) * motion_mask;
+
+ } else {
+ // Alternative planar scaling mode
+ if (p_shift) {
+ motion = motion_mask.dot(motion) * motion_mask;
+ }
+ }
+
+ } else {
+ const real_t center_click_dist = click.distance_to(_edit.center);
+ const real_t center_inters_dist = intersection.distance_to(_edit.center);
+ if (center_click_dist == 0) {
+ break;
+ }
+
+ const real_t scale = center_inters_dist - center_click_dist;
+ motion = Vector3(scale, scale, scale);
+ }
+
+ motion /= click.distance_to(_edit.center);
+
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_scale_snap() / 100;
+ }
+ Vector3 motion_snapped = motion;
+ motion_snapped.snap(Vector3(snap, snap, snap));
+ // This might not be necessary anymore after issue #288 is solved (in 4.0?).
+ set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+ motion = _edit.original.basis.inverse().xform(motion);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Node3D *sp = Object::cast_to<Node3D>(E);
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ if (se->gizmo.is_valid()) {
+ for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
+ Transform3D xform = GE.value;
+ Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo.
+ if (!local_coords) {
+ new_xform = se->original.affine_inverse() * new_xform;
+ }
+ se->gizmo->set_subgizmo_transform(GE.key, new_xform);
+ }
+ } else {
+ Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
+ _transform_gizmo_apply(se->sp, new_xform, local_coords);
+ }
+ }
+
+ spatial_editor->update_transform_gizmo();
+ surface->update();
+
+ } break;
+
+ case TRANSFORM_TRANSLATE: {
+ Vector3 motion_mask;
+ Plane plane;
+ bool plane_mv = false;
+
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ plane = Plane(_get_camera_normal(), _edit.center);
+ break;
+ case TRANSFORM_X_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(0).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Y_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(1).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_Z_AXIS:
+ motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(2).normalized();
+ plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
+ break;
+ case TRANSFORM_YZ:
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(0).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XZ:
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(1).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ case TRANSFORM_XY:
+ plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(2).normalized(), _edit.center);
+ plane_mv = true;
+ break;
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
+ break;
+ }
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
+ break;
+ }
+
+ Vector3 motion = intersection - click;
+ if (_edit.plane != TRANSFORM_VIEW) {
+ if (!plane_mv) {
+ motion = motion_mask.dot(motion) * motion_mask;
+ }
+ }
+
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_translate_snap();
+ }
+ Vector3 motion_snapped = motion;
+ motion_snapped.snap(Vector3(snap, snap, snap));
+ set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+ motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion);
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Node3D *sp = Object::cast_to<Node3D>(E);
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ if (se->gizmo.is_valid()) {
+ for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
+ Transform3D xform = GE.value;
+ Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo.
+ new_xform = se->original.affine_inverse() * new_xform;
+ se->gizmo->set_subgizmo_transform(GE.key, new_xform);
+ }
+ } else {
+ Transform3D new_xform = _compute_transform(TRANSFORM_TRANSLATE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
+ _transform_gizmo_apply(se->sp, new_xform, false);
+ }
+ }
+
+ spatial_editor->update_transform_gizmo();
+ surface->update();
+
+ } break;
+
+ case TRANSFORM_ROTATE: {
+ Plane plane = Plane(_get_camera_normal(), _edit.center);
+
+ Vector3 local_axis;
+ Vector3 global_axis;
+ switch (_edit.plane) {
+ case TRANSFORM_VIEW:
+ // local_axis unused
+ global_axis = _get_camera_normal();
+ break;
+ case TRANSFORM_X_AXIS:
+ local_axis = Vector3(1, 0, 0);
+ break;
+ case TRANSFORM_Y_AXIS:
+ local_axis = Vector3(0, 1, 0);
+ break;
+ case TRANSFORM_Z_AXIS:
+ local_axis = Vector3(0, 0, 1);
+ break;
+ case TRANSFORM_YZ:
+ case TRANSFORM_XZ:
+ case TRANSFORM_XY:
+ break;
+ }
+
+ if (_edit.plane != TRANSFORM_VIEW) {
+ global_axis = spatial_editor->get_gizmo_transform().basis.xform(local_axis).normalized();
+ }
+
+ Vector3 intersection;
+ if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
+ break;
+ }
+
+ Vector3 click;
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
+ break;
+ }
+
+ static const float orthogonal_threshold = Math::cos(Math::deg2rad(87.0f));
+ bool axis_is_orthogonal = ABS(plane.normal.dot(global_axis)) < orthogonal_threshold;
+
+ double angle = 0.0f;
+ if (axis_is_orthogonal) {
+ _edit.show_rotation_line = false;
+ Vector3 projection_axis = plane.normal.cross(global_axis);
+ Vector3 delta = intersection - click;
+ float projection = delta.dot(projection_axis);
+ angle = (projection * (Math_PI / 2.0f)) / (gizmo_scale * GIZMO_CIRCLE_SIZE);
+ } else {
+ _edit.show_rotation_line = true;
+ Vector3 click_axis = (click - _edit.center).normalized();
+ Vector3 current_axis = (intersection - _edit.center).normalized();
+ angle = click_axis.signed_angle_to(current_axis, global_axis);
+ }
+
+ if (_edit.snap || spatial_editor->is_snap_enabled()) {
+ snap = spatial_editor->get_rotate_snap();
+ }
+ angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
+ angle -= Math::fmod(angle, snap);
+ set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
+ angle = Math::deg2rad(angle);
+
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
+
+ List<Node *> &selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Node3D *sp = Object::cast_to<Node3D>(E);
+ if (!sp) {
+ continue;
+ }
+
+ Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
+ if (!se) {
+ continue;
+ }
+
+ if (sp->has_meta("_edit_lock_")) {
+ continue;
+ }
+
+ Vector3 compute_axis = local_coords ? local_axis : global_axis;
+ if (se->gizmo.is_valid()) {
+ for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
+ Transform3D xform = GE.value;
+
+ Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original * xform, xform, compute_axis, angle, local_coords, true); // Force orthogonal with subgizmo.
+ if (!local_coords) {
+ new_xform = se->original.affine_inverse() * new_xform;
+ }
+ se->gizmo->set_subgizmo_transform(GE.key, new_xform);
+ }
+ } else {
+ Transform3D new_xform = _compute_transform(TRANSFORM_ROTATE, se->original, se->original_local, compute_axis, angle, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
+ _transform_gizmo_apply(se->sp, new_xform, local_coords);
+ }
+ }
+
+ spatial_editor->update_transform_gizmo();
+ surface->update();
+
+ } break;
+ default: {
+ }
+ }
+}
+
+void Node3DEditorViewport::finish_transform() {
+ spatial_editor->set_local_coords_enabled(_edit.original_local);
+ spatial_editor->update_transform_gizmo();
+ _edit.mode = TRANSFORM_NONE;
+ _edit.instant = false;
+ surface->update();
+}
+
+// Register a shortcut and also add it as an input action with the same events.
+void Node3DEditorViewport::register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode) {
+ Ref<Shortcut> sc = ED_SHORTCUT(p_path, p_name, p_keycode);
+ shortcut_changed_callback(sc, p_path);
+ // Connect to the change event on the shortcut so the input binding can be updated.
+ sc->connect("changed", callable_mp(this, &Node3DEditorViewport::shortcut_changed_callback), varray(sc, p_path));
+}
+
+// Update the action in the InputMap to the provided shortcut events.
+void Node3DEditorViewport::shortcut_changed_callback(const Ref<Shortcut> p_shortcut, const String &p_shortcut_path) {
+ InputMap *im = InputMap::get_singleton();
+ if (im->has_action(p_shortcut_path)) {
+ im->action_erase_events(p_shortcut_path);
+ } else {
+ im->add_action(p_shortcut_path);
+ }
+
+ for (int i = 0; i < p_shortcut->get_events().size(); i++) {
+ im->action_add_event(p_shortcut_path, p_shortcut->get_events()[i]);
+ }
+}
+
+Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p_index) {
cpu_time_history_index = 0;
gpu_time_history_index = 0;
_edit.mode = TRANSFORM_NONE;
_edit.plane = TRANSFORM_VIEW;
_edit.snap = true;
+ _edit.show_rotation_line = true;
+ _edit.instant = false;
_edit.gizmo_handle = -1;
+ _edit.gizmo_handle_secondary = false;
index = p_index;
- editor = p_editor;
- editor_data = editor->get_scene_tree_dock()->get_editor_data();
- editor_selection = editor->get_editor_selection();
- undo_redo = editor->get_undo_redo();
+ editor_data = SceneTreeDock::get_singleton()->get_editor_data();
+ editor_selection = EditorNode::get_singleton()->get_editor_selection();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
orthogonal = false;
auto_orthogonal = false;
@@ -4315,7 +4520,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("Normal Buffer"), VIEW_DISPLAY_NORMAL_BUFFER);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("Shadow Atlas"), VIEW_DISPLAY_DEBUG_SHADOW_ATLAS);
- display_submenu->add_radio_check_item(TTR("Directional Shadow"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS);
+ display_submenu->add_radio_check_item(TTR("Directional Shadow Map"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("Decal Atlas"), VIEW_DISPLAY_DEBUG_DECAL_ATLAS);
display_submenu->add_separator();
@@ -4329,15 +4534,16 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("Scene Luminance"), VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO);
+ display_submenu->add_radio_check_item(TTR("SSIL"), VIEW_DISPLAY_DEBUG_SSIL);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("GI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER);
+ display_submenu->add_radio_check_item(TTR("VoxelGI/SDFGI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Disable LOD"), VIEW_DISPLAY_DEBUG_DISABLE_LOD);
+ display_submenu->add_radio_check_item(TTR("Disable Mesh LOD"), VIEW_DISPLAY_DEBUG_DISABLE_LOD);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Omni Light Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS);
- display_submenu->add_radio_check_item(TTR("Spot Light Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS);
+ display_submenu->add_radio_check_item(TTR("OmniLight3D Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS);
+ display_submenu->add_radio_check_item(TTR("SpotLight3D Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS);
display_submenu->add_radio_check_item(TTR("Decal Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_DECALS);
- display_submenu->add_radio_check_item(TTR("Reflection Probe Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES);
+ display_submenu->add_radio_check_item(TTR("ReflectionProbe Cluster"), VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES);
display_submenu->add_radio_check_item(TTR("Occlusion Culling Buffer"), VIEW_DISPLAY_DEBUG_OCCLUDERS);
display_submenu->set_name("display_advanced");
@@ -4388,18 +4594,29 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip);
}
- ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A);
- ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D);
- ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W);
- ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S);
- ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_E);
- ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_Q);
- ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT);
- ED_SHORTCUT("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), KEY_ALT);
+ register_shortcut_action("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A);
+ register_shortcut_action("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D);
+ register_shortcut_action("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W);
+ register_shortcut_action("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), Key::S);
+ register_shortcut_action("spatial_editor/freelook_up", TTR("Freelook Up"), Key::E);
+ register_shortcut_action("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q);
+ register_shortcut_action("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), Key::SHIFT);
+ register_shortcut_action("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), Key::ALT);
+
+ ED_SHORTCUT("spatial_editor/lock_transform_x", TTR("Lock Transformation to X axis"), Key::X);
+ ED_SHORTCUT("spatial_editor/lock_transform_y", TTR("Lock Transformation to Y axis"), Key::Y);
+ ED_SHORTCUT("spatial_editor/lock_transform_z", TTR("Lock Transformation to Z axis"), Key::Z);
+ ED_SHORTCUT("spatial_editor/lock_transform_yz", TTR("Lock Transformation to YZ plane"), KeyModifierMask::SHIFT | Key::X);
+ ED_SHORTCUT("spatial_editor/lock_transform_xz", TTR("Lock Transformation to XZ plane"), KeyModifierMask::SHIFT | Key::Y);
+ ED_SHORTCUT("spatial_editor/lock_transform_xy", TTR("Lock Transformation to XY plane"), KeyModifierMask::SHIFT | Key::Z);
+ ED_SHORTCUT("spatial_editor/cancel_transform", TTR("Cancel Transformation"), Key::ESCAPE);
+ ED_SHORTCUT("spatial_editor/instant_translate", TTR("Begin Translate Transformation"));
+ ED_SHORTCUT("spatial_editor/instant_rotate", TTR("Begin Rotate Transformation"));
+ ED_SHORTCUT("spatial_editor/instant_scale", TTR("Begin Scale Transformation"));
preview_camera = memnew(CheckBox);
preview_camera->set_text(TTR("Preview"));
- preview_camera->set_shortcut(ED_SHORTCUT("spatial_editor/toggle_camera_preview", TTR("Toggle Camera Preview"), KEY_MASK_CMD | KEY_P));
+ preview_camera->set_shortcut(ED_SHORTCUT("spatial_editor/toggle_camera_preview", TTR("Toggle Camera Preview"), KeyModifierMask::CMD | Key::P));
vbox->add_child(preview_camera);
preview_camera->set_h_size_flags(0);
preview_camera->hide();
@@ -4422,7 +4639,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
cinema_label = memnew(Label);
cinema_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
cinema_label->set_h_grow_direction(GROW_DIRECTION_END);
- cinema_label->set_align(Label::ALIGN_CENTER);
+ cinema_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
surface->add_child(cinema_label);
cinema_label->set_text(TTR("Cinematic Preview"));
cinema_label->hide();
@@ -4433,7 +4650,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
locked_label->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -10 * EDSCALE);
locked_label->set_h_grow_direction(GROW_DIRECTION_END);
locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
- locked_label->set_align(Label::ALIGN_CENTER);
+ locked_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
surface->add_child(locked_label);
locked_label->set_text(TTR("View Rotation Locked"));
locked_label->hide();
@@ -4513,7 +4730,7 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
Vector2 size = get_size();
@@ -4597,197 +4814,202 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) {
}
void Node3DEditorViewportContainer::_notification(int p_what) {
- if (p_what == NOTIFICATION_MOUSE_ENTER || p_what == NOTIFICATION_MOUSE_EXIT) {
- mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
- update();
- }
+ switch (p_what) {
+ case NOTIFICATION_MOUSE_ENTER:
+ case NOTIFICATION_MOUSE_EXIT: {
+ mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
+ update();
+ } break;
- if (p_what == NOTIFICATION_DRAW && mouseover) {
- Ref<Texture2D> h_grabber = get_theme_icon(SNAME("grabber"), SNAME("HSplitContainer"));
- Ref<Texture2D> v_grabber = get_theme_icon(SNAME("grabber"), SNAME("VSplitContainer"));
+ case NOTIFICATION_DRAW: {
+ if (mouseover) {
+ Ref<Texture2D> h_grabber = get_theme_icon(SNAME("grabber"), SNAME("HSplitContainer"));
+ Ref<Texture2D> v_grabber = get_theme_icon(SNAME("grabber"), SNAME("VSplitContainer"));
- Ref<Texture2D> hdiag_grabber = get_theme_icon(SNAME("GuiViewportHdiagsplitter"), SNAME("EditorIcons"));
- Ref<Texture2D> vdiag_grabber = get_theme_icon(SNAME("GuiViewportVdiagsplitter"), SNAME("EditorIcons"));
- Ref<Texture2D> vh_grabber = get_theme_icon(SNAME("GuiViewportVhsplitter"), SNAME("EditorIcons"));
+ Ref<Texture2D> hdiag_grabber = get_theme_icon(SNAME("GuiViewportHdiagsplitter"), SNAME("EditorIcons"));
+ Ref<Texture2D> vdiag_grabber = get_theme_icon(SNAME("GuiViewportVdiagsplitter"), SNAME("EditorIcons"));
+ Ref<Texture2D> vh_grabber = get_theme_icon(SNAME("GuiViewportVhsplitter"), SNAME("EditorIcons"));
- Vector2 size = get_size();
+ Vector2 size = get_size();
- int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
+ int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
- int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
+ int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
+ int mid_w = size.width * ratio_h;
+ int mid_h = size.height * ratio_v;
- int size_left = mid_w - h_sep / 2;
- int size_bottom = size.height - mid_h - v_sep / 2;
+ int size_left = mid_w - h_sep / 2;
+ int size_bottom = size.height - mid_h - v_sep / 2;
- switch (view) {
- case VIEW_USE_1_VIEWPORT: {
- // Nothing to show.
+ switch (view) {
+ case VIEW_USE_1_VIEWPORT: {
+ // Nothing to show.
- } break;
- case VIEW_USE_2_VIEWPORTS: {
- draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
+ } break;
+ case VIEW_USE_2_VIEWPORTS: {
+ draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_VSPLIT);
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
+ } break;
+ case VIEW_USE_2_VIEWPORTS_ALT: {
+ draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
+ set_default_cursor_shape(CURSOR_HSPLIT);
- } break;
- case VIEW_USE_3_VIEWPORTS: {
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(hdiag_grabber, Vector2(mid_w - hdiag_grabber->get_width() / 2, mid_h - v_grabber->get_height() / 4));
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, mid_h + v_grabber->get_height() / 2 + (size_bottom - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
+ } break;
+ case VIEW_USE_3_VIEWPORTS: {
+ if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
+ draw_texture(hdiag_grabber, Vector2(mid_w - hdiag_grabber->get_width() / 2, mid_h - v_grabber->get_height() / 4));
+ set_default_cursor_shape(CURSOR_DRAG);
+ } else if ((hovering_v && !dragging_h) || dragging_v) {
+ draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_VSPLIT);
+ } else if (hovering_h || dragging_h) {
+ draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, mid_h + v_grabber->get_height() / 2 + (size_bottom - h_grabber->get_height()) / 2));
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ }
- } break;
- case VIEW_USE_3_VIEWPORTS_ALT: {
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(vdiag_grabber, Vector2(mid_w - vdiag_grabber->get_width() + v_grabber->get_height() / 4, mid_h - vdiag_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, Vector2((size_left - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
+ } break;
+ case VIEW_USE_3_VIEWPORTS_ALT: {
+ if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
+ draw_texture(vdiag_grabber, Vector2(mid_w - vdiag_grabber->get_width() + v_grabber->get_height() / 4, mid_h - vdiag_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_DRAG);
+ } else if ((hovering_v && !dragging_h) || dragging_v) {
+ draw_texture(v_grabber, Vector2((size_left - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
+ set_default_cursor_shape(CURSOR_VSPLIT);
+ } else if (hovering_h || dragging_h) {
+ draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ }
- } break;
- case VIEW_USE_4_VIEWPORTS: {
- Vector2 half(mid_w, mid_h);
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(vh_grabber, half - vh_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, half - v_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, half - h_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
+ } break;
+ case VIEW_USE_4_VIEWPORTS: {
+ Vector2 half(mid_w, mid_h);
+ if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
+ draw_texture(vh_grabber, half - vh_grabber->get_size() / 2.0);
+ set_default_cursor_shape(CURSOR_DRAG);
+ } else if ((hovering_v && !dragging_h) || dragging_v) {
+ draw_texture(v_grabber, half - v_grabber->get_size() / 2.0);
+ set_default_cursor_shape(CURSOR_VSPLIT);
+ } else if (hovering_h || dragging_h) {
+ draw_texture(h_grabber, half - h_grabber->get_size() / 2.0);
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ }
- } break;
- }
- }
+ } break;
+ }
+ }
+ } break;
- if (p_what == NOTIFICATION_SORT_CHILDREN) {
- Node3DEditorViewport *viewports[4];
- int vc = 0;
- for (int i = 0; i < get_child_count(); i++) {
- viewports[vc] = Object::cast_to<Node3DEditorViewport>(get_child(i));
- if (viewports[vc]) {
- vc++;
+ case NOTIFICATION_SORT_CHILDREN: {
+ Node3DEditorViewport *viewports[4];
+ int vc = 0;
+ for (int i = 0; i < get_child_count(); i++) {
+ viewports[vc] = Object::cast_to<Node3DEditorViewport>(get_child(i));
+ if (viewports[vc]) {
+ vc++;
+ }
}
- }
- ERR_FAIL_COND(vc != 4);
+ ERR_FAIL_COND(vc != 4);
- Size2 size = get_size();
+ Size2 size = get_size();
- if (size.x < 10 || size.y < 10) {
- for (int i = 0; i < 4; i++) {
- viewports[i]->hide();
+ if (size.x < 10 || size.y < 10) {
+ for (int i = 0; i < 4; i++) {
+ viewports[i]->hide();
+ }
+ return;
}
- return;
- }
- int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
+ int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
- int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
+ int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
+ int mid_w = size.width * ratio_h;
+ int mid_h = size.height * ratio_v;
- int size_left = mid_w - h_sep / 2;
- int size_right = size.width - mid_w - h_sep / 2;
+ int size_left = mid_w - h_sep / 2;
+ int size_right = size.width - mid_w - h_sep / 2;
- int size_top = mid_h - v_sep / 2;
- int size_bottom = size.height - mid_h - v_sep / 2;
+ int size_top = mid_h - v_sep / 2;
+ int size_bottom = size.height - mid_h - v_sep / 2;
- switch (view) {
- case VIEW_USE_1_VIEWPORT: {
- viewports[0]->show();
- for (int i = 1; i < 4; i++) {
- viewports[i]->hide();
- }
+ switch (view) {
+ case VIEW_USE_1_VIEWPORT: {
+ viewports[0]->show();
+ for (int i = 1; i < 4; i++) {
+ viewports[i]->hide();
+ }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), size));
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), size));
- } break;
- case VIEW_USE_2_VIEWPORTS: {
- for (int i = 0; i < 4; i++) {
- if (i == 1 || i == 3) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
+ } break;
+ case VIEW_USE_2_VIEWPORTS: {
+ for (int i = 0; i < 4; i++) {
+ if (i == 1 || i == 3) {
+ viewports[i]->hide();
+ } else {
+ viewports[i]->show();
+ }
}
- }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size.width, size_bottom)));
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size.width, size_bottom)));
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
- for (int i = 0; i < 4; i++) {
- if (i == 1 || i == 3) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
+ } break;
+ case VIEW_USE_2_VIEWPORTS_ALT: {
+ for (int i = 0; i < 4; i++) {
+ if (i == 1 || i == 3) {
+ viewports[i]->hide();
+ } else {
+ viewports[i]->show();
+ }
}
- }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size.height)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size.height)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
- } break;
- case VIEW_USE_3_VIEWPORTS: {
- for (int i = 0; i < 4; i++) {
- if (i == 1) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
+ } break;
+ case VIEW_USE_3_VIEWPORTS: {
+ for (int i = 0; i < 4; i++) {
+ if (i == 1) {
+ viewports[i]->hide();
+ } else {
+ viewports[i]->show();
+ }
}
- }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
+ fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
- } break;
- case VIEW_USE_3_VIEWPORTS_ALT: {
- for (int i = 0; i < 4; i++) {
- if (i == 1) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
+ } break;
+ case VIEW_USE_3_VIEWPORTS_ALT: {
+ for (int i = 0; i < 4; i++) {
+ if (i == 1) {
+ viewports[i]->hide();
+ } else {
+ viewports[i]->show();
+ }
}
- }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
+ fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
- } break;
- case VIEW_USE_4_VIEWPORTS: {
- for (int i = 0; i < 4; i++) {
- viewports[i]->show();
- }
+ } break;
+ case VIEW_USE_4_VIEWPORTS: {
+ for (int i = 0; i < 4; i++) {
+ viewports[i]->show();
+ }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
- fit_child_in_rect(viewports[1], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
+ fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
+ fit_child_in_rect(viewports[1], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size_top)));
+ fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
+ fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
- } break;
- }
+ } break;
+ }
+ } break;
}
}
@@ -4856,7 +5078,6 @@ void Node3DEditor::update_transform_gizmo() {
gizmo_center += xf.origin;
if (count == 0 && local_gizmo_coords) {
gizmo_basis = xf.basis;
- gizmo_basis.orthonormalize();
}
count++;
}
@@ -4881,7 +5102,6 @@ void Node3DEditor::update_transform_gizmo() {
gizmo_center += xf.origin;
if (count == 0 && local_gizmo_coords) {
gizmo_basis = xf.basis;
- gizmo_basis.orthonormalize();
}
count++;
}
@@ -5246,6 +5466,7 @@ void Node3DEditor::edit(Node3D *p_spatial) {
selected = p_spatial;
current_hover_gizmo = Ref<EditorNode3DGizmo>();
current_hover_gizmo_handle = -1;
+ current_hover_gizmo_handle_secondary = false;
if (selected) {
Vector<Ref<Node3DGizmo>> gizmos = selected->get_gizmos();
@@ -5292,7 +5513,7 @@ void Node3DEditor::_xform_dialog_action() {
undo_redo->create_action(TTR("XForm Dialog"));
- List<Node *> &selection = editor_selection->get_selected_node_list();
+ const List<Node *> &selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
Node3D *sp = Object::cast_to<Node3D>(E);
@@ -5712,9 +5933,9 @@ void fragment() {
float angle_fade = abs(dot(dir, NORMAL));
angle_fade = smoothstep(0.05, 0.2, angle_fade);
- vec3 world_pos = (CAMERA_MATRIX * vec4(VERTEX, 1.0)).xyz;
- vec3 world_normal = (CAMERA_MATRIX * vec4(NORMAL, 0.0)).xyz;
- vec3 camera_world_pos = CAMERA_MATRIX[3].xyz;
+ vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
+ vec3 world_normal = (INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz;
+ vec3 camera_world_pos = INV_VIEW_MATRIX[3].xyz;
vec3 camera_world_pos_on_plane = camera_world_pos * (1.0 - world_normal);
float dist_fade = 1.0 - (distance(world_pos, camera_world_pos_on_plane) / grid_size);
dist_fade = smoothstep(0.02, 0.3, dist_fade);
@@ -5756,6 +5977,12 @@ void fragment() {
{
//move gizmo
+ // Inverted zxy.
+ Vector3 ivec = Vector3(0, 0, -1);
+ Vector3 nivec = Vector3(-1, -1, 0);
+ Vector3 ivec2 = Vector3(-1, 0, 0);
+ Vector3 ivec3 = Vector3(0, -1, 0);
+
for (int i = 0; i < 3; i++) {
Color col;
switch (i) {
@@ -5780,6 +6007,7 @@ void fragment() {
rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ axis_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -5793,16 +6021,6 @@ void fragment() {
mat_hl->set_albedo(albedo);
gizmo_color_hl[i] = mat_hl;
- Vector3 ivec;
- ivec[i] = 1;
- Vector3 nivec;
- nivec[(i + 1) % 3] = 1;
- nivec[(i + 2) % 3] = 1;
- Vector3 ivec2;
- ivec2[(i + 1) % 3] = 1;
- Vector3 ivec3;
- ivec3[(i + 2) % 3] = 1;
-
//translate
{
Ref<SurfaceTool> surftool = memnew(SurfaceTool);
@@ -6111,6 +6329,22 @@ void fragment() {
plane_mat_hl->set_albedo(col.from_hsv(col.get_h(), 0.25, 1.0, 1));
plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
}
+
+ // Lines to visualize transforms locked to an axis/plane
+ {
+ Ref<SurfaceTool> surftool = memnew(SurfaceTool);
+ surftool->begin(Mesh::PRIMITIVE_LINE_STRIP);
+
+ Vector3 vec;
+ vec[i] = 1;
+
+ // line extending through infinity(ish)
+ surftool->add_vertex(vec * -1048576);
+ surftool->add_vertex(Vector3());
+ surftool->add_vertex(vec * 1048576);
+ surftool->set_material(mat_hl);
+ surftool->commit(axis_gizmo[i]);
+ }
}
}
@@ -6235,7 +6469,7 @@ void Node3DEditor::_init_grid() {
if (orthogonal) {
camera_distance = camera->get_size() / 2.0;
- Vector3 camera_direction = -camera->get_global_transform().get_basis().get_axis(2);
+ Vector3 camera_direction = -camera->get_global_transform().get_basis().get_column(2);
Plane grid_plane = Plane(normal);
Vector3 intersection;
if (grid_plane.intersects_ray(camera_position, camera_direction, &intersection)) {
@@ -6484,7 +6718,7 @@ Set<RID> _get_physics_bodies_rid(Node *node) {
}
void Node3DEditor::snap_selected_nodes_to_floor() {
- List<Node *> &selection = editor_selection->get_selected_node_list();
+ const List<Node *> &selection = editor_selection->get_selected_node_list();
Dictionary snap_data;
for (Node *E : selection) {
@@ -6559,14 +6793,19 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
// For snapping to be performed, there must be solid geometry under at least one of the selected nodes.
// We need to check this before snapping to register the undo/redo action only if needed.
for (int i = 0; i < keys.size(); i++) {
- Node *node = keys[i];
+ Node *node = Object::cast_to<Node>(keys[i]);
Node3D *sp = Object::cast_to<Node3D>(node);
Dictionary d = snap_data[node];
Vector3 from = d["from"];
Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
Set<RID> excluded = _get_physics_bodies_rid(sp);
- if (ss->intersect_ray(from, to, result, excluded)) {
+ PhysicsDirectSpaceState3D::RayParameters ray_params;
+ ray_params.from = from;
+ ray_params.to = to;
+ ray_params.exclude = excluded;
+
+ if (ss->intersect_ray(ray_params, result)) {
snapped_to_floor = true;
}
}
@@ -6576,14 +6815,19 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
// Perform snapping if at least one node can be snapped
for (int i = 0; i < keys.size(); i++) {
- Node *node = keys[i];
+ Node *node = Object::cast_to<Node>(keys[i]);
Node3D *sp = Object::cast_to<Node3D>(node);
Dictionary d = snap_data[node];
Vector3 from = d["from"];
Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
Set<RID> excluded = _get_physics_bodies_rid(sp);
- if (ss->intersect_ray(from, to, result, excluded)) {
+ PhysicsDirectSpaceState3D::RayParameters ray_params;
+ ray_params.from = from;
+ ray_params.to = to;
+ ray_params.exclude = excluded;
+
+ if (ss->intersect_ray(ray_params, result)) {
Vector3 position_offset = d["position_offset"];
Transform3D new_transform = sp->get_global_transform();
@@ -6602,26 +6846,27 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
}
}
-void Node3DEditor::unhandled_key_input(const Ref<InputEvent> &p_event) {
+void Node3DEditor::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!is_visible_in_tree()) {
return;
}
- snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CTRL);
+ snap_key_enabled = Input::get_singleton()->is_key_pressed(Key::CTRL);
}
void Node3DEditor::_sun_environ_settings_pressed() {
Vector2 pos = sun_environ_settings->get_screen_position() + sun_environ_settings->get_size();
sun_environ_popup->set_position(pos - Vector2(sun_environ_popup->get_contents_minimum_size().width / 2, 0));
+ sun_environ_popup->reset_size();
sun_environ_popup->popup();
}
void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
sun_environ_popup->hide();
- if (!p_already_added_environment && world_env_count == 0 && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (!p_already_added_environment && world_env_count == 0 && Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Prevent infinite feedback loop between the sun and environment methods.
_add_environment_to_scene(true);
}
@@ -6629,14 +6874,14 @@ void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
Node *base = get_tree()->get_edited_scene_root();
if (!base) {
// Create a root node so we can add child nodes to it.
- EditorNode::get_singleton()->get_scene_tree_dock()->add_root_node(memnew(Node3D));
+ SceneTreeDock::get_singleton()->add_root_node(memnew(Node3D));
base = get_tree()->get_edited_scene_root();
}
ERR_FAIL_COND(!base);
Node *new_sun = preview_sun->duplicate();
undo_redo->create_action(TTR("Add Preview Sun to Scene"));
- undo_redo->add_do_method(base, "add_child", new_sun);
+ undo_redo->add_do_method(base, "add_child", new_sun, true);
// Move to the beginning of the scene tree since more "global" nodes
// generally look better when placed at the top.
undo_redo->add_do_method(base, "move_child", new_sun, 0);
@@ -6649,7 +6894,7 @@ void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
sun_environ_popup->hide();
- if (!p_already_added_sun && directional_light_count == 0 && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (!p_already_added_sun && directional_light_count == 0 && Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Prevent infinite feedback loop between the sun and environment methods.
_add_sun_to_scene(true);
}
@@ -6657,7 +6902,7 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
Node *base = get_tree()->get_edited_scene_root();
if (!base) {
// Create a root node so we can add child nodes to it.
- EditorNode::get_singleton()->get_scene_tree_dock()->add_root_node(memnew(Node3D));
+ SceneTreeDock::get_singleton()->add_root_node(memnew(Node3D));
base = get_tree()->get_edited_scene_root();
}
ERR_FAIL_COND(!base);
@@ -6666,7 +6911,7 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
new_env->set_environment(preview_environment->get_environment()->duplicate(true));
undo_redo->create_action(TTR("Add Preview Environment to Scene"));
- undo_redo->add_do_method(base, "add_child", new_env);
+ undo_redo->add_do_method(base, "add_child", new_env, true);
// Move to the beginning of the scene tree since more "global" nodes
// generally look better when placed at the top.
undo_redo->add_do_method(base, "move_child", new_env, 0);
@@ -6677,19 +6922,19 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
}
void Node3DEditor::_update_theme() {
- tool_button[Node3DEditor::TOOL_MODE_SELECT]->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_MODE_MOVE]->set_icon(get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_MODE_ROTATE]->set_icon(get_theme_icon(SNAME("ToolRotate"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_MODE_SCALE]->set_icon(get_theme_icon(SNAME("ToolScale"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon(SNAME("ListSelect"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_LOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Lock"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_GROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
- tool_button[Node3DEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
-
- tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")));
- tool_option_button[Node3DEditor::TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
- tool_option_button[Node3DEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_theme_icon(SNAME("Camera3D"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_SELECT]->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_MOVE]->set_icon(get_theme_icon(SNAME("ToolMove"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_ROTATE]->set_icon(get_theme_icon(SNAME("ToolRotate"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_SCALE]->set_icon(get_theme_icon(SNAME("ToolScale"), SNAME("EditorIcons")));
+ tool_button[TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon(SNAME("ListSelect"), SNAME("EditorIcons")));
+ tool_button[TOOL_LOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Lock"), SNAME("EditorIcons")));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons")));
+ tool_button[TOOL_GROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
+
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")));
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
+ tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_theme_icon(SNAME("Camera3D"), SNAME("EditorIcons")));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_theme_icon(SNAME("Panels1"), SNAME("EditorIcons")));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_theme_icon(SNAME("Panels2"), SNAME("EditorIcons")));
@@ -6715,17 +6960,18 @@ void Node3DEditor::_notification(int p_what) {
get_tree()->connect("node_removed", callable_mp(this, &Node3DEditor::_node_removed));
get_tree()->connect("node_added", callable_mp(this, &Node3DEditor::_node_added));
- EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons));
+ SceneTreeDock::get_singleton()->get_tree_editor()->connect("node_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons));
editor_selection->connect("selection_changed", callable_mp(this, &Node3DEditor::_selection_changed));
- editor->connect("stop_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(false));
- editor->connect("play_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(true));
+ EditorNode::get_singleton()->connect("stop_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(false));
+ EditorNode::get_singleton()->connect("play_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(true));
_update_preview_environment();
sun_state->set_custom_minimum_size(sun_vb->get_combined_minimum_size());
environ_state->set_custom_minimum_size(environ_vb->get_combined_minimum_size());
} break;
+
case NOTIFICATION_ENTER_TREE: {
_update_theme();
_register_all_gizmos();
@@ -6733,9 +6979,11 @@ void Node3DEditor::_notification(int p_what) {
_init_indicators();
update_all_gizmos();
} break;
+
case NOTIFICATION_EXIT_TREE: {
_finish_indicators();
} break;
+
case NOTIFICATION_THEME_CHANGED: {
_update_theme();
_update_gizmos_menu_theme();
@@ -6743,11 +6991,13 @@ void Node3DEditor::_notification(int p_what) {
sun_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
environ_title->add_theme_font_override("font", get_theme_font(SNAME("title_font"), SNAME("Window")));
} break;
+
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
// Update grid color by rebuilding grid.
_finish_grid();
_init_grid();
} break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
@@ -6805,8 +7055,46 @@ VSplitContainer *Node3DEditor::get_shader_split() {
return shader_split;
}
-HSplitContainer *Node3DEditor::get_palette_split() {
- return palette_split;
+void Node3DEditor::add_control_to_left_panel(Control *p_control) {
+ left_panel_split->add_child(p_control);
+ left_panel_split->move_child(p_control, 0);
+}
+
+void Node3DEditor::add_control_to_right_panel(Control *p_control) {
+ right_panel_split->add_child(p_control);
+ right_panel_split->move_child(p_control, 1);
+}
+
+void Node3DEditor::remove_control_from_left_panel(Control *p_control) {
+ left_panel_split->remove_child(p_control);
+}
+
+void Node3DEditor::remove_control_from_right_panel(Control *p_control) {
+ right_panel_split->remove_child(p_control);
+}
+
+void Node3DEditor::move_control_to_left_panel(Control *p_control) {
+ ERR_FAIL_NULL(p_control);
+ if (p_control->get_parent() == left_panel_split) {
+ return;
+ }
+
+ ERR_FAIL_COND(p_control->get_parent() != right_panel_split);
+ right_panel_split->remove_child(p_control);
+
+ add_control_to_left_panel(p_control);
+}
+
+void Node3DEditor::move_control_to_right_panel(Control *p_control) {
+ ERR_FAIL_NULL(p_control);
+ if (p_control->get_parent() == right_panel_split) {
+ return;
+ }
+
+ ERR_FAIL_COND(p_control->get_parent() != left_panel_split);
+ left_panel_split->remove_child(p_control);
+
+ add_control_to_right_panel(p_control);
}
void Node3DEditor::_request_gizmo(Object *p_obj) {
@@ -6817,7 +7105,8 @@ void Node3DEditor::_request_gizmo(Object *p_obj) {
bool is_selected = (sp == selected);
- if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_ancestor_of(sp)))) {
+ Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
+ if (edited_scene && (sp == edited_scene || (sp->get_owner() && edited_scene->is_ancestor_of(sp)))) {
for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) {
Ref<EditorNode3DGizmo> seg = gizmo_plugins_by_priority.write[i]->get_gizmo(sp);
@@ -6829,7 +7118,9 @@ void Node3DEditor::_request_gizmo(Object *p_obj) {
}
}
}
- sp->update_gizmos();
+ if (!sp->get_gizmos().is_empty()) {
+ sp->update_gizmos();
+ }
}
}
@@ -6985,6 +7276,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<OccluderInstance3DGizmoPlugin>(memnew(OccluderInstance3DGizmoPlugin)));
add_gizmo_plugin(Ref<SoftDynamicBody3DGizmoPlugin>(memnew(SoftDynamicBody3DGizmoPlugin)));
add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<Label3DGizmoPlugin>(memnew(Label3DGizmoPlugin)));
add_gizmo_plugin(Ref<Position3DGizmoPlugin>(memnew(Position3DGizmoPlugin)));
add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin)));
@@ -7046,7 +7338,7 @@ void Node3DEditor::clear() {
void Node3DEditor::_sun_direction_draw() {
sun_direction->draw_rect(Rect2(Vector2(), sun_direction->get_size()), Color(1, 1, 1, 1));
- Vector3 z_axis = preview_sun->get_transform().basis.get_axis(Vector3::AXIS_Z);
+ Vector3 z_axis = preview_sun->get_transform().basis.get_column(Vector3::AXIS_Z);
z_axis = get_editor_viewport(0)->camera->get_camera_transform().basis.xform_inv(z_axis);
sun_direction_material->set_shader_param("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z));
Color color = sun_color->get_pick_color() * sun_energy->get_value();
@@ -7097,8 +7389,8 @@ void Node3DEditor::_load_default_preview_settings() {
sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
sun_direction->update();
- environ_sky_color->set_pick_color(Color::hex(0x91b2ceff));
- environ_ground_color->set_pick_color(Color::hex(0x1f1f21ff));
+ environ_sky_color->set_pick_color(Color(0.385, 0.454, 0.55));
+ environ_ground_color->set_pick_color(Color(0.2, 0.169, 0.133));
environ_energy->set_value(1.0);
environ_glow_button->set_pressed(true);
environ_tonemap_button->set_pressed(true);
@@ -7132,7 +7424,7 @@ void Node3DEditor::_update_preview_environment() {
} else {
if (!preview_sun->get_parent()) {
- add_child(preview_sun);
+ add_child(preview_sun, true);
sun_state->hide();
sun_vb->show();
}
@@ -7168,7 +7460,7 @@ void Node3DEditor::_update_preview_environment() {
void Node3DEditor::_sun_direction_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
sun_rotation.x += mm->get_relative().y * (0.02 * EDSCALE);
sun_rotation.y -= mm->get_relative().x * (0.02 * EDSCALE);
sun_rotation.x = CLAMP(sun_rotation.x, -Math_TAU / 4, Math_TAU / 4);
@@ -7184,18 +7476,17 @@ void Node3DEditor::_sun_direction_angle_set() {
_preview_settings_changed();
}
-Node3DEditor::Node3DEditor(EditorNode *p_editor) {
+Node3DEditor::Node3DEditor() {
gizmo.visible = true;
gizmo.scale = 1.0;
viewport_environment = Ref<Environment>(memnew(Environment));
- undo_redo = p_editor->get_undo_redo();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
VBoxContainer *vbc = this;
custom_camera = nullptr;
singleton = this;
- editor = p_editor;
- editor_selection = editor->get_editor_selection();
+ editor_selection = EditorNode::get_singleton()->get_editor_selection();
editor_selection->add_editor_plugin(this);
snap_enabled = false;
@@ -7225,9 +7516,9 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SELECT]->set_pressed(true);
button_binds.write[0] = MENU_TOOL_SELECT;
tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q));
+ tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q));
tool_button[TOOL_MODE_SELECT]->set_shortcut_context(this);
- tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked."));
+ tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked."));
hbc_menu->add_child(memnew(VSeparator));
tool_button[TOOL_MODE_MOVE] = memnew(Button);
@@ -7236,7 +7527,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_MOVE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_MOVE;
tool_button[TOOL_MODE_MOVE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W));
+ tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), Key::W));
tool_button[TOOL_MODE_MOVE]->set_shortcut_context(this);
tool_button[TOOL_MODE_ROTATE] = memnew(Button);
@@ -7245,7 +7536,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_ROTATE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_ROTATE;
tool_button[TOOL_MODE_ROTATE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E));
+ tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), Key::E));
tool_button[TOOL_MODE_ROTATE]->set_shortcut_context(this);
tool_button[TOOL_MODE_SCALE] = memnew(Button);
@@ -7254,7 +7545,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SCALE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_SCALE;
tool_button[TOOL_MODE_SCALE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
- tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R));
+ tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), Key::R));
tool_button[TOOL_MODE_SCALE]->set_shortcut_context(this);
hbc_menu->add_child(memnew(VSeparator));
@@ -7274,7 +7565,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock selected node, preventing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KEY_MASK_CMD | KEY_L));
+ tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD | Key::L));
tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
@@ -7283,7 +7574,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock selected node, allowing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_L));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L));
tool_button[TOOL_GROUP_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
@@ -7292,7 +7583,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KEY_MASK_CMD | KEY_G));
+ tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G));
tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
@@ -7301,7 +7592,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
hbc_menu->add_child(memnew(VSeparator));
@@ -7311,7 +7602,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true);
button_binds.write[0] = MENU_TOOL_LOCAL_COORDS;
tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds);
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T));
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), Key::T));
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut_context(this);
tool_option_button[TOOL_OPT_USE_SNAP] = memnew(Button);
@@ -7320,7 +7611,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true);
button_binds.write[0] = MENU_TOOL_USE_SNAP;
tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds);
- tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y));
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), Key::Y));
tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut_context(this);
hbc_menu->add_child(memnew(VSeparator));
@@ -7366,27 +7657,27 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
preview_node = memnew(Node3D);
preview_bounds = AABB();
- ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT + KEY_KP_7);
- ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), KEY_KP_7);
- ED_SHORTCUT("spatial_editor/rear_view", TTR("Rear View"), KEY_MASK_ALT + KEY_KP_1);
- ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), KEY_KP_1);
- ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KEY_MASK_ALT + KEY_KP_3);
- ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), KEY_KP_3);
- ED_SHORTCUT("spatial_editor/orbit_view_down", TTR("Orbit View Down"), KEY_KP_2);
- ED_SHORTCUT("spatial_editor/orbit_view_left", TTR("Orbit View Left"), KEY_KP_4);
- ED_SHORTCUT("spatial_editor/orbit_view_right", TTR("Orbit View Right"), KEY_KP_6);
- ED_SHORTCUT("spatial_editor/orbit_view_up", TTR("Orbit View Up"), KEY_KP_8);
- ED_SHORTCUT("spatial_editor/orbit_view_180", TTR("Orbit View 180"), KEY_KP_9);
- ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal View"), KEY_KP_5);
- ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), KEY_K);
- ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), KEY_O);
- ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F);
- ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_M);
- ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F);
- ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F);
- ED_SHORTCUT("spatial_editor/decrease_fov", TTR("Decrease Field of View"), KEY_MASK_CMD + KEY_EQUAL); // Usually direct access key for `KEY_PLUS`.
- ED_SHORTCUT("spatial_editor/increase_fov", TTR("Increase Field of View"), KEY_MASK_CMD + KEY_MINUS);
- ED_SHORTCUT("spatial_editor/reset_fov", TTR("Reset Field of View to Default"), KEY_MASK_CMD + KEY_0);
+ ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KeyModifierMask::ALT + Key::KP_7);
+ ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), Key::KP_7);
+ ED_SHORTCUT("spatial_editor/rear_view", TTR("Rear View"), KeyModifierMask::ALT + Key::KP_1);
+ ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), Key::KP_1);
+ ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KeyModifierMask::ALT + Key::KP_3);
+ ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), Key::KP_3);
+ ED_SHORTCUT("spatial_editor/orbit_view_down", TTR("Orbit View Down"), Key::KP_2);
+ ED_SHORTCUT("spatial_editor/orbit_view_left", TTR("Orbit View Left"), Key::KP_4);
+ ED_SHORTCUT("spatial_editor/orbit_view_right", TTR("Orbit View Right"), Key::KP_6);
+ ED_SHORTCUT("spatial_editor/orbit_view_up", TTR("Orbit View Up"), Key::KP_8);
+ ED_SHORTCUT("spatial_editor/orbit_view_180", TTR("Orbit View 180"), Key::KP_9);
+ ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal View"), Key::KP_5);
+ ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), Key::K);
+ ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), Key::O);
+ ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), Key::F);
+ ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KeyModifierMask::ALT + KeyModifierMask::CMD + Key::M);
+ ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KeyModifierMask::ALT + KeyModifierMask::CMD + Key::F);
+ ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KeyModifierMask::SHIFT + Key::F);
+ ED_SHORTCUT("spatial_editor/decrease_fov", TTR("Decrease Field of View"), KeyModifierMask::CMD + Key::EQUAL); // Usually direct access key for `KEY_PLUS`.
+ ED_SHORTCUT("spatial_editor/increase_fov", TTR("Increase Field of View"), KeyModifierMask::CMD + Key::MINUS);
+ ED_SHORTCUT("spatial_editor/reset_fov", TTR("Reset Field of View to Default"), KeyModifierMask::CMD + Key::KEY_0);
PopupMenu *p;
@@ -7397,7 +7688,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
hbc_menu->add_child(transform_menu);
p = transform_menu->get_popup();
- p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR);
+ p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), Key::PAGEDOWN), MENU_SNAP_TO_FLOOR);
p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog...")), MENU_TRANSFORM_DIALOG);
p->add_separator();
@@ -7427,21 +7718,21 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
p->set_hide_on_checkable_item_selection(false);
accept = memnew(AcceptDialog);
- editor->get_gui_base()->add_child(accept);
-
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
- p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
+ EditorNode::get_singleton()->get_gui_base()->add_child(accept);
+
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KeyModifierMask::CMD + Key::KEY_1), MENU_VIEW_USE_1_VIEWPORT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KeyModifierMask::CMD + Key::KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KeyModifierMask::ALT + KeyModifierMask::CMD + Key::KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KeyModifierMask::CMD + Key::KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KeyModifierMask::ALT + KeyModifierMask::CMD + Key::KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KeyModifierMask::CMD + Key::KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
p->add_separator();
p->add_submenu_item(TTR("Gizmos"), "GizmosMenu");
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), KEY_NUMBERSIGN), MENU_VIEW_GRID);
+ p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), Key::NUMBERSIGN), MENU_VIEW_GRID);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
@@ -7459,18 +7750,22 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
/* REST OF MENU */
- palette_split = memnew(HSplitContainer);
- palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
- vbc->add_child(palette_split);
+ left_panel_split = memnew(HSplitContainer);
+ left_panel_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ vbc->add_child(left_panel_split);
+
+ right_panel_split = memnew(HSplitContainer);
+ right_panel_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ left_panel_split->add_child(right_panel_split);
shader_split = memnew(VSplitContainer);
shader_split->set_h_size_flags(SIZE_EXPAND_FILL);
- palette_split->add_child(shader_split);
+ right_panel_split->add_child(shader_split);
viewport_base = memnew(Node3DEditorViewportContainer);
shader_split->add_child(viewport_base);
viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
- viewports[i] = memnew(Node3DEditorViewport(this, editor, i));
+ viewports[i] = memnew(Node3DEditorViewport(this, i));
viewports[i]->connect("toggle_maximize_view", callable_mp(this, &Node3DEditor::_toggle_maximize_view));
viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_update_camera_override_viewport));
viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
@@ -7599,7 +7894,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
selected = nullptr;
- set_process_unhandled_key_input(true);
+ set_process_shortcut_input(true);
add_to_group("_spatial_editor_group");
EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80);
@@ -7609,6 +7904,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true);
current_hover_gizmo_handle = -1;
+ current_hover_gizmo_handle_secondary = false;
{
//sun popup
@@ -7628,7 +7924,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
sun_title->set_theme_type_variation("HeaderSmall");
sun_vb->add_child(sun_title);
sun_title->set_text(TTR("Preview Sun"));
- sun_title->set_align(Label::ALIGN_CENTER);
+ sun_title->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
CenterContainer *sun_direction_center = memnew(CenterContainer);
sun_direction = memnew(Control);
@@ -7716,8 +8012,8 @@ void fragment() {
sun_state = memnew(Label);
sun_environ_hb->add_child(sun_state);
- sun_state->set_align(Label::ALIGN_CENTER);
- sun_state->set_valign(Label::VALIGN_CENTER);
+ sun_state->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ sun_state->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
sun_state->set_h_size_flags(SIZE_EXPAND_FILL);
VSeparator *sc = memnew(VSeparator);
@@ -7735,7 +8031,7 @@ void fragment() {
environ_vb->add_child(environ_title);
environ_title->set_text(TTR("Preview Environment"));
- environ_title->set_align(Label::ALIGN_CENTER);
+ environ_title->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
environ_sky_color = memnew(ColorPickerButton);
environ_sky_color->set_edit_alpha(false);
@@ -7783,8 +8079,8 @@ void fragment() {
environ_state = memnew(Label);
sun_environ_hb->add_child(environ_state);
- environ_state->set_align(Label::ALIGN_CENTER);
- environ_state->set_valign(Label::VALIGN_CENTER);
+ environ_state->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ environ_state->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
environ_state->set_h_size_flags(SIZE_EXPAND_FILL);
preview_sun = memnew(DirectionalLight3D);
@@ -7854,7 +8150,7 @@ bool Node3DEditor::is_gizmo_visible() const {
double Node3DEditor::get_translate_snap() const {
double snap_value;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
snap_value = snap_translate->get_text().to_float() / 10.0;
} else {
snap_value = snap_translate->get_text().to_float();
@@ -7865,7 +8161,7 @@ double Node3DEditor::get_translate_snap() const {
double Node3DEditor::get_rotate_snap() const {
double snap_value;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
snap_value = snap_rotate->get_text().to_float() / 3.0;
} else {
snap_value = snap_rotate->get_text().to_float();
@@ -7876,7 +8172,7 @@ double Node3DEditor::get_rotate_snap() const {
double Node3DEditor::get_scale_snap() const {
double snap_value;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
snap_value = snap_scale->get_text().to_float() / 2.0;
} else {
snap_value = snap_scale->get_text().to_float();
@@ -7918,14 +8214,12 @@ void Node3DEditor::remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) {
_update_gizmos_menu();
}
-Node3DEditorPlugin::Node3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- spatial_editor = memnew(Node3DEditor(p_node));
+Node3DEditorPlugin::Node3DEditorPlugin() {
+ spatial_editor = memnew(Node3DEditor);
spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- editor->get_main_control()->add_child(spatial_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(spatial_editor);
spatial_editor->hide();
- spatial_editor->connect("transform_key_request", Callable(editor->get_inspector_dock(), "_transform_keyed"));
}
Node3DEditorPlugin::~Node3DEditorPlugin() {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 8d647808ba..43efdeec72 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,19 +31,23 @@
#ifndef NODE_3D_EDITOR_PLUGIN_H
#define NODE_3D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_scale.h"
+#include "editor/editor_spin_slider.h"
#include "editor/plugins/node_3d_editor_gizmos.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/3d/world_environment.h"
+#include "scene/gui/color_picker.h"
#include "scene/gui/panel_container.h"
+#include "scene/gui/spin_box.h"
+#include "scene/gui/split_container.h"
#include "scene/resources/environment.h"
#include "scene/resources/fog_material.h"
#include "scene/resources/sky_material.h"
+class EditorData;
class Node3DEditor;
class Node3DEditorViewport;
class SubViewportContainer;
@@ -125,6 +129,7 @@ class Node3DEditorViewport : public Control {
VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
+ VIEW_DISPLAY_DEBUG_SSIL,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
VIEW_DISPLAY_DEBUG_SDFGI,
@@ -185,29 +190,28 @@ private:
ViewType view_type;
void _menu_option(int p_option);
void _set_auto_orthogonal();
- Node3D *preview_node;
- AABB *preview_bounds;
+ Node3D *preview_node = nullptr;
+ AABB *preview_bounds = nullptr;
Vector<String> selected_files;
- AcceptDialog *accept;
+ AcceptDialog *accept = nullptr;
- Node *target_node;
+ Node *target_node = nullptr;
Point2 drop_pos;
- EditorNode *editor;
- EditorData *editor_data;
- EditorSelection *editor_selection;
- UndoRedo *undo_redo;
+ EditorData *editor_data = nullptr;
+ EditorSelection *editor_selection = nullptr;
+ UndoRedo *undo_redo = nullptr;
- CheckBox *preview_camera;
- SubViewportContainer *subviewport_container;
+ CheckBox *preview_camera = nullptr;
+ SubViewportContainer *subviewport_container = nullptr;
- MenuButton *view_menu;
- PopupMenu *display_submenu;
+ MenuButton *view_menu = nullptr;
+ PopupMenu *display_submenu = nullptr;
- Control *surface;
- SubViewport *viewport;
- Camera3D *camera;
- bool transforming;
+ Control *surface = nullptr;
+ SubViewport *viewport = nullptr;
+ Camera3D *camera = nullptr;
+ bool transforming = false;
bool orthogonal;
bool auto_orthogonal;
bool lock_rotation;
@@ -217,17 +221,17 @@ private:
real_t freelook_speed;
Vector2 previous_mouse_position;
- Label *info_label;
- Label *cinema_label;
- Label *locked_label;
- Label *zoom_limit_label;
+ Label *info_label = nullptr;
+ Label *cinema_label = nullptr;
+ Label *locked_label = nullptr;
+ Label *zoom_limit_label = nullptr;
- VBoxContainer *top_right_vbox;
- ViewportRotationControl *rotation_control;
- Gradient *frame_time_gradient;
- Label *cpu_time_label;
- Label *gpu_time_label;
- Label *fps_label;
+ VBoxContainer *top_right_vbox = nullptr;
+ ViewportRotationControl *rotation_control = nullptr;
+ Gradient *frame_time_gradient = nullptr;
+ Label *cpu_time_label = nullptr;
+ Label *gpu_time_label = nullptr;
+ Label *fps_label = nullptr;
struct _RayResult {
Node3D *item = nullptr;
@@ -246,6 +250,7 @@ private:
Point2 _point_to_screen(const Vector3 &p_point);
Transform3D _get_camera_transform() const;
int get_selected_count() const;
+ void cancel_transform();
Vector3 _get_camera_position() const;
Vector3 _get_camera_normal() const;
@@ -266,9 +271,10 @@ private:
ObjectID clicked;
Vector<_RayResult> selection_results;
- bool clicked_wants_append;
+ bool clicked_wants_append = false;
+ bool selection_in_progress = false;
- PopupMenu *selection_menu;
+ PopupMenu *selection_menu = nullptr;
enum NavigationZoomStyle {
NAVIGATION_ZOOM_VERTICAL,
@@ -309,9 +315,13 @@ private:
Point2 mouse_pos;
Point2 original_mouse_pos;
bool snap = false;
+ bool show_rotation_line = false;
Ref<EditorNode3DGizmo> gizmo;
int gizmo_handle = 0;
+ bool gizmo_handle_secondary = false;
Variant gizmo_initial_value;
+ bool original_local;
+ bool instant;
} _edit;
struct Cursor {
@@ -345,7 +355,7 @@ private:
real_t zoom_indicator_delay;
int zoom_failed_attempts_count = 0;
- RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
+ RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3], axis_gizmo_instance[3];
String last_message;
String message;
@@ -365,10 +375,10 @@ private:
void _sinput(const Ref<InputEvent> &p_event);
void _update_freelook(real_t delta);
- Node3DEditor *spatial_editor;
+ Node3DEditor *spatial_editor = nullptr;
- Camera3D *previewing;
- Camera3D *preview;
+ Camera3D *previewing = nullptr;
+ Camera3D *preview = nullptr;
bool previewing_cinema;
bool _is_node_locked(const Node *p_node);
@@ -384,6 +394,9 @@ private:
Vector3 _get_instance_position(const Point2 &p_pos) const;
static AABB _calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_top_level_transform = true);
+
+ Node *_sanitize_preview_node(Node *p_node) const;
+
void _create_preview(const Vector<String> &files) const;
void _remove_preview();
bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node);
@@ -395,7 +408,15 @@ private:
void _project_settings_changed();
- Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local);
+ Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double p_extra, bool p_local, bool p_orthogonal);
+
+ void begin_transform(TransformMode p_mode, bool instant);
+ void commit_transform();
+ void update_transform(Point2 p_mousepos, bool p_shift);
+ void finish_transform();
+
+ void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode);
+ void shortcut_changed_callback(const Ref<Shortcut> p_shortcut, const String &p_shortcut_path);
protected:
void _notification(int p_what);
@@ -421,7 +442,7 @@ public:
SubViewport *get_viewport_node() { return viewport; }
Camera3D *get_camera_3d() { return camera; } // return the default camera object.
- Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index);
+ Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p_index);
~Node3DEditorViewport();
};
@@ -434,7 +455,7 @@ public:
Transform3D original_local;
Transform3D last_xform; // last transform
bool last_xform_dirty;
- Node3D *sp;
+ Node3D *sp = nullptr;
RID sbox_instance;
RID sbox_instance_offset;
RID sbox_instance_xray;
@@ -516,13 +537,13 @@ public:
};
private:
- EditorNode *editor;
- EditorSelection *editor_selection;
+ EditorSelection *editor_selection = nullptr;
- Node3DEditorViewportContainer *viewport_base;
+ Node3DEditorViewportContainer *viewport_base = nullptr;
Node3DEditorViewport *viewports[VIEWPORTS_COUNT];
- VSplitContainer *shader_split;
- HSplitContainer *palette_split;
+ VSplitContainer *shader_split = nullptr;
+ HSplitContainer *left_panel_split = nullptr;
+ HSplitContainer *right_panel_split = nullptr;
/////
@@ -530,17 +551,17 @@ private:
RID origin;
RID origin_instance;
- bool origin_enabled;
+ bool origin_enabled = false;
RID grid[3];
RID grid_instance[3];
bool grid_visible[3]; //currently visible
bool grid_enable[3]; //should be always visible if true
- bool grid_enabled;
+ bool grid_enabled = false;
bool grid_init_draw = false;
Camera3D::Projection grid_camera_last_update_perspective = Camera3D::PROJECTION_PERSPECTIVE;
Vector3 grid_camera_last_update_position = Vector3();
- Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3];
+ Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3], axis_gizmo[3];
Ref<StandardMaterial3D> gizmo_color[3];
Ref<StandardMaterial3D> plane_gizmo_color[3];
Ref<ShaderMaterial> rotate_gizmo_color[3];
@@ -550,6 +571,7 @@ private:
Ref<Node3DGizmo> current_hover_gizmo;
int current_hover_gizmo_handle;
+ bool current_hover_gizmo_handle_secondary;
real_t snap_translate_value;
real_t snap_rotate_value;
@@ -566,7 +588,7 @@ private:
Ref<StandardMaterial3D> cursor_material;
// Scene drag and drop support
- Node3D *preview_node;
+ Node3D *preview_node = nullptr;
AABB preview_bounds;
struct Gizmo {
@@ -606,31 +628,31 @@ private:
Button *tool_button[TOOL_MAX];
Button *tool_option_button[TOOL_OPT_MAX];
- MenuButton *transform_menu;
- PopupMenu *gizmos_menu;
- MenuButton *view_menu;
+ MenuButton *transform_menu = nullptr;
+ PopupMenu *gizmos_menu = nullptr;
+ MenuButton *view_menu = nullptr;
- AcceptDialog *accept;
+ AcceptDialog *accept = nullptr;
- ConfirmationDialog *snap_dialog;
- ConfirmationDialog *xform_dialog;
- ConfirmationDialog *settings_dialog;
+ ConfirmationDialog *snap_dialog = nullptr;
+ ConfirmationDialog *xform_dialog = nullptr;
+ ConfirmationDialog *settings_dialog = nullptr;
bool snap_enabled;
bool snap_key_enabled;
- LineEdit *snap_translate;
- LineEdit *snap_rotate;
- LineEdit *snap_scale;
+ LineEdit *snap_translate = nullptr;
+ LineEdit *snap_rotate = nullptr;
+ LineEdit *snap_scale = nullptr;
LineEdit *xform_translate[3];
LineEdit *xform_rotate[3];
LineEdit *xform_scale[3];
- OptionButton *xform_type;
+ OptionButton *xform_type = nullptr;
- VBoxContainer *settings_vbc;
- SpinBox *settings_fov;
- SpinBox *settings_znear;
- SpinBox *settings_zfar;
+ VBoxContainer *settings_vbc = nullptr;
+ SpinBox *settings_fov = nullptr;
+ SpinBox *settings_znear = nullptr;
+ SpinBox *settings_zfar = nullptr;
void _snap_changed();
void _snap_update();
@@ -640,14 +662,14 @@ private:
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;
+ HBoxContainer *hbc_menu = nullptr;
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
- PanelContainer *context_menu_container;
- HBoxContainer *hbc_context_menu;
+ PanelContainer *context_menu_container = nullptr;
+ HBoxContainer *hbc_context_menu = nullptr;
void _generate_selection_boxes();
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
int camera_override_viewport_id;
@@ -661,13 +683,13 @@ private:
void _toggle_maximize_view(Object *p_viewport);
- Node *custom_camera;
+ Node *custom_camera = nullptr;
Object *_get_editor_data(Object *p_what);
Ref<Environment> viewport_environment;
- Node3D *selected;
+ Node3D *selected = nullptr;
void _request_gizmo(Object *p_obj);
void _set_subgizmo_selection(Object *p_obj, Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D());
@@ -690,18 +712,18 @@ private:
uint32_t world_env_count = 0;
uint32_t directional_light_count = 0;
- Button *sun_button;
- Label *sun_state;
- Label *sun_title;
- VBoxContainer *sun_vb;
- Popup *sun_environ_popup;
- Control *sun_direction;
- EditorSpinSlider *sun_angle_altitude;
- EditorSpinSlider *sun_angle_azimuth;
- ColorPickerButton *sun_color;
- EditorSpinSlider *sun_energy;
- EditorSpinSlider *sun_max_distance;
- Button *sun_add_to_scene;
+ Button *sun_button = nullptr;
+ Label *sun_state = nullptr;
+ Label *sun_title = nullptr;
+ VBoxContainer *sun_vb = nullptr;
+ Popup *sun_environ_popup = nullptr;
+ Control *sun_direction = nullptr;
+ EditorSpinSlider *sun_angle_altitude = nullptr;
+ EditorSpinSlider *sun_angle_azimuth = nullptr;
+ ColorPickerButton *sun_color = nullptr;
+ EditorSpinSlider *sun_energy = nullptr;
+ EditorSpinSlider *sun_max_distance = nullptr;
+ Button *sun_add_to_scene = nullptr;
void _sun_direction_draw();
void _sun_direction_input(const Ref<InputEvent> &p_event);
@@ -712,23 +734,23 @@ private:
Ref<Shader> sun_direction_shader;
Ref<ShaderMaterial> sun_direction_material;
- Button *environ_button;
- Label *environ_state;
- Label *environ_title;
- VBoxContainer *environ_vb;
- ColorPickerButton *environ_sky_color;
- ColorPickerButton *environ_ground_color;
- EditorSpinSlider *environ_energy;
- Button *environ_ao_button;
- Button *environ_glow_button;
- Button *environ_tonemap_button;
- Button *environ_gi_button;
- Button *environ_add_to_scene;
-
- Button *sun_environ_settings;
-
- DirectionalLight3D *preview_sun;
- WorldEnvironment *preview_environment;
+ Button *environ_button = nullptr;
+ Label *environ_state = nullptr;
+ Label *environ_title = nullptr;
+ VBoxContainer *environ_vb = nullptr;
+ ColorPickerButton *environ_sky_color = nullptr;
+ ColorPickerButton *environ_ground_color = nullptr;
+ EditorSpinSlider *environ_energy = nullptr;
+ Button *environ_ao_button = nullptr;
+ Button *environ_glow_button = nullptr;
+ Button *environ_tonemap_button = nullptr;
+ Button *environ_gi_button = nullptr;
+ Button *environ_add_to_scene = nullptr;
+
+ Button *sun_environ_settings = nullptr;
+
+ DirectionalLight3D *preview_sun = nullptr;
+ WorldEnvironment *preview_environment = nullptr;
Ref<Environment> environment;
Ref<ProceduralSkyMaterial> sky_material;
@@ -748,7 +770,7 @@ private:
protected:
void _notification(int p_what);
//void _gui_input(InputEvent p_event);
- virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
static void _bind_methods();
@@ -766,12 +788,14 @@ public:
ToolMode get_tool_mode() const { return tool_mode; }
bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }
+ void set_local_coords_enabled(bool on) const { tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_pressed(on); }
bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
double get_translate_snap() const;
double get_rotate_snap() const;
double get_scale_snap() const;
Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
+ Ref<ArrayMesh> get_axis_gizmo(int idx) const { return axis_gizmo[idx]; }
Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; }
Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
@@ -795,8 +819,16 @@ public:
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
+ void add_control_to_left_panel(Control *p_control);
+ void remove_control_from_left_panel(Control *p_control);
+
+ void add_control_to_right_panel(Control *p_control);
+ void remove_control_from_right_panel(Control *p_control);
+
+ void move_control_to_left_panel(Control *p_control);
+ void move_control_to_right_panel(Control *p_control);
+
VSplitContainer *get_shader_split();
- HSplitContainer *get_palette_split();
Node3D *get_single_selected_node() { return selected; }
bool is_current_selected_gizmo(const EditorNode3DGizmo *p_gizmo);
@@ -806,8 +838,15 @@ public:
Ref<EditorNode3DGizmo> get_current_hover_gizmo() const { return current_hover_gizmo; }
void set_current_hover_gizmo(Ref<EditorNode3DGizmo> p_gizmo) { current_hover_gizmo = p_gizmo; }
- void set_current_hover_gizmo_handle(int p_id) { current_hover_gizmo_handle = p_id; }
- int get_current_hover_gizmo_handle() const { return current_hover_gizmo_handle; }
+ void set_current_hover_gizmo_handle(int p_id, bool p_secondary) {
+ current_hover_gizmo_handle = p_id;
+ current_hover_gizmo_handle_secondary = p_secondary;
+ }
+
+ int get_current_hover_gizmo_handle(bool &r_secondary) const {
+ r_secondary = current_hover_gizmo_handle_secondary;
+ return current_hover_gizmo_handle;
+ }
void set_can_preview(Camera3D *p_preview);
@@ -822,15 +861,14 @@ public:
void edit(Node3D *p_spatial);
void clear();
- Node3DEditor(EditorNode *p_editor);
+ Node3DEditor();
~Node3DEditor();
};
class Node3DEditorPlugin : public EditorPlugin {
GDCLASS(Node3DEditorPlugin, EditorPlugin);
- Node3DEditor *spatial_editor;
- EditorNode *editor;
+ Node3DEditor *spatial_editor = nullptr;
public:
Node3DEditor *get_spatial_editor() { return spatial_editor; }
@@ -846,7 +884,7 @@ public:
virtual void edited_scene_changed() override;
- Node3DEditorPlugin(EditorNode *p_node);
+ Node3DEditorPlugin();
~Node3DEditorPlugin();
};
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
index 0328b1bea6..79cf4c394e 100644
--- a/editor/plugins/occluder_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,22 +30,25 @@
#include "occluder_instance_3d_editor_plugin.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+
void OccluderInstance3DEditorPlugin::_bake_select_file(const String &p_file) {
if (occluder_instance) {
OccluderInstance3D::BakeError err;
if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == occluder_instance) {
- err = occluder_instance->bake(occluder_instance, p_file);
+ err = occluder_instance->bake_scene(occluder_instance, p_file);
} else {
- err = occluder_instance->bake(occluder_instance->get_parent(), p_file);
+ err = occluder_instance->bake_scene(occluder_instance->get_parent(), p_file);
}
switch (err) {
case OccluderInstance3D::BAKE_ERROR_NO_SAVE_PATH: {
String scene_path = occluder_instance->get_scene_file_path();
- if (scene_path == String()) {
+ if (scene_path.is_empty()) {
scene_path = occluder_instance->get_owner()->get_scene_file_path();
}
- if (scene_path == String()) {
+ if (scene_path.is_empty()) {
EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for the occluder.\nSave your scene and try again."));
break;
}
@@ -59,6 +62,10 @@ void OccluderInstance3DEditorPlugin::_bake_select_file(const String &p_file) {
EditorNode::get_singleton()->show_warning(TTR("No meshes to bake.\nMake sure there is at least one MeshInstance3D node in the scene whose visual layers are part of the OccluderInstance3D's Bake Mask property."));
break;
}
+ case OccluderInstance3D::BAKE_ERROR_CANT_SAVE: {
+ EditorNode::get_singleton()->show_warning(TTR("Could not save the new occluder at the specified path: ") + p_file);
+ break;
+ }
default: {
}
}
@@ -94,11 +101,10 @@ void OccluderInstance3DEditorPlugin::_bind_methods() {
ClassDB::bind_method("_bake", &OccluderInstance3DEditorPlugin::_bake);
}
-OccluderInstance3DEditorPlugin::OccluderInstance3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+OccluderInstance3DEditorPlugin::OccluderInstance3DEditorPlugin() {
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(editor->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
+ bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
bake->set_text(TTR("Bake Occluders"));
bake->hide();
bake->connect("pressed", Callable(this, "_bake"));
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.h b/editor/plugins/occluder_instance_3d_editor_plugin.h
index 161b17811c..360b7297cf 100644
--- a/editor/plugins/occluder_instance_3d_editor_plugin.h
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,20 +31,20 @@
#ifndef OCCLUDER_INSTANCE_3D_EDITOR_PLUGIN_H
#define OCCLUDER_INSTANCE_3D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/occluder_instance_3d.h"
#include "scene/resources/material.h"
+class EditorFileDialog;
+
class OccluderInstance3DEditorPlugin : public EditorPlugin {
GDCLASS(OccluderInstance3DEditorPlugin, EditorPlugin);
- OccluderInstance3D *occluder_instance;
+ OccluderInstance3D *occluder_instance = nullptr;
- Button *bake;
- EditorNode *editor;
+ Button *bake = nullptr;
- EditorFileDialog *file_dialog;
+ EditorFileDialog *file_dialog = nullptr;
void _bake_select_file(const String &p_file);
void _bake();
@@ -59,7 +59,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- OccluderInstance3DEditorPlugin(EditorNode *p_node);
+ OccluderInstance3DEditorPlugin();
~OccluderInstance3DEditorPlugin();
};
diff --git a/editor/plugins/ot_features_plugin.cpp b/editor/plugins/ot_features_plugin.cpp
index fd42bce06e..ffa74173be 100644
--- a/editor/plugins/ot_features_plugin.cpp
+++ b/editor/plugins/ot_features_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,7 +30,7 @@
#include "ot_features_plugin.h"
-#include "editor/editor_scale.h"
+#include "scene/3d/label_3d.h"
void OpenTypeFeaturesEditor::_value_changed(double val) {
if (setting) {
@@ -48,12 +48,15 @@ void OpenTypeFeaturesEditor::update_property() {
}
void OpenTypeFeaturesEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Color base = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
-
- button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- button->set_size(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))->get_size());
- spin->set_custom_label_color(true, base);
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ Color base = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+
+ button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ button->set_size(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))->get_size());
+ spin->add_theme_color_override("label_color", base);
+ } break;
}
}
@@ -95,10 +98,19 @@ OpenTypeFeaturesEditor::OpenTypeFeaturesEditor() {
/*************************************************************************/
void OpenTypeFeaturesAdd::_add_feature(int p_option) {
- get_edited_object()->set("opentype_features/" + TS->tag_to_name(p_option), 1);
+ edited_object->set("opentype_features/" + TS->tag_to_name(p_option), 1);
}
-void OpenTypeFeaturesAdd::update_property() {
+void OpenTypeFeaturesAdd::_features_menu() {
+ Size2 size = get_size();
+ menu->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
+ menu->reset_size();
+ menu->popup();
+}
+
+void OpenTypeFeaturesAdd::setup(Object *p_object) {
+ edited_object = p_object;
+
menu->clear();
menu_ss->clear();
menu_cv->clear();
@@ -106,7 +118,25 @@ void OpenTypeFeaturesAdd::update_property() {
bool have_ss = false;
bool have_cv = false;
bool have_cu = false;
- Dictionary features = Object::cast_to<Control>(get_edited_object())->get_theme_font(SNAME("font"))->get_feature_list();
+
+ Ref<Font> font;
+
+ Control *ctrl = Object::cast_to<Control>(edited_object);
+ if (ctrl != nullptr) {
+ font = ctrl->get_theme_font(SNAME("font"));
+ } else {
+ Label3D *l3d = Object::cast_to<Label3D>(edited_object);
+ if (l3d != nullptr) {
+ font = l3d->_get_font_or_default();
+ }
+ }
+
+ if (font.is_null()) {
+ return;
+ }
+
+ Dictionary features = font->get_feature_list();
+
for (const Variant *ftr = features.next(nullptr); ftr != nullptr; ftr = features.next(ftr)) {
String ftr_name = TS->tag_to_name(*ftr);
if (ftr_name.begins_with("stylistic_set_")) {
@@ -133,17 +163,15 @@ void OpenTypeFeaturesAdd::update_property() {
}
}
-void OpenTypeFeaturesAdd::_features_menu() {
- Size2 size = get_size();
- menu->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
- menu->popup();
-}
-
void OpenTypeFeaturesAdd::_notification(int p_what) {
- if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
- set_label("");
- button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
- button->set_size(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))->get_size());
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ connect("pressed", callable_mp(this, &OpenTypeFeaturesAdd::_features_menu));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ } break;
}
}
@@ -151,6 +179,8 @@ void OpenTypeFeaturesAdd::_bind_methods() {
}
OpenTypeFeaturesAdd::OpenTypeFeaturesAdd() {
+ set_text(TTR("Add Feature..."));
+
menu = memnew(PopupMenu);
add_child(menu);
@@ -166,13 +196,6 @@ OpenTypeFeaturesAdd::OpenTypeFeaturesAdd() {
menu_cu->set_name("CUMenu");
menu->add_child(menu_cu);
- button = memnew(Button);
- button->set_flat(true);
- button->set_text(RTR("Add feature..."));
- button->set_tooltip(RTR("Add feature..."));
- add_child(button);
-
- button->connect("pressed", callable_mp(this, &OpenTypeFeaturesAdd::_features_menu));
menu->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature));
menu_cv->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature));
menu_ss->connect("id_pressed", callable_mp(this, &OpenTypeFeaturesAdd::_add_feature));
@@ -182,19 +205,14 @@ OpenTypeFeaturesAdd::OpenTypeFeaturesAdd() {
/*************************************************************************/
bool EditorInspectorPluginOpenTypeFeatures::can_handle(Object *p_object) {
- return (Object::cast_to<Control>(p_object) != nullptr);
-}
-
-void EditorInspectorPluginOpenTypeFeatures::parse_begin(Object *p_object) {
-}
-
-void EditorInspectorPluginOpenTypeFeatures::parse_category(Object *p_object, const String &p_parse_category) {
+ return (Object::cast_to<Control>(p_object) != nullptr) || (Object::cast_to<Label3D>(p_object) != nullptr);
}
bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
if (p_path == "opentype_features/_new") {
OpenTypeFeaturesAdd *editor = memnew(OpenTypeFeaturesAdd);
- add_property_editor(p_path, editor);
+ editor->setup(p_object);
+ add_custom_control(editor);
return true;
} else if (p_path.begins_with("opentype_features")) {
OpenTypeFeaturesEditor *editor = memnew(OpenTypeFeaturesEditor);
@@ -206,7 +224,7 @@ bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, con
/*************************************************************************/
-OpenTypeFeaturesEditorPlugin::OpenTypeFeaturesEditorPlugin(EditorNode *p_node) {
+OpenTypeFeaturesEditorPlugin::OpenTypeFeaturesEditorPlugin() {
Ref<EditorInspectorPluginOpenTypeFeatures> ftr_plugin;
ftr_plugin.instantiate();
EditorInspector::add_inspector_plugin(ftr_plugin);
diff --git a/editor/plugins/ot_features_plugin.h b/editor/plugins/ot_features_plugin.h
index dbafa3bbf6..6639148080 100644
--- a/editor/plugins/ot_features_plugin.h
+++ b/editor/plugins/ot_features_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef OT_FEATURES_PLUGIN_H
#define OT_FEATURES_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
@@ -39,7 +38,7 @@
class OpenTypeFeaturesEditor : public EditorProperty {
GDCLASS(OpenTypeFeaturesEditor, EditorProperty);
- EditorSpinSlider *spin;
+ EditorSpinSlider *spin = nullptr;
bool setting = true;
void _value_changed(double p_val);
Button *button = nullptr;
@@ -57,10 +56,10 @@ public:
/*************************************************************************/
-class OpenTypeFeaturesAdd : public EditorProperty {
- GDCLASS(OpenTypeFeaturesAdd, EditorProperty);
+class OpenTypeFeaturesAdd : public Button {
+ GDCLASS(OpenTypeFeaturesAdd, Button);
- Button *button = nullptr;
+ Object *edited_object = nullptr;
PopupMenu *menu = nullptr;
PopupMenu *menu_ss = nullptr;
PopupMenu *menu_cv = nullptr;
@@ -74,7 +73,7 @@ protected:
static void _bind_methods();
public:
- virtual void update_property() override;
+ void setup(Object *p_object);
OpenTypeFeaturesAdd();
};
@@ -86,8 +85,6 @@ class EditorInspectorPluginOpenTypeFeatures : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual void parse_begin(Object *p_object) override;
- virtual void parse_category(Object *p_object, const String &p_parse_category) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
};
@@ -97,7 +94,7 @@ class OpenTypeFeaturesEditorPlugin : public EditorPlugin {
GDCLASS(OpenTypeFeaturesEditorPlugin, EditorPlugin);
public:
- OpenTypeFeaturesEditorPlugin(EditorNode *p_node);
+ OpenTypeFeaturesEditorPlugin();
virtual String get_name() const override { return "OpenTypeFeatures"; }
};
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp
index 53c5b8dd70..8d083d28b2 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.cpp
+++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -43,7 +43,7 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
// These properties are translated with the tr() function in the C++ code when being set or updated.
Error err;
- RES loaded_res = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
+ Ref<Resource> loaded_res = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
if (err) {
ERR_PRINT("Failed to load " + p_path);
return err;
@@ -132,10 +132,7 @@ PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlug
lookup_properties.insert("script");
// Exception list (to prevent false positives).
- exception_list.insert("LineEdit", Vector<StringName>());
- exception_list["LineEdit"].append("text");
- exception_list.insert("TextEdit", Vector<StringName>());
- exception_list["TextEdit"].append("text");
- exception_list.insert("CodeEdit", Vector<StringName>());
- exception_list["CodeEdit"].append("text");
+ exception_list.insert("LineEdit", { "text" });
+ exception_list.insert("TextEdit", { "text" });
+ exception_list.insert("CodeEdit", { "text" });
}
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.h b/editor/plugins/packed_scene_translation_parser_plugin.h
index af0291b69c..ecd090b31b 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.h
+++ b/editor/plugins/packed_scene_translation_parser_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,9 +37,9 @@ class PackedSceneEditorTranslationParserPlugin : public EditorTranslationParserP
GDCLASS(PackedSceneEditorTranslationParserPlugin, EditorTranslationParserPlugin);
// Scene Node's properties that contain translation strings.
- Set<StringName> lookup_properties;
+ Set<String> lookup_properties;
// Properties from specific Nodes that should be ignored.
- Map<StringName, Vector<StringName>> exception_list;
+ Map<String, Vector<String>> exception_list;
public:
virtual Error parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) override;
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 119ecddf63..9e666ef70a 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,19 +33,19 @@
#include "canvas_item_editor_plugin.h"
#include "core/io/file_access.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
void Path2DEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- //button_create->set_icon( get_icon("Edit","EditorIcons"));
- //button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
- //set_pressed_button(button_edit);
- //button_edit->set_pressed(true);
-
- } break;
- case NOTIFICATION_PHYSICS_PROCESS: {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ curve_edit->set_icon(get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
+ curve_edit_curve->set_icon(get_theme_icon(SNAME("CurveCurve"), SNAME("EditorIcons")));
+ curve_create->set_icon(get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
+ curve_del->set_icon(get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
+ curve_close->set_icon(get_theme_icon(SNAME("CurveClose"), SNAME("EditorIcons")));
} break;
}
}
@@ -88,7 +88,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
real_t dist_to_p_in = gpoint.distance_to(xform.xform(curve->get_point_position(i) + curve->get_point_in(i)));
// Check for point movement start (for point + in/out controls).
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mode == MODE_EDIT && !mb->is_shift_pressed() && dist_to_p < grab_threshold) {
// Points can only be moved in edit mode.
@@ -118,7 +118,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point deletion.
- if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && mode == MODE_DELETE)) {
+ if ((mb->get_button_index() == MouseButton::RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) {
if (dist_to_p < grab_threshold) {
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(curve.ptr(), "remove_point", i);
@@ -149,7 +149,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point creation.
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && ((mb->is_command_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
undo_redo->create_action(TTR("Add Point to Curve"));
@@ -170,7 +170,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for segment split.
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mode == MODE_EDIT && on_edge) {
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && mode == MODE_EDIT && on_edge) {
Vector2 gpoint2 = mb->get_position();
Ref<Curve2D> curve = node->get_curve();
@@ -207,7 +207,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point movement completion.
- if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && action != ACTION_NONE) {
+ if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && action != ACTION_NONE) {
Ref<Curve2D> curve = node->get_curve();
Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
@@ -516,10 +516,9 @@ void Path2DEditor::_handle_option_pressed(int p_option) {
}
}
-Path2DEditor::Path2DEditor(EditorNode *p_editor) {
+Path2DEditor::Path2DEditor() {
canvas_item_editor = nullptr;
- editor = p_editor;
- undo_redo = editor->get_undo_redo();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
mirror_handle_angle = true;
mirror_handle_length = true;
on_edge = false;
@@ -532,41 +531,41 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) {
sep = memnew(VSeparator);
base_hb->add_child(sep);
+
curve_edit = memnew(Button);
curve_edit->set_flat(true);
- curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
curve_edit->set_toggle_mode(true);
curve_edit->set_focus_mode(Control::FOCUS_NONE);
- curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
+ curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
curve_edit->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT));
base_hb->add_child(curve_edit);
+
curve_edit_curve = memnew(Button);
curve_edit_curve->set_flat(true);
- curve_edit_curve->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveCurve"), SNAME("EditorIcons")));
curve_edit_curve->set_toggle_mode(true);
curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
curve_edit_curve->set_tooltip(TTR("Select Control Points (Shift+Drag)"));
curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT_CURVE));
base_hb->add_child(curve_edit_curve);
+
curve_create = memnew(Button);
curve_create->set_flat(true);
- curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
curve_create->set_toggle_mode(true);
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip(TTR("Add Point (in empty space)"));
curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_CREATE));
base_hb->add_child(curve_create);
+
curve_del = memnew(Button);
curve_del->set_flat(true);
- curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
curve_del->set_toggle_mode(true);
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip(TTR("Delete Point"));
curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_DELETE));
base_hb->add_child(curve_del);
+
curve_close = memnew(Button);
curve_close->set_flat(true);
- curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveClose"), SNAME("EditorIcons")));
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip(TTR("Close Curve"));
curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(ACTION_CLOSE));
@@ -610,9 +609,8 @@ void Path2DEditorPlugin::make_visible(bool p_visible) {
}
}
-Path2DEditorPlugin::Path2DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- path2d_editor = memnew(Path2DEditor(p_node));
+Path2DEditorPlugin::Path2DEditorPlugin() {
+ path2d_editor = memnew(Path2DEditor);
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(path2d_editor);
path2d_editor->hide();
}
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index 867e0ce74f..720f5c090f 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,24 +31,23 @@
#ifndef PATH_2D_EDITOR_PLUGIN_H
#define PATH_2D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/path_2d.h"
+#include "scene/gui/separator.h"
class CanvasItemEditor;
class Path2DEditor : public HBoxContainer {
GDCLASS(Path2DEditor, HBoxContainer);
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
- CanvasItemEditor *canvas_item_editor;
- EditorNode *editor;
- Panel *panel;
- Path2D *node;
+ CanvasItemEditor *canvas_item_editor = nullptr;
+ Panel *panel = nullptr;
+ Path2D *node = nullptr;
- HBoxContainer *base_hb;
- Separator *sep;
+ HBoxContainer *base_hb = nullptr;
+ Separator *sep = nullptr;
enum Mode {
MODE_CREATE,
@@ -59,12 +58,12 @@ class Path2DEditor : public HBoxContainer {
};
Mode mode;
- Button *curve_create;
- Button *curve_edit;
- Button *curve_edit_curve;
- Button *curve_del;
- Button *curve_close;
- MenuButton *handle_menu;
+ Button *curve_create = nullptr;
+ Button *curve_edit = nullptr;
+ Button *curve_edit_curve = nullptr;
+ Button *curve_del = nullptr;
+ Button *curve_close = nullptr;
+ MenuButton *handle_menu = nullptr;
bool mirror_handle_angle;
bool mirror_handle_length;
@@ -83,11 +82,11 @@ class Path2DEditor : public HBoxContainer {
};
Action action;
- int action_point;
+ int action_point = 0;
Point2 moving_from;
Point2 moving_screen_from;
- float orig_in_length;
- float orig_out_length;
+ float orig_in_length = 0.0f;
+ float orig_out_length = 0.0f;
Vector2 edge_point;
void _mode_selected(int p_mode);
@@ -105,14 +104,13 @@ public:
bool forward_gui_input(const Ref<InputEvent> &p_event);
void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(Node *p_path2d);
- Path2DEditor(EditorNode *p_editor);
+ Path2DEditor();
};
class Path2DEditorPlugin : public EditorPlugin {
GDCLASS(Path2DEditorPlugin, EditorPlugin);
- Path2DEditor *path2d_editor;
- EditorNode *editor;
+ Path2DEditor *path2d_editor = nullptr;
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return path2d_editor->forward_gui_input(p_event); }
@@ -124,7 +122,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- Path2DEditorPlugin(EditorNode *p_node);
+ Path2DEditorPlugin();
~Path2DEditorPlugin();
};
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index f9a5f429d2..3851738cfa 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,20 +33,21 @@
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "node_3d_editor_plugin.h"
#include "scene/resources/curve.h"
-String Path3DGizmo::get_handle_name(int p_id) const {
+String Path3DGizmo::get_handle_name(int p_id, bool p_secondary) const {
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return "";
}
- if (p_id < c->get_point_count()) {
+ if (!p_secondary) {
return TTR("Curve Point #") + itos(p_id);
}
- p_id = p_id - c->get_point_count() + 1;
+ p_id += 1; // Account for the first point only having an "out" handle
int idx = p_id / 2;
int t = p_id % 2;
@@ -60,18 +61,18 @@ String Path3DGizmo::get_handle_name(int p_id) const {
return n;
}
-Variant Path3DGizmo::get_handle_value(int p_id) const {
+Variant Path3DGizmo::get_handle_value(int p_id, bool p_secondary) const {
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return Variant();
}
- if (p_id < c->get_point_count()) {
+ if (!p_secondary) {
original = c->get_point_position(p_id);
return original;
}
- p_id = p_id - c->get_point_count() + 1;
+ p_id += 1; // Account for the first point only having an "out" handle
int idx = p_id / 2;
int t = p_id % 2;
@@ -88,7 +89,7 @@ Variant Path3DGizmo::get_handle_value(int p_id) const {
return ofs;
}
-void Path3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) {
+void Path3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return;
@@ -100,8 +101,8 @@ void Path3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
// Setting curve point positions
- if (p_id < c->get_point_count()) {
- const Plane p = Plane(p_camera->get_transform().basis.get_axis(2), gt.xform(original));
+ if (!p_secondary) {
+ const Plane p = Plane(p_camera->get_transform().basis.get_column(2), gt.xform(original));
Vector3 inters;
@@ -118,14 +119,14 @@ void Path3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point
return;
}
- p_id = p_id - c->get_point_count() + 1;
+ p_id += 1; // Account for the first point only having an "out" handle
int idx = p_id / 2;
int t = p_id % 2;
Vector3 base = c->get_point_position(idx);
- Plane p(p_camera->get_transform().basis.get_axis(2), gt.xform(original));
+ Plane p(p_camera->get_transform().basis.get_column(2), gt.xform(original));
Vector3 inters;
@@ -157,7 +158,7 @@ void Path3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point
}
}
-void Path3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cancel) {
+void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return;
@@ -165,7 +166,7 @@ void Path3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cance
UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
- if (p_id < c->get_point_count()) {
+ if (!p_secondary) {
if (p_cancel) {
c->set_point_position(p_id, p_restore);
return;
@@ -178,7 +179,7 @@ void Path3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cance
return;
}
- p_id = p_id - c->get_point_count() + 1;
+ p_id += 1; // Account for the first point only having an "out" handle
int idx = p_id / 2;
int t = p_id % 2;
@@ -316,17 +317,17 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
set_handle_clicked(false);
}
- if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->is_ctrl_pressed()))) {
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->is_ctrl_pressed()))) {
//click into curve, break it down
Vector<Vector3> v3a = c->tessellate();
- int idx = 0;
int rc = v3a.size();
int closest_seg = -1;
Vector3 closest_seg_point;
- float closest_d = 1e20;
if (rc >= 2) {
+ int idx = 0;
const Vector3 *r = v3a.ptr();
+ float closest_d = 1e20;
if (p_camera->unproject_position(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist) {
return EditorPlugin::AFTER_GUI_INPUT_PASS; //nope, existing
@@ -378,7 +379,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
}
}
- UndoRedo *ur = editor->get_undo_redo();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
if (closest_seg != -1) {
//subdivide
@@ -395,7 +396,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
} else {
origin = gt.xform(c->get_point_position(c->get_point_count() - 1));
}
- Plane p(p_camera->get_transform().basis.get_axis(2), origin);
+ Plane p(p_camera->get_transform().basis.get_column(2), origin);
Vector3 ray_from = p_camera->project_ray_origin(mbpos);
Vector3 ray_dir = p_camera->project_ray_normal(mbpos);
@@ -411,7 +412,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
//add new at pos
}
- } else if (mb->is_pressed() && ((mb->get_button_index() == MOUSE_BUTTON_LEFT && curve_del->is_pressed()) || (mb->get_button_index() == MOUSE_BUTTON_RIGHT && curve_edit->is_pressed()))) {
+ } else if (mb->is_pressed() && ((mb->get_button_index() == MouseButton::LEFT && curve_del->is_pressed()) || (mb->get_button_index() == MouseButton::RIGHT && curve_edit->is_pressed()))) {
for (int i = 0; i < c->get_point_count(); i++) {
real_t dist_to_p = p_camera->unproject_position(gt.xform(c->get_point_position(i))).distance_to(mbpos);
real_t dist_to_p_out = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos);
@@ -420,21 +421,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
// Find the offset and point index of the place to break up.
// Also check for the control points.
if (dist_to_p < click_dist) {
- UndoRedo *ur = editor->get_undo_redo();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Remove Path Point"));
ur->add_do_method(c.ptr(), "remove_point", i);
ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i);
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_out < click_dist) {
- UndoRedo *ur = editor->get_undo_redo();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Remove Out-Control Point"));
ur->add_do_method(c.ptr(), "set_point_out", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i));
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_in < click_dist) {
- UndoRedo *ur = editor->get_undo_redo();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Remove In-Control Point"));
ur->add_do_method(c.ptr(), "set_point_in", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i));
@@ -513,7 +514,7 @@ void Path3DEditorPlugin::_close_curve() {
if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) {
return;
}
- UndoRedo *ur = editor->get_undo_redo();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Close Curve"));
ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1);
ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
@@ -539,12 +540,29 @@ void Path3DEditorPlugin::_handle_option_pressed(int p_option) {
}
}
+void Path3DEditorPlugin::_update_theme() {
+ // TODO: Split the EditorPlugin instance from the UI instance and connect this properly.
+ // See the 2D path editor for inspiration.
+ curve_edit->set_icon(Node3DEditor::get_singleton()->get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
+ curve_create->set_icon(Node3DEditor::get_singleton()->get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
+ curve_del->set_icon(Node3DEditor::get_singleton()->get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
+ curve_close->set_icon(Node3DEditor::get_singleton()->get_theme_icon(SNAME("CurveClose"), SNAME("EditorIcons")));
+}
+
void Path3DEditorPlugin::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- curve_create->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(0));
- curve_edit->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(1));
- curve_del->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(2));
- curve_close->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_close_curve));
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ curve_create->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(0));
+ curve_edit->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(1));
+ curve_del->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(2));
+ curve_close->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_close_curve));
+
+ _update_theme();
+ } break;
+
+ case NOTIFICATION_READY: {
+ Node3DEditor::get_singleton()->connect("theme_changed", callable_mp(this, &Path3DEditorPlugin::_update_theme));
+ } break;
}
}
@@ -553,9 +571,8 @@ void Path3DEditorPlugin::_bind_methods() {
Path3DEditorPlugin *Path3DEditorPlugin::singleton = nullptr;
-Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) {
+Path3DEditorPlugin::Path3DEditorPlugin() {
path = nullptr;
- editor = p_node;
singleton = this;
mirror_handle_angle = true;
mirror_handle_length = true;
@@ -567,33 +584,33 @@ Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) {
sep = memnew(VSeparator);
sep->hide();
Node3DEditor::get_singleton()->add_control_to_menu_panel(sep);
+
curve_edit = memnew(Button);
curve_edit->set_flat(true);
- curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
curve_edit->set_toggle_mode(true);
curve_edit->hide();
curve_edit->set_focus_mode(Control::FOCUS_NONE);
- curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
+ curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
+
curve_create = memnew(Button);
curve_create->set_flat(true);
- curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
curve_create->set_toggle_mode(true);
curve_create->hide();
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_create);
+
curve_del = memnew(Button);
curve_del->set_flat(true);
- curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
curve_del->set_toggle_mode(true);
curve_del->hide();
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip(TTR("Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del);
+
curve_close = memnew(Button);
curve_close->set_flat(true);
- curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveClose"), SNAME("EditorIcons")));
curve_close->hide();
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip(TTR("Close Curve"));
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 974234ba8f..ee31fcf43d 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -35,20 +35,21 @@
#include "editor/plugins/node_3d_editor_gizmos.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/path_3d.h"
+#include "scene/gui/separator.h"
class Path3DGizmo : public EditorNode3DGizmo {
GDCLASS(Path3DGizmo, EditorNode3DGizmo);
- Path3D *path;
+ Path3D *path = nullptr;
mutable Vector3 original;
mutable float orig_in_length;
mutable float orig_out_length;
public:
- virtual String get_handle_name(int p_idx) const override;
- virtual Variant get_handle_value(int p_id) const override;
- virtual void set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) override;
- virtual void commit_handle(int p_id, const Variant &p_restore, bool p_cancel = false) override;
+ virtual String get_handle_name(int p_id, bool p_secondary) const override;
+ virtual Variant get_handle_value(int p_id, bool p_secondary) const override;
+ virtual void set_handle(int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
+ virtual void commit_handle(int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
virtual void redraw() override;
Path3DGizmo(Path3D *p_path = nullptr);
@@ -69,21 +70,21 @@ public:
class Path3DEditorPlugin : public EditorPlugin {
GDCLASS(Path3DEditorPlugin, EditorPlugin);
- Separator *sep;
- Button *curve_create;
- Button *curve_edit;
- Button *curve_del;
- Button *curve_close;
- MenuButton *handle_menu;
+ Separator *sep = nullptr;
+ Button *curve_create = nullptr;
+ Button *curve_edit = nullptr;
+ Button *curve_del = nullptr;
+ Button *curve_close = nullptr;
+ MenuButton *handle_menu = nullptr;
- EditorNode *editor;
+ Path3D *path = nullptr;
- Path3D *path;
+ void _update_theme();
void _mode_changed(int p_idx);
void _close_curve();
void _handle_option_pressed(int p_option);
- bool handle_clicked;
+ bool handle_clicked = false;
bool mirror_handle_angle;
bool mirror_handle_length;
@@ -113,7 +114,7 @@ public:
bool is_handle_clicked() { return handle_clicked; }
void set_handle_clicked(bool clicked) { handle_clicked = clicked; }
- Path3DEditorPlugin(EditorNode *p_node);
+ Path3DEditorPlugin();
~Path3DEditorPlugin();
};
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp
index b1e104e680..9dc89133c4 100644
--- a/editor/plugins/physical_bone_3d_editor_plugin.cpp
+++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#include "physical_bone_3d_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
-#include "scene/3d/physics_body_3d.h"
void PhysicalBone3DEditor::_bind_methods() {
}
@@ -47,11 +46,10 @@ void PhysicalBone3DEditor::_set_move_joint() {
}
}
-PhysicalBone3DEditor::PhysicalBone3DEditor(EditorNode *p_editor) :
- editor(p_editor) {
+PhysicalBone3DEditor::PhysicalBone3DEditor() {
spatial_editor_hb = memnew(HBoxContainer);
spatial_editor_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- spatial_editor_hb->set_alignment(BoxContainer::ALIGN_BEGIN);
+ spatial_editor_hb->set_alignment(BoxContainer::ALIGNMENT_BEGIN);
Node3DEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
spatial_editor_hb->add_child(memnew(VSeparator));
@@ -84,9 +82,7 @@ void PhysicalBone3DEditor::show() {
spatial_editor_hb->show();
}
-PhysicalBone3DEditorPlugin::PhysicalBone3DEditorPlugin(EditorNode *p_editor) :
- editor(p_editor),
- physical_bone_editor(editor) {}
+PhysicalBone3DEditorPlugin::PhysicalBone3DEditorPlugin() {}
void PhysicalBone3DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.h b/editor/plugins/physical_bone_3d_editor_plugin.h
index 248aad9298..93e722a432 100644
--- a/editor/plugins/physical_bone_3d_editor_plugin.h
+++ b/editor/plugins/physical_bone_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,14 +31,16 @@
#ifndef PHYSICAL_BONE_PLUGIN_H
#define PHYSICAL_BONE_PLUGIN_H
-#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/3d/physics_body_3d.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
class PhysicalBone3DEditor : public Object {
GDCLASS(PhysicalBone3DEditor, Object);
- EditorNode *editor;
- HBoxContainer *spatial_editor_hb;
- Button *button_transform_joint;
+ HBoxContainer *spatial_editor_hb = nullptr;
+ Button *button_transform_joint = nullptr;
PhysicalBone3D *selected = nullptr;
@@ -50,7 +52,7 @@ private:
void _set_move_joint();
public:
- PhysicalBone3DEditor(EditorNode *p_editor);
+ PhysicalBone3DEditor();
~PhysicalBone3DEditor() {}
void set_selected(PhysicalBone3D *p_pb);
@@ -62,7 +64,6 @@ public:
class PhysicalBone3DEditorPlugin : public EditorPlugin {
GDCLASS(PhysicalBone3DEditorPlugin, EditorPlugin);
- EditorNode *editor;
PhysicalBone3D *selected = nullptr;
PhysicalBone3DEditor physical_bone_editor;
@@ -72,7 +73,7 @@ public:
virtual void make_visible(bool p_visible) override;
virtual void edit(Object *p_node) override;
- PhysicalBone3DEditorPlugin(EditorNode *p_editor);
+ PhysicalBone3DEditorPlugin();
};
#endif
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 5afe9ed60c..a682bb455c 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,14 +30,17 @@
#include "polygon_2d_editor_plugin.h"
-#include "canvas_item_editor_plugin.h"
-#include "core/input/input.h"
-#include "core/io/file_access.h"
+#include "core/input/input_event.h"
#include "core/math/geometry_2d.h"
-#include "core/os/keyboard.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/skeleton_2d.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/slider.h"
+#include "scene/gui/view_panner.h"
Node2D *Polygon2DEditor::_get_node() const {
return node;
@@ -63,10 +66,10 @@ int Polygon2DEditor::_get_polygon_count() const {
void Polygon2DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED: {
- uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- bone_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ uv_panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
} break;
+
case NOTIFICATION_READY: {
button_uv->set_icon(get_theme_icon(SNAME("Uv"), SNAME("EditorIcons")));
@@ -88,7 +91,13 @@ void Polygon2DEditor::_notification(int p_what) {
uv_vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
uv_hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ bone_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
} break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) {
uv_edit->hide();
@@ -170,7 +179,7 @@ void Polygon2DEditor::_update_bone_list() {
if (np.get_name_count()) {
name = np.get_name(np.get_name_count() - 1);
}
- if (name == String()) {
+ if (name.is_empty()) {
name = "Bone " + itos(i);
}
cb->set_text(name);
@@ -440,14 +449,19 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
return;
}
+ if (uv_panner->gui_input(p_input)) {
+ accept_event();
+ return;
+ }
+
Transform2D mtx;
- mtx.elements[2] = -uv_draw_ofs;
+ mtx.columns[2] = -uv_draw_ofs;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
uv_drag_from = snap_point(mb->get_position());
uv_drag = true;
@@ -462,7 +476,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_move_current = uv_mode;
if (uv_move_current == UV_MODE_CREATE) {
if (!uv_create) {
- points_prev.resize(0);
+ points_prev.clear();
Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position()));
points_prev.push_back(tuv);
uv_create_to = tuv;
@@ -584,10 +598,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
return;
}
- uv_create_poly_prev.remove(closest);
- uv_create_uv_prev.remove(closest);
+ uv_create_poly_prev.remove_at(closest);
+ uv_create_uv_prev.remove_at(closest);
if (uv_create_colors_prev.size()) {
- uv_create_colors_prev.remove(closest);
+ uv_create_colors_prev.remove_at(closest);
}
undo_redo->create_action(TTR("Remove Internal Vertex"));
@@ -599,7 +613,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "set_vertex_colors", node->get_vertex_colors());
for (int i = 0; i < node->get_bone_count(); i++) {
Vector<float> bonew = node->get_bone_weights(i);
- bonew.remove(closest);
+ bonew.remove_at(closest);
undo_redo->add_do_method(node, "set_bone_weights", i, bonew);
undo_redo->add_undo_method(node, "set_bone_weights", i, node->get_bone_weights(i));
}
@@ -671,7 +685,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
polygon_create.clear();
- } else if (polygon_create.find(closest) == -1) {
+ } else if (!polygon_create.has(closest)) {
//add temporarily if not exists
polygon_create.push_back(closest);
}
@@ -702,7 +716,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
if (erase_index != -1) {
- polygons.remove(erase_index);
+ polygons.remove_at(erase_index);
undo_redo->create_action(TTR("Remove Custom Polygon"));
undo_redo->add_do_method(node, "set_polygons", polygons);
undo_redo->add_undo_method(node, "set_polygons", node->get_polygons());
@@ -759,7 +773,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
bone_painting = false;
}
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
_cancel_editing();
if (bone_painting) {
@@ -767,23 +781,13 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
uv_edit_draw->update();
-
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
- uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * mb->get_factor())));
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
- uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * mb->get_factor())));
}
}
Ref<InputEventMouseMotion> mm = p_input;
if (mm.is_valid()) {
- if ((mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
- Vector2 drag = mm->get_relative();
- uv_hscroll->set_value(uv_hscroll->get_value() - drag.x);
- uv_vscroll->set_value(uv_vscroll->get_value() - drag.y);
-
- } else if (uv_drag) {
+ if (uv_drag) {
Vector2 uv_drag_to = mm->get_position();
uv_drag_to = snap_point(uv_drag_to); // FIXME: Only works correctly with 'UV_MODE_EDIT_POINT', it's imprecise with the rest.
Vector2 drag = mtx.affine_inverse().xform(uv_drag_to) - mtx.affine_inverse().xform(uv_drag_from);
@@ -925,6 +929,23 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
}
+void Polygon2DEditor::_uv_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
+ _uv_pan_callback(-p_scroll_vec * 32);
+}
+
+void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec) {
+ uv_hscroll->set_value(uv_hscroll->get_value() - p_scroll_vec.x);
+ uv_vscroll->set_value(uv_vscroll->get_value() - p_scroll_vec.y);
+}
+
+void Polygon2DEditor::_uv_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
+ if (p_scroll_vec.y < 0) {
+ uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * Math::abs(p_scroll_vec.y))));
+ } else {
+ uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * Math::abs(p_scroll_vec.y))));
+ }
+}
+
void Polygon2DEditor::_uv_scroll_changed(real_t) {
if (updating_uv_scroll) {
return;
@@ -949,7 +970,7 @@ void Polygon2DEditor::_uv_draw() {
String warning;
Transform2D mtx;
- mtx.elements[2] = -uv_draw_ofs;
+ mtx.columns[2] = -uv_draw_ofs;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx);
@@ -1041,7 +1062,7 @@ void Polygon2DEditor::_uv_draw() {
for (int i = 0; i < uvs.size(); i++) {
int next = uv_draw_max > 0 ? (i + 1) % uv_draw_max : 0;
- if (i < uv_draw_max && uv_drag && uv_move_current == UV_MODE_EDIT_POINT && EDITOR_DEF("editors/polygon_editor/show_previous_outline", true)) {
+ if (i < uv_draw_max && uv_drag && uv_move_current == UV_MODE_EDIT_POINT && EDITOR_GET("editors/polygon_editor/show_previous_outline")) {
uv_edit_draw->draw_line(mtx.xform(points_prev[i]), mtx.xform(points_prev[next]), prev_color, Math::round(EDSCALE));
}
@@ -1049,7 +1070,7 @@ void Polygon2DEditor::_uv_draw() {
if (uv_create && i == uvs.size() - 1) {
next_point = uv_create_to;
}
- if (i < uv_draw_max /*&& polygons.size() == 0 && polygon_create.size() == 0*/) { //if using or creating polygons, do not show outline (will show polygons instead)
+ if (i < uv_draw_max) { // If using or creating polygons, do not show outline (will show polygons instead).
uv_edit_draw->draw_line(mtx.xform(uvs[i]), mtx.xform(next_point), poly_line_color, Math::round(EDSCALE));
}
}
@@ -1207,9 +1228,7 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
return p_target;
}
-Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
- AbstractPolygon2DEditor(p_editor) {
- node = nullptr;
+Polygon2DEditor::Polygon2DEditor() {
snap_offset = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_offset", Vector2());
snap_step = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_step", Vector2(10, 10));
use_snap = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_enabled", false);
@@ -1448,8 +1467,13 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
bone_scroll_vb = memnew(VBoxContainer);
bone_scroll->add_child(bone_scroll_vb);
+ uv_panner.instantiate();
+ uv_panner->set_callbacks(callable_mp(this, &Polygon2DEditor::_uv_scroll_callback), callable_mp(this, &Polygon2DEditor::_uv_pan_callback), callable_mp(this, &Polygon2DEditor::_uv_zoom_callback));
+
uv_edit_draw->connect("draw", callable_mp(this, &Polygon2DEditor::_uv_draw));
uv_edit_draw->connect("gui_input", callable_mp(this, &Polygon2DEditor::_uv_input));
+ uv_edit_draw->connect("focus_exited", callable_mp(uv_panner.ptr(), &ViewPanner::release_pan_key));
+ uv_edit_draw->set_focus_mode(FOCUS_CLICK);
uv_draw_zoom = 1.0;
point_drag_index = -1;
uv_drag = false;
@@ -1463,6 +1487,6 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
uv_edit_draw->set_clip_contents(true);
}
-Polygon2DEditorPlugin::Polygon2DEditorPlugin(EditorNode *p_node) :
- AbstractPolygon2DEditorPlugin(p_node, memnew(Polygon2DEditor(p_node)), "Polygon2D") {
+Polygon2DEditorPlugin::Polygon2DEditorPlugin() :
+ AbstractPolygon2DEditorPlugin(memnew(Polygon2DEditor), "Polygon2D") {
}
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index cbe7ecf360..d878d3f9af 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,7 +32,12 @@
#define POLYGON_2D_EDITOR_PLUGIN_H
#include "editor/plugins/abstract_polygon_2d_editor.h"
-#include "scene/gui/scroll_container.h"
+
+class HSlider;
+class Panel;
+class ScrollContainer;
+class SpinBox;
+class ViewPanner;
class Polygon2DEditor : public AbstractPolygon2DEditor {
GDCLASS(Polygon2DEditor, AbstractPolygon2DEditor);
@@ -63,33 +68,38 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
Button *uv_edit_mode[4];
Ref<ButtonGroup> uv_edit_group;
- Polygon2D *node;
+ Polygon2D *node = nullptr;
UVMode uv_mode;
- AcceptDialog *uv_edit;
+ AcceptDialog *uv_edit = nullptr;
Button *uv_button[UV_MODE_MAX];
- Button *b_snap_enable;
- Button *b_snap_grid;
- Panel *uv_edit_draw;
- HSlider *uv_zoom;
- SpinBox *uv_zoom_value;
- HScrollBar *uv_hscroll;
- VScrollBar *uv_vscroll;
- MenuButton *uv_menu;
- TextureRect *uv_icon_zoom;
-
- VBoxContainer *bone_scroll_main_vb;
- ScrollContainer *bone_scroll;
- VBoxContainer *bone_scroll_vb;
- Button *sync_bones;
- HSlider *bone_paint_strength;
- SpinBox *bone_paint_radius;
- Label *bone_paint_radius_label;
+ Button *b_snap_enable = nullptr;
+ Button *b_snap_grid = nullptr;
+ Panel *uv_edit_draw = nullptr;
+ HSlider *uv_zoom = nullptr;
+ SpinBox *uv_zoom_value = nullptr;
+ HScrollBar *uv_hscroll = nullptr;
+ VScrollBar *uv_vscroll = nullptr;
+ MenuButton *uv_menu = nullptr;
+ TextureRect *uv_icon_zoom = nullptr;
+
+ Ref<ViewPanner> uv_panner;
+ void _uv_scroll_callback(Vector2 p_scroll_vec, bool p_alt);
+ void _uv_pan_callback(Vector2 p_scroll_vec);
+ void _uv_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+
+ VBoxContainer *bone_scroll_main_vb = nullptr;
+ ScrollContainer *bone_scroll = nullptr;
+ VBoxContainer *bone_scroll_vb = nullptr;
+ Button *sync_bones = nullptr;
+ HSlider *bone_paint_strength = nullptr;
+ SpinBox *bone_paint_radius = nullptr;
+ Label *bone_paint_radius_label = nullptr;
bool bone_painting;
- int bone_painting_bone;
+ int bone_painting_bone = 0;
Vector<float> prev_weights;
Vector2 bone_paint_pos;
- AcceptDialog *grid_settings;
+ AcceptDialog *grid_settings = nullptr;
void _sync_bones();
void _update_bone_list();
@@ -100,7 +110,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
Vector<Vector2> uv_create_uv_prev;
Vector<Vector2> uv_create_poly_prev;
Vector<Color> uv_create_colors_prev;
- int uv_create_prev_internal_vertices;
+ int uv_create_prev_internal_vertices = 0;
Array uv_create_bones_prev;
Array polygons_prev;
@@ -113,9 +123,9 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
Vector2 uv_drag_from;
bool updating_uv_scroll;
- AcceptDialog *error;
+ AcceptDialog *error = nullptr;
- Button *button_uv;
+ Button *button_uv = nullptr;
bool use_snap;
bool snap_show_grid;
@@ -160,14 +170,14 @@ protected:
Vector2 snap_point(Vector2 p_target) const;
public:
- Polygon2DEditor(EditorNode *p_editor);
+ Polygon2DEditor();
};
class Polygon2DEditorPlugin : public AbstractPolygon2DEditorPlugin {
GDCLASS(Polygon2DEditorPlugin, AbstractPolygon2DEditorPlugin);
public:
- Polygon2DEditorPlugin(EditorNode *p_node);
+ Polygon2DEditorPlugin();
};
#endif // POLYGON_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 53314db1e9..1c69e0d635 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_polygon_3d_editor_plugin.cpp */
+/* polygon_3d_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,26 +28,29 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "collision_polygon_3d_editor_plugin.h"
+#include "polygon_3d_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
+#include "core/core_string_names.h"
#include "core/input/input.h"
#include "core/io/file_access.h"
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
-void CollisionPolygon3DEditor::_notification(int p_what) {
+void Polygon3DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
button_create->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
button_edit->set_icon(get_theme_icon(SNAME("MovePoint"), SNAME("EditorIcons")));
button_edit->set_pressed(true);
- get_tree()->connect("node_removed", callable_mp(this, &CollisionPolygon3DEditor::_node_removed));
+ get_tree()->connect("node_removed", callable_mp(this, &Polygon3DEditor::_node_removed));
} break;
+
case NOTIFICATION_PROCESS: {
if (!node) {
return;
@@ -62,7 +65,7 @@ void CollisionPolygon3DEditor::_notification(int p_what) {
}
}
-void CollisionPolygon3DEditor::_node_removed(Node *p_node) {
+void Polygon3DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
node = nullptr;
if (imgeom->get_parent() == p_node) {
@@ -73,7 +76,7 @@ void CollisionPolygon3DEditor::_node_removed(Node *p_node) {
}
}
-void CollisionPolygon3DEditor::_menu_option(int p_option) {
+void Polygon3DEditor::_menu_option(int p_option) {
switch (p_option) {
case MODE_CREATE: {
mode = MODE_CREATE;
@@ -88,10 +91,12 @@ void CollisionPolygon3DEditor::_menu_option(int p_option) {
}
}
-void CollisionPolygon3DEditor::_wip_close() {
+void Polygon3DEditor::_wip_close() {
+ Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
+ ERR_FAIL_COND_MSG(!obj, "Edited object is not valid.");
undo_redo->create_action(TTR("Create Polygon3D"));
- undo_redo->add_undo_method(node, "set_polygon", node->call("get_polygon"));
- undo_redo->add_do_method(node, "set_polygon", wip);
+ undo_redo->add_undo_method(obj, "set_polygon", obj->call("get_polygon"));
+ undo_redo->add_do_method(obj, "set_polygon", wip);
undo_redo->add_do_method(this, "_polygon_draw");
undo_redo->add_undo_method(this, "_polygon_draw");
wip.clear();
@@ -103,15 +108,16 @@ void CollisionPolygon3DEditor::_wip_close() {
undo_redo->commit_action();
}
-EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+EditorPlugin::AfterGUIInput Polygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!node) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
+ Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
Transform3D gt = node->get_global_transform();
Transform3D gi = gt.affine_inverse();
float depth = _get_depth() * 0.5;
- Vector3 n = gt.basis.get_axis(2).normalized();
+ Vector3 n = gt.basis.get_column(2).normalized();
Plane p(n, gt.origin + n * depth);
Ref<InputEventMouseButton> mb = p_event;
@@ -135,14 +141,14 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
//Let the snap happen when the point is being moved, instead.
//cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint);
- Vector<Vector2> poly = node->call("get_polygon");
+ PackedVector2Array poly = _get_polygon();
//first check if a point is to be added (segment split)
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
switch (mode) {
case MODE_CREATE: {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
if (!wip_active) {
wip.clear();
wip.push_back(cpoint);
@@ -166,21 +172,21 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && wip_active) {
_wip_close();
}
} break;
case MODE_EDIT: {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (mb->is_ctrl_pressed()) {
if (poly.size() < 3) {
undo_redo->create_action(TTR("Edit Poly"));
- undo_redo->add_undo_method(node, "set_polygon", poly);
+ undo_redo->add_undo_method(obj, "set_polygon", poly);
poly.push_back(cpoint);
- undo_redo->add_do_method(node, "set_polygon", poly);
+ undo_redo->add_do_method(obj, "set_polygon", poly);
undo_redo->add_do_method(this, "_polygon_draw");
undo_redo->add_undo_method(this, "_polygon_draw");
undo_redo->commit_action();
@@ -215,7 +221,7 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
poly.insert(closest_idx + 1, cpoint);
edited_point = closest_idx + 1;
edited_point_pos = cpoint;
- node->call("set_polygon", poly);
+ _set_polygon(poly);
_polygon_draw();
snap_ignore = true;
@@ -256,8 +262,8 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
ERR_FAIL_INDEX_V(edited_point, poly.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
poly.write[edited_point] = edited_point_pos;
undo_redo->create_action(TTR("Edit Poly"));
- undo_redo->add_do_method(node, "set_polygon", poly);
- undo_redo->add_undo_method(node, "set_polygon", pre_move_edit);
+ undo_redo->add_do_method(obj, "set_polygon", poly);
+ undo_redo->add_undo_method(obj, "set_polygon", pre_move_edit);
undo_redo->add_do_method(this, "_polygon_draw");
undo_redo->add_undo_method(this, "_polygon_draw");
undo_redo->commit_action();
@@ -267,7 +273,7 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
}
}
}
- if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
+ if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && edited_point == -1) {
int closest_idx = -1;
Vector2 closest_pos;
real_t closest_dist = 1e10;
@@ -284,9 +290,9 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
if (closest_idx >= 0) {
undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
- undo_redo->add_undo_method(node, "set_polygon", poly);
- poly.remove(closest_idx);
- undo_redo->add_do_method(node, "set_polygon", poly);
+ undo_redo->add_undo_method(obj, "set_polygon", poly);
+ poly.remove_at(closest_idx);
+ undo_redo->add_do_method(obj, "set_polygon", poly);
undo_redo->add_do_method(this, "_polygon_draw");
undo_redo->add_undo_method(this, "_polygon_draw");
undo_redo->commit_action();
@@ -301,7 +307,7 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- if (edited_point != -1 && (wip_active || mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) {
+ if (edited_point != -1 && (wip_active || (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE)) {
Vector2 gpoint = mm->get_position();
Vector3 ray_from = p_camera->project_ray_origin(gpoint);
@@ -317,7 +323,7 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
Vector2 cpoint(spoint.x, spoint.y);
- if (snap_ignore && !Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ if (snap_ignore && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
snap_ignore = false;
}
@@ -335,29 +341,45 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
-float CollisionPolygon3DEditor::_get_depth() {
- if (bool(node->call("_has_editable_3d_polygon_no_depth"))) {
- return 0;
+float Polygon3DEditor::_get_depth() {
+ Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
+ ERR_FAIL_COND_V_MSG(!obj, 0.0f, "Edited object is not valid.");
+
+ if (bool(obj->call("_has_editable_3d_polygon_no_depth"))) {
+ return 0.0f;
}
- return float(node->call("get_depth"));
+ return float(obj->call("get_depth"));
}
-void CollisionPolygon3DEditor::_polygon_draw() {
+PackedVector2Array Polygon3DEditor::_get_polygon() {
+ Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
+ ERR_FAIL_COND_V_MSG(!obj, PackedVector2Array(), "Edited object is not valid.");
+ return PackedVector2Array(obj->call("get_polygon"));
+}
+
+void Polygon3DEditor::_set_polygon(PackedVector2Array p_poly) {
+ Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
+ ERR_FAIL_COND_MSG(!obj, "Edited object is not valid.");
+ obj->call("set_polygon", p_poly);
+}
+
+void Polygon3DEditor::_polygon_draw() {
if (!node) {
return;
}
- Vector<Vector2> poly;
+ PackedVector2Array poly;
if (wip_active) {
poly = wip;
} else {
- poly = node->call("get_polygon");
+ poly = _get_polygon();
}
float depth = _get_depth() * 0.5;
+ m->clear_surfaces();
imesh->clear_surfaces();
imgeom->set_material_override(line_material);
imesh->surface_begin(Mesh::PRIMITIVE_LINES);
@@ -463,23 +485,32 @@ void CollisionPolygon3DEditor::_polygon_draw() {
m->surface_set_material(0, handle_material);
}
-void CollisionPolygon3DEditor::edit(Node *p_collision_polygon) {
- if (p_collision_polygon) {
- node = Object::cast_to<Node3D>(p_collision_polygon);
+void Polygon3DEditor::edit(Node *p_node) {
+ if (p_node) {
+ node = Object::cast_to<Node3D>(p_node);
+ node_resource = node->call("_get_editable_3d_polygon_resource");
+
+ if (node_resource.is_valid()) {
+ node_resource->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Polygon3DEditor::_polygon_draw));
+ }
//Enable the pencil tool if the polygon is empty
- if (Vector<Vector2>(node->call("get_polygon")).size() == 0) {
+ if (_get_polygon().is_empty()) {
_menu_option(MODE_CREATE);
}
wip.clear();
wip_active = false;
edited_point = -1;
- p_collision_polygon->add_child(imgeom);
+ p_node->add_child(imgeom);
_polygon_draw();
set_process(true);
prev_depth = -1;
} else {
node = nullptr;
+ if (node_resource.is_valid()) {
+ node_resource->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Polygon3DEditor::_polygon_draw));
+ }
+ node_resource.unref();
if (imgeom->get_parent()) {
imgeom->get_parent()->remove_child(imgeom);
@@ -489,26 +520,25 @@ void CollisionPolygon3DEditor::edit(Node *p_collision_polygon) {
}
}
-void CollisionPolygon3DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_polygon_draw"), &CollisionPolygon3DEditor::_polygon_draw);
+void Polygon3DEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_polygon_draw"), &Polygon3DEditor::_polygon_draw);
}
-CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
+Polygon3DEditor::Polygon3DEditor() {
node = nullptr;
- editor = p_editor;
undo_redo = EditorNode::get_undo_redo();
add_child(memnew(VSeparator));
button_create = memnew(Button);
button_create->set_flat(true);
add_child(button_create);
- button_create->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_CREATE));
+ button_create->connect("pressed", callable_mp(this, &Polygon3DEditor::_menu_option), varray(MODE_CREATE));
button_create->set_toggle_mode(true);
button_edit = memnew(Button);
button_edit->set_flat(true);
add_child(button_edit);
- button_edit->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_EDIT));
+ button_edit->connect("pressed", callable_mp(this, &Polygon3DEditor::_menu_option), varray(MODE_EDIT));
button_edit->set_toggle_mode(true);
mode = MODE_EDIT;
@@ -531,7 +561,7 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- Ref<Texture2D> handle = editor->get_gui_base()->get_theme_icon(SNAME("Editor3DHandle"), SNAME("EditorIcons"));
+ Ref<Texture2D> handle = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Editor3DHandle"), SNAME("EditorIcons"));
handle_material->set_point_size(handle->get_width());
handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle);
@@ -544,12 +574,12 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) {
snap_ignore = false;
}
-CollisionPolygon3DEditor::~CollisionPolygon3DEditor() {
+Polygon3DEditor::~Polygon3DEditor() {
memdelete(imgeom);
}
void Polygon3DEditorPlugin::edit(Object *p_object) {
- collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
+ polygon_editor->edit(Object::cast_to<Node>(p_object));
}
bool Polygon3DEditorPlugin::handles(Object *p_object) const {
@@ -558,19 +588,18 @@ bool Polygon3DEditorPlugin::handles(Object *p_object) const {
void Polygon3DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- collision_polygon_editor->show();
+ polygon_editor->show();
} else {
- collision_polygon_editor->hide();
- collision_polygon_editor->edit(nullptr);
+ polygon_editor->hide();
+ polygon_editor->edit(nullptr);
}
}
-Polygon3DEditorPlugin::Polygon3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- collision_polygon_editor = memnew(CollisionPolygon3DEditor(p_node));
- Node3DEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
+Polygon3DEditorPlugin::Polygon3DEditorPlugin() {
+ polygon_editor = memnew(Polygon3DEditor);
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(polygon_editor);
- collision_polygon_editor->hide();
+ polygon_editor->hide();
}
Polygon3DEditorPlugin::~Polygon3DEditorPlugin() {
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h
index 10b0adf76c..e1e1261250 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.h
+++ b/editor/plugins/polygon_3d_editor_plugin.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* collision_polygon_3d_editor_plugin.h */
+/* polygon_3d_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -28,10 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COLLISION_POLYGON_EDITOR_PLUGIN_H
-#define COLLISION_POLYGON_EDITOR_PLUGIN_H
+#ifndef POLYGON_3D_EDITOR_PLUGIN_H
+#define POLYGON_3D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/collision_polygon_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -39,10 +38,10 @@
class CanvasItemEditor;
-class CollisionPolygon3DEditor : public HBoxContainer {
- GDCLASS(CollisionPolygon3DEditor, HBoxContainer);
+class Polygon3DEditor : public HBoxContainer {
+ GDCLASS(Polygon3DEditor, HBoxContainer);
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
enum Mode {
MODE_CREATE,
MODE_EDIT,
@@ -51,36 +50,38 @@ class CollisionPolygon3DEditor : public HBoxContainer {
Mode mode;
- Button *button_create;
- Button *button_edit;
+ Button *button_create = nullptr;
+ Button *button_edit = nullptr;
Ref<StandardMaterial3D> line_material;
Ref<StandardMaterial3D> handle_material;
- EditorNode *editor;
- Panel *panel;
- Node3D *node;
+ Panel *panel = nullptr;
+ Node3D *node = nullptr;
+ Ref<Resource> node_resource;
Ref<ImmediateMesh> imesh;
- MeshInstance3D *imgeom;
- MeshInstance3D *pointsm;
+ MeshInstance3D *imgeom = nullptr;
+ MeshInstance3D *pointsm = nullptr;
Ref<ArrayMesh> m;
- MenuButton *options;
+ MenuButton *options = nullptr;
- int edited_point;
+ int edited_point = 0;
Vector2 edited_point_pos;
- Vector<Vector2> pre_move_edit;
- Vector<Vector2> wip;
+ PackedVector2Array pre_move_edit;
+ PackedVector2Array wip;
bool wip_active;
bool snap_ignore;
- float prev_depth;
+ float prev_depth = 0.0f;
void _wip_close();
void _polygon_draw();
void _menu_option(int p_option);
float _get_depth();
+ PackedVector2Array _get_polygon();
+ void _set_polygon(PackedVector2Array p_poly);
protected:
void _notification(int p_what);
@@ -89,19 +90,18 @@ protected:
public:
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
- void edit(Node *p_collision_polygon);
- CollisionPolygon3DEditor(EditorNode *p_editor);
- ~CollisionPolygon3DEditor();
+ void edit(Node *p_node);
+ Polygon3DEditor();
+ ~Polygon3DEditor();
};
class Polygon3DEditorPlugin : public EditorPlugin {
GDCLASS(Polygon3DEditorPlugin, EditorPlugin);
- CollisionPolygon3DEditor *collision_polygon_editor;
- EditorNode *editor;
+ Polygon3DEditor *polygon_editor = nullptr;
public:
- virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
+ virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
virtual String get_name() const override { return "Polygon3DEditor"; }
bool has_main_screen() const override { return false; }
@@ -109,8 +109,8 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- Polygon3DEditorPlugin(EditorNode *p_node);
+ Polygon3DEditorPlugin();
~Polygon3DEditorPlugin();
};
-#endif // COLLISION_POLYGON_EDITOR_PLUGIN_H
+#endif // POLYGON_3D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/ray_cast_2d_editor_plugin.cpp b/editor/plugins/ray_cast_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..6f247a37ef
--- /dev/null
+++ b/editor/plugins/ray_cast_2d_editor_plugin.cpp
@@ -0,0 +1,151 @@
+/*************************************************************************/
+/* ray_cast_2d_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "ray_cast_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "editor/editor_node.h"
+
+void RayCast2DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ get_tree()->connect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed));
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed));
+ } break;
+ }
+}
+
+void RayCast2DEditor::_node_removed(Node *p_node) {
+ if (p_node == node) {
+ node = nullptr;
+ }
+}
+
+bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ if (!node || !node->is_visible_in_tree()) {
+ return false;
+ }
+
+ Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ if (xform.xform(node->get_target_position()).distance_to(mb->get_position()) < 8) {
+ pressed = true;
+ original_target_position = node->get_target_position();
+
+ return true;
+ } else {
+ pressed = false;
+
+ return false;
+ }
+ } else if (pressed) {
+ undo_redo->create_action(TTR("Set target_position"));
+ undo_redo->add_do_method(node, "set_target_position", node->get_target_position());
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(node, "set_target_position", original_target_position);
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
+ undo_redo->commit_action();
+
+ pressed = false;
+
+ return true;
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && pressed) {
+ Vector2 point = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position()));
+ point = node->get_global_transform().affine_inverse().xform(point);
+
+ node->set_target_position(point);
+ canvas_item_editor->update_viewport();
+ node->notify_property_list_changed();
+
+ return true;
+ }
+
+ return false;
+}
+
+void RayCast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
+ if (!node || !node->is_visible_in_tree()) {
+ return;
+ }
+
+ Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
+
+ const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
+ p_overlay->draw_texture(handle, gt.xform(node->get_target_position()) - handle->get_size() / 2);
+}
+
+void RayCast2DEditor::edit(Node *p_node) {
+ if (!canvas_item_editor) {
+ canvas_item_editor = CanvasItemEditor::get_singleton();
+ }
+
+ if (p_node) {
+ node = Object::cast_to<RayCast2D>(p_node);
+ } else {
+ node = nullptr;
+ }
+
+ canvas_item_editor->update_viewport();
+}
+
+RayCast2DEditor::RayCast2DEditor() {
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+}
+
+///////////////////////
+
+void RayCast2DEditorPlugin::edit(Object *p_object) {
+ ray_cast_2d_editor->edit(Object::cast_to<RayCast2D>(p_object));
+}
+
+bool RayCast2DEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<RayCast2D>(p_object) != nullptr;
+}
+
+void RayCast2DEditorPlugin::make_visible(bool p_visible) {
+ if (!p_visible) {
+ edit(nullptr);
+ }
+}
+
+RayCast2DEditorPlugin::RayCast2DEditorPlugin() {
+ ray_cast_2d_editor = memnew(RayCast2DEditor);
+ EditorNode::get_singleton()->get_gui_base()->add_child(ray_cast_2d_editor);
+}
diff --git a/editor/plugins/ray_cast_2d_editor_plugin.h b/editor/plugins/ray_cast_2d_editor_plugin.h
new file mode 100644
index 0000000000..74628da0e4
--- /dev/null
+++ b/editor/plugins/ray_cast_2d_editor_plugin.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* ray_cast_2d_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 RAY_CAST_2D_EDITOR_PLUGIN_H
+#define RAY_CAST_2D_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "scene/2d/ray_cast_2d.h"
+
+class CanvasItemEditor;
+
+class RayCast2DEditor : public Control {
+ GDCLASS(RayCast2DEditor, Control);
+
+ UndoRedo *undo_redo = nullptr;
+ CanvasItemEditor *canvas_item_editor = nullptr;
+ RayCast2D *node;
+
+ bool pressed = false;
+ Point2 original_target_position;
+
+protected:
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+
+public:
+ bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
+ void forward_canvas_draw_over_viewport(Control *p_overlay);
+ void edit(Node *p_node);
+
+ RayCast2DEditor();
+};
+
+class RayCast2DEditorPlugin : public EditorPlugin {
+ GDCLASS(RayCast2DEditorPlugin, EditorPlugin);
+
+ RayCast2DEditor *ray_cast_2d_editor = nullptr;
+
+public:
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return ray_cast_2d_editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { ray_cast_2d_editor->forward_canvas_draw_over_viewport(p_overlay); }
+
+ virtual String get_name() const override { return "RayCast2D"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool visible) override;
+
+ RayCast2DEditorPlugin();
+};
+
+#endif // RAY_CAST_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/replication_editor_plugin.cpp b/editor/plugins/replication_editor_plugin.cpp
new file mode 100644
index 0000000000..2a7b3c7a55
--- /dev/null
+++ b/editor/plugins/replication_editor_plugin.cpp
@@ -0,0 +1,396 @@
+/*************************************************************************/
+/* replication_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "replication_editor_plugin.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/inspector_dock.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/tree.h"
+#include "scene/multiplayer/multiplayer_synchronizer.h"
+
+/// ReplicationEditor
+ReplicationEditor::ReplicationEditor() {
+ set_v_size_flags(SIZE_EXPAND_FILL);
+ set_custom_minimum_size(Size2(0, 200) * EDSCALE);
+
+ delete_dialog = memnew(ConfirmationDialog);
+ delete_dialog->connect("cancelled", callable_mp(this, &ReplicationEditor::_dialog_closed), varray(false));
+ delete_dialog->connect("confirmed", callable_mp(this, &ReplicationEditor::_dialog_closed), varray(true));
+ add_child(delete_dialog);
+
+ error_dialog = memnew(AcceptDialog);
+ error_dialog->get_ok_button()->set_text(TTR("Close"));
+ error_dialog->set_title(TTR("Error!"));
+ add_child(error_dialog);
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(vb);
+
+ HBoxContainer *hb = memnew(HBoxContainer);
+ vb->add_child(hb);
+ np_line_edit = memnew(LineEdit);
+ np_line_edit->set_placeholder(":property");
+ np_line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ hb->add_child(np_line_edit);
+ add_button = memnew(Button);
+ add_button->connect("pressed", callable_mp(this, &ReplicationEditor::_add_pressed));
+ add_button->set_text(TTR("Add"));
+ hb->add_child(add_button);
+
+ tree = memnew(Tree);
+ tree->set_hide_root(true);
+ tree->set_columns(4);
+ tree->set_column_titles_visible(true);
+ tree->set_column_title(0, TTR("Properties"));
+ tree->set_column_expand(0, true);
+ tree->set_column_title(1, TTR("Spawn"));
+ tree->set_column_expand(1, false);
+ tree->set_column_custom_minimum_width(1, 100);
+ tree->set_column_title(2, TTR("Sync"));
+ tree->set_column_custom_minimum_width(2, 100);
+ tree->set_column_expand(2, false);
+ tree->set_column_expand(3, false);
+ tree->create_item();
+ tree->connect("button_pressed", callable_mp(this, &ReplicationEditor::_tree_button_pressed));
+ tree->connect("item_edited", callable_mp(this, &ReplicationEditor::_tree_item_edited));
+ tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ vb->add_child(tree);
+}
+
+void ReplicationEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_config"), &ReplicationEditor::_update_config);
+ ClassDB::bind_method(D_METHOD("_update_checked", "property", "column", "checked"), &ReplicationEditor::_update_checked);
+ ADD_SIGNAL(MethodInfo("keying_changed"));
+}
+
+void ReplicationEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ update_keying();
+ } break;
+ }
+}
+
+void ReplicationEditor::_add_pressed() {
+ if (!current) {
+ error_dialog->set_text(TTR("Please select a MultiplayerSynchronizer first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ if (current->get_root_path().is_empty()) {
+ error_dialog->set_text(TTR("The MultiplayerSynchronizer needs a root path."));
+ error_dialog->popup_centered();
+ return;
+ }
+ String np_text = np_line_edit->get_text();
+ if (np_text.find(":") == -1) {
+ np_text = ":" + np_text;
+ }
+ NodePath prop = NodePath(np_text);
+ if (prop.is_empty()) {
+ return;
+ }
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(TTR("Add property"));
+ config = current->get_replication_config();
+ if (config.is_null()) {
+ config.instantiate();
+ current->set_replication_config(config);
+ undo_redo->add_do_method(current, "set_replication_config", config);
+ undo_redo->add_undo_method(current, "set_replication_config", Ref<SceneReplicationConfig>());
+ _update_config();
+ }
+ undo_redo->add_do_method(config.ptr(), "add_property", prop);
+ undo_redo->add_undo_method(config.ptr(), "remove_property", prop);
+ undo_redo->add_do_method(this, "_update_config");
+ undo_redo->add_undo_method(this, "_update_config");
+ undo_redo->commit_action();
+}
+
+void ReplicationEditor::_tree_item_edited() {
+ TreeItem *ti = tree->get_edited();
+ if (!ti || config.is_null()) {
+ return;
+ }
+ int column = tree->get_edited_column();
+ ERR_FAIL_COND(column < 1 || column > 2);
+ const NodePath prop = ti->get_metadata(0);
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ bool value = ti->is_checked(column);
+ String method;
+ if (column == 1) {
+ undo_redo->create_action(TTR("Set spawn property"));
+ method = "property_set_spawn";
+ } else {
+ undo_redo->create_action(TTR("Set sync property"));
+ method = "property_set_sync";
+ }
+ undo_redo->add_do_method(config.ptr(), method, prop, value);
+ undo_redo->add_undo_method(config.ptr(), method, prop, !value);
+ undo_redo->add_do_method(this, "_update_checked", prop, column, value);
+ undo_redo->add_undo_method(this, "_update_checked", prop, column, !value);
+ undo_redo->commit_action();
+}
+
+void ReplicationEditor::_tree_button_pressed(Object *p_item, int p_column, int p_id) {
+ TreeItem *ti = Object::cast_to<TreeItem>(p_item);
+ if (!ti) {
+ return;
+ }
+ deleting = ti->get_metadata(0);
+ delete_dialog->set_text(TTR("Delete Property?") + "\n\"" + ti->get_text(0) + "\"");
+ delete_dialog->popup_centered();
+}
+
+void ReplicationEditor::_dialog_closed(bool p_confirmed) {
+ if (deleting.is_empty() || config.is_null()) {
+ return;
+ }
+ if (p_confirmed) {
+ const NodePath prop = deleting;
+ int idx = config->property_get_index(prop);
+ bool spawn = config->property_get_spawn(prop);
+ bool sync = config->property_get_sync(prop);
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(TTR("Remove Property"));
+ undo_redo->add_do_method(config.ptr(), "remove_property", prop);
+ undo_redo->add_undo_method(config.ptr(), "add_property", prop, idx);
+ undo_redo->add_undo_method(config.ptr(), "property_set_spawn", prop, spawn);
+ undo_redo->add_undo_method(config.ptr(), "property_set_sync", prop, sync);
+ undo_redo->add_do_method(this, "_update_config");
+ undo_redo->add_undo_method(this, "_update_config");
+ undo_redo->commit_action();
+ }
+ deleting = NodePath();
+}
+
+void ReplicationEditor::_update_checked(const NodePath &p_prop, int p_column, bool p_checked) {
+ if (!tree->get_root()) {
+ return;
+ }
+ TreeItem *ti = tree->get_root()->get_first_child();
+ while (ti) {
+ if (ti->get_metadata(0).operator NodePath() == p_prop) {
+ ti->set_checked(p_column, p_checked);
+ return;
+ }
+ ti = ti->get_next();
+ }
+}
+
+void ReplicationEditor::update_keying() {
+ /// TODO make keying usable.
+#if 0
+ bool keying_enabled = false;
+ EditorSelectionHistory *editor_history = EditorNode::get_singleton()->get_editor_selection_history();
+ if (is_visible_in_tree() && config.is_valid() && editor_history->get_path_size() > 0) {
+ Object *obj = ObjectDB::get_instance(editor_history->get_path_object(0));
+ keying_enabled = Object::cast_to<Node>(obj) != nullptr;
+ }
+
+ if (keying_enabled == keying) {
+ return;
+ }
+
+ keying = keying_enabled;
+ emit_signal(SNAME("keying_changed"));
+#endif
+}
+
+void ReplicationEditor::_update_config() {
+ deleting = NodePath();
+ tree->clear();
+ tree->create_item();
+ if (!config.is_valid()) {
+ update_keying();
+ return;
+ }
+ TypedArray<NodePath> props = config->get_properties();
+ for (int i = 0; i < props.size(); i++) {
+ const NodePath path = props[i];
+ _add_property(path, config->property_get_spawn(path), config->property_get_sync(path));
+ }
+ update_keying();
+}
+
+void ReplicationEditor::edit(MultiplayerSynchronizer *p_sync) {
+ if (current == p_sync) {
+ return;
+ }
+ current = p_sync;
+ if (current) {
+ config = current->get_replication_config();
+ } else {
+ config.unref();
+ }
+ _update_config();
+}
+
+Ref<Texture2D> ReplicationEditor::_get_class_icon(const Node *p_node) {
+ if (!p_node || !has_theme_icon(p_node->get_class(), "EditorIcons")) {
+ return get_theme_icon(SNAME("ImportFail"), SNAME("EditorIcons"));
+ }
+ return get_theme_icon(p_node->get_class(), "EditorIcons");
+}
+
+void ReplicationEditor::_add_property(const NodePath &p_property, bool p_spawn, bool p_sync) {
+ String prop = String(p_property);
+ TreeItem *item = tree->create_item();
+ item->set_selectable(0, false);
+ item->set_selectable(1, false);
+ item->set_selectable(2, false);
+ item->set_selectable(3, false);
+ item->set_text(0, prop);
+ item->set_metadata(0, prop);
+ Node *root_node = current && !current->get_root_path().is_empty() ? current->get_node(current->get_root_path()) : nullptr;
+ Ref<Texture2D> icon = _get_class_icon(root_node);
+ if (root_node) {
+ String path = prop.substr(0, prop.find(":"));
+ String subpath = prop.substr(path.size());
+ Node *node = root_node->get_node_or_null(path);
+ if (!node) {
+ node = root_node;
+ }
+ item->set_text(0, String(node->get_name()) + ":" + subpath);
+ icon = _get_class_icon(node);
+ }
+ item->set_icon(0, icon);
+ item->add_button(3, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ item->set_text_alignment(1, HORIZONTAL_ALIGNMENT_CENTER);
+ item->set_cell_mode(1, TreeItem::CELL_MODE_CHECK);
+ item->set_checked(1, p_spawn);
+ item->set_editable(1, true);
+ item->set_text_alignment(2, HORIZONTAL_ALIGNMENT_CENTER);
+ item->set_cell_mode(2, TreeItem::CELL_MODE_CHECK);
+ item->set_checked(2, p_sync);
+ item->set_editable(2, true);
+}
+
+void ReplicationEditor::property_keyed(const String &p_property) {
+ ERR_FAIL_COND(!current || config.is_null());
+ Node *root = current->get_node(current->get_root_path());
+ ERR_FAIL_COND(!root);
+ EditorSelectionHistory *history = EditorNode::get_singleton()->get_editor_selection_history();
+ ERR_FAIL_COND(history->get_path_size() == 0);
+ Node *node = Object::cast_to<Node>(ObjectDB::get_instance(history->get_path_object(0)));
+ ERR_FAIL_COND(!node);
+ if (node->is_class("MultiplayerSynchronizer")) {
+ error_dialog->set_text(TTR("Properties of 'MultiplayerSynchronizer' cannot be configured for replication."));
+ error_dialog->popup_centered();
+ return;
+ }
+ if (history->get_path_size() > 1 || p_property.get_slice_count(":") > 1) {
+ error_dialog->set_text(TTR("Subresources cannot yet be configured for replication."));
+ error_dialog->popup_centered();
+ return;
+ }
+
+ String path = root->get_path_to(node);
+ for (int i = 1; i < history->get_path_size(); i++) {
+ String prop = history->get_path_property(i);
+ ERR_FAIL_COND(prop == "");
+ path += ":" + prop;
+ }
+ path += ":" + p_property;
+
+ NodePath prop = path;
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(TTR("Add property"));
+ undo_redo->add_do_method(config.ptr(), "add_property", prop);
+ undo_redo->add_undo_method(config.ptr(), "remove_property", prop);
+ undo_redo->add_do_method(this, "_update_config");
+ undo_redo->add_undo_method(this, "_update_config");
+ undo_redo->commit_action();
+}
+
+/// ReplicationEditorPlugin
+ReplicationEditorPlugin::ReplicationEditorPlugin() {
+ repl_editor = memnew(ReplicationEditor);
+ EditorNode::get_singleton()->add_bottom_panel_item(TTR("Replication"), repl_editor);
+}
+
+ReplicationEditorPlugin::~ReplicationEditorPlugin() {
+}
+
+void ReplicationEditorPlugin::_keying_changed() {
+ // TODO make lock usable.
+ //InspectorDock::get_inspector_singleton()->set_keying(repl_editor->has_keying(), this);
+}
+
+void ReplicationEditorPlugin::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) {
+ if (!repl_editor->has_keying()) {
+ return;
+ }
+ repl_editor->property_keyed(p_keyed);
+}
+
+void ReplicationEditorPlugin::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ //Node3DEditor::get_singleton()->connect("transform_key_request", callable_mp(this, &AnimationPlayerEditorPlugin::_transform_key_request));
+ InspectorDock::get_inspector_singleton()->connect("property_keyed", callable_mp(this, &ReplicationEditorPlugin::_property_keyed));
+ repl_editor->connect("keying_changed", callable_mp(this, &ReplicationEditorPlugin::_keying_changed));
+ // TODO make lock usable.
+ //InspectorDock::get_inspector_singleton()->connect("object_inspected", callable_mp(repl_editor, &ReplicationEditor::update_keying));
+ get_tree()->connect("node_removed", callable_mp(this, &ReplicationEditorPlugin::_node_removed));
+ } break;
+ }
+}
+
+void ReplicationEditorPlugin::_node_removed(Node *p_node) {
+ if (p_node && p_node == repl_editor->get_current()) {
+ repl_editor->edit(nullptr);
+ if (repl_editor->is_visible_in_tree()) {
+ EditorNode::get_singleton()->hide_bottom_panel();
+ }
+ }
+}
+
+void ReplicationEditorPlugin::edit(Object *p_object) {
+ repl_editor->edit(Object::cast_to<MultiplayerSynchronizer>(p_object));
+}
+
+bool ReplicationEditorPlugin::handles(Object *p_object) const {
+ return p_object->is_class("MultiplayerSynchronizer");
+}
+
+void ReplicationEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(repl_editor);
+ }
+}
diff --git a/editor/plugins/replication_editor_plugin.h b/editor/plugins/replication_editor_plugin.h
new file mode 100644
index 0000000000..08e86d1617
--- /dev/null
+++ b/editor/plugins/replication_editor_plugin.h
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* replication_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 REPLICATION_EDITOR_PLUGIN_H
+#define REPLICATION_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "scene/resources/scene_replication_config.h"
+
+class ConfirmationDialog;
+class MultiplayerSynchronizer;
+class Tree;
+
+class ReplicationEditor : public VBoxContainer {
+ GDCLASS(ReplicationEditor, VBoxContainer);
+
+private:
+ MultiplayerSynchronizer *current = nullptr;
+
+ AcceptDialog *error_dialog = nullptr;
+ ConfirmationDialog *delete_dialog = nullptr;
+ Button *add_button = nullptr;
+ LineEdit *np_line_edit = nullptr;
+
+ Ref<SceneReplicationConfig> config;
+ NodePath deleting;
+ Tree *tree = nullptr;
+ bool keying = false;
+
+ Ref<Texture2D> _get_class_icon(const Node *p_node);
+
+ void _add_pressed();
+ void _tree_item_edited();
+ void _tree_button_pressed(Object *p_item, int p_column, int p_id);
+ void _update_checked(const NodePath &p_prop, int p_column, bool p_checked);
+ void _update_config();
+ void _dialog_closed(bool p_confirmed);
+ void _add_property(const NodePath &p_property, bool p_spawn = true, bool p_sync = true);
+
+protected:
+ static void _bind_methods();
+
+ void _notification(int p_what);
+
+public:
+ void update_keying();
+ void edit(MultiplayerSynchronizer *p_object);
+ bool has_keying() const { return keying; }
+ MultiplayerSynchronizer *get_current() const { return current; }
+ void property_keyed(const String &p_property);
+
+ ReplicationEditor();
+ ~ReplicationEditor() {}
+};
+
+class ReplicationEditorPlugin : public EditorPlugin {
+ GDCLASS(ReplicationEditorPlugin, EditorPlugin);
+
+private:
+ ReplicationEditor *repl_editor = nullptr;
+
+ void _node_removed(Node *p_node);
+ void _keying_changed();
+ void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ ReplicationEditorPlugin();
+ ~ReplicationEditorPlugin();
+};
+
+#endif // REPLICATION_EDITOR_PLUGIN_H
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index eae6916a92..71d31aa1d7 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,19 +32,17 @@
#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
void ResourcePreloaderEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- load->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
- }
-
- if (p_what == NOTIFICATION_READY) {
- //NodePath("/root")->connect("node_removed", this,"_node_removed",Vector<Variant>(),true);
- }
-
- if (p_what == NOTIFICATION_DRAW) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ load->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
+ } break;
}
}
@@ -52,7 +50,7 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths)
for (int i = 0; i < p_paths.size(); i++) {
String path = p_paths[i];
- RES resource;
+ Ref<Resource> resource;
resource = ResourceLoader::load(path);
if (resource.is_null()) {
@@ -110,12 +108,12 @@ void ResourcePreloaderEditor::_item_edited() {
return;
}
- if (new_name == "" || new_name.find("\\") != -1 || new_name.find("/") != -1 || preloader->has_resource(new_name)) {
+ if (new_name.is_empty() || new_name.contains("\\") || new_name.contains("/") || preloader->has_resource(new_name)) {
s->set_text(0, old_name);
return;
}
- RES samp = preloader->get_resource(old_name);
+ Ref<Resource> samp = preloader->get_resource(old_name);
undo_redo->create_action(TTR("Rename Resource"));
undo_redo->add_do_method(preloader, "remove_resource", old_name);
undo_redo->add_do_method(preloader, "add_resource", new_name, samp);
@@ -137,7 +135,7 @@ void ResourcePreloaderEditor::_remove_resource(const String &p_to_remove) {
}
void ResourcePreloaderEditor::_paste_pressed() {
- RES r = EditorSettings::get_singleton()->get_resource_clipboard();
+ Ref<Resource> r = EditorSettings::get_singleton()->get_resource_clipboard();
if (!r.is_valid()) {
dialog->set_text(TTR("Resource clipboard is empty!"));
dialog->set_title(TTR("Error!"));
@@ -147,10 +145,10 @@ void ResourcePreloaderEditor::_paste_pressed() {
}
String name = r->get_name();
- if (name == "") {
+ if (name.is_empty()) {
name = r->get_path().get_file();
}
- if (name == "") {
+ if (name.is_empty()) {
name = r->get_class();
}
@@ -192,7 +190,7 @@ void ResourcePreloaderEditor::_update_library() {
ti->set_text(0, E);
ti->set_metadata(0, E);
- RES r = preloader->get_resource(E);
+ Ref<Resource> r = preloader->get_resource(E);
ERR_CONTINUE(r.is_null());
@@ -224,7 +222,7 @@ void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column,
EditorInterface::get_singleton()->open_scene_from_path(rpath);
} else if (p_id == BUTTON_EDIT_RESOURCE) {
- RES r = preloader->get_resource(item->get_text(0));
+ Ref<Resource> r = preloader->get_resource(item->get_text(0));
EditorInterface::get_singleton()->edit_resource(r);
} else if (p_id == BUTTON_REMOVE) {
@@ -251,7 +249,7 @@ Variant ResourcePreloaderEditor::get_drag_data_fw(const Point2 &p_point, Control
String name = ti->get_metadata(0);
- RES res = preloader->get_resource(name);
+ Ref<Resource> res = preloader->get_resource(name);
if (!res.is_valid()) {
return Variant();
}
@@ -271,7 +269,7 @@ bool ResourcePreloaderEditor::can_drop_data_fw(const Point2 &p_point, const Vari
}
if (String(d["type"]) == "resource" && d.has("resource")) {
- RES r = d["resource"];
+ Ref<Resource> r = d["resource"];
return r.is_valid();
}
@@ -296,11 +294,11 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant
}
if (String(d["type"]) == "resource" && d.has("resource")) {
- RES r = d["resource"];
+ Ref<Resource> r = d["resource"];
if (r.is_valid()) {
String basename;
- if (r->get_name() != "") {
+ if (!r->get_name().is_empty()) {
basename = r->get_name();
} else if (r->get_path().is_resource_file()) {
basename = r->get_path().get_basename();
@@ -402,11 +400,11 @@ void ResourcePreloaderEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
//preloader_editor->show();
button->show();
- editor->make_bottom_panel_item_visible(preloader_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(preloader_editor);
//preloader_editor->set_process(true);
} else {
if (preloader_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
button->hide();
//preloader_editor->hide();
@@ -414,12 +412,11 @@ void ResourcePreloaderEditorPlugin::make_visible(bool p_visible) {
}
}
-ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin() {
preloader_editor = memnew(ResourcePreloaderEditor);
preloader_editor->set_custom_minimum_size(Size2(0, 250) * EDSCALE);
- button = editor->add_bottom_panel_item(TTR("ResourcePreloader"), preloader_editor);
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("ResourcePreloader"), preloader_editor);
button->hide();
//preloader_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END);
diff --git a/editor/plugins/resource_preloader_editor_plugin.h b/editor/plugins/resource_preloader_editor_plugin.h
index 943765d4e0..0b799c13c6 100644
--- a/editor/plugins/resource_preloader_editor_plugin.h
+++ b/editor/plugins/resource_preloader_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,13 +31,13 @@
#ifndef RESOURCE_PRELOADER_EDITOR_PLUGIN_H
#define RESOURCE_PRELOADER_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/gui/dialogs.h"
-#include "scene/gui/file_dialog.h"
#include "scene/gui/tree.h"
#include "scene/main/resource_preloader.h"
+class EditorFileDialog;
+
class ResourcePreloaderEditor : public PanelContainer {
GDCLASS(ResourcePreloaderEditor, PanelContainer);
@@ -47,16 +47,16 @@ class ResourcePreloaderEditor : public PanelContainer {
BUTTON_REMOVE
};
- Button *load;
- Button *paste;
- Tree *tree;
+ Button *load = nullptr;
+ Button *paste = nullptr;
+ Tree *tree = nullptr;
bool loading_scene;
- EditorFileDialog *file;
+ EditorFileDialog *file = nullptr;
- AcceptDialog *dialog;
+ AcceptDialog *dialog = nullptr;
- ResourcePreloader *preloader;
+ ResourcePreloader *preloader = nullptr;
void _load_pressed();
void _files_load_request(const Vector<String> &p_paths);
@@ -66,7 +66,7 @@ class ResourcePreloaderEditor : public PanelContainer {
void _cell_button_pressed(Object *p_item, int p_column, int p_id);
void _item_edited();
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
@@ -87,9 +87,8 @@ public:
class ResourcePreloaderEditorPlugin : public EditorPlugin {
GDCLASS(ResourcePreloaderEditorPlugin, EditorPlugin);
- ResourcePreloaderEditor *preloader_editor;
- EditorNode *editor;
- Button *button;
+ ResourcePreloaderEditor *preloader_editor = nullptr;
+ Button *button = nullptr;
public:
virtual String get_name() const override { return "ResourcePreloader"; }
@@ -98,7 +97,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- ResourcePreloaderEditorPlugin(EditorNode *p_node);
+ ResourcePreloaderEditorPlugin();
~ResourcePreloaderEditorPlugin();
};
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index ed91f174d1..bfb672d694 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -89,7 +89,7 @@ void EditorPropertyRootMotion::_node_assign() {
String accum;
for (int i = 0; i < path.get_name_count(); i++) {
String name = path.get_name(i);
- if (accum != String()) {
+ if (!accum.is_empty()) {
accum += "/";
}
accum += name;
@@ -233,9 +233,12 @@ void EditorPropertyRootMotion::setup(const NodePath &p_base_hint) {
}
void EditorPropertyRootMotion::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- Ref<Texture2D> t = get_theme_icon(SNAME("Clear"), SNAME("EditorIcons"));
- clear->set_icon(t);
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ Ref<Texture2D> t = get_theme_icon(SNAME("Clear"), SNAME("EditorIcons"));
+ clear->set_icon(t);
+ } break;
}
}
@@ -271,26 +274,18 @@ EditorPropertyRootMotion::EditorPropertyRootMotion() {
//////////////////////////
bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) {
- return true; //can handle everything
-}
-
-void EditorInspectorRootMotionPlugin::parse_begin(Object *p_object) {
- //do none
+ return true; // Can handle everything.
}
bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) {
EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion);
- if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && p_hint_text != String()) {
+ if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && !p_hint_text.is_empty()) {
editor->setup(p_hint_text);
}
add_property_editor(p_path, editor);
return true;
}
- return false; //can be overridden, although it will most likely be last anyway
-}
-
-void EditorInspectorRootMotionPlugin::parse_end() {
- //do none
+ return false;
}
diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h
index 1484af62e8..5b8c1d77b3 100644
--- a/editor/plugins/root_motion_editor_plugin.h
+++ b/editor/plugins/root_motion_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -38,12 +38,12 @@
class EditorPropertyRootMotion : public EditorProperty {
GDCLASS(EditorPropertyRootMotion, EditorProperty);
- Button *assign;
- Button *clear;
+ Button *assign = nullptr;
+ Button *clear = nullptr;
NodePath base_hint;
- ConfirmationDialog *filter_dialog;
- Tree *filters;
+ ConfirmationDialog *filter_dialog = nullptr;
+ Tree *filters = nullptr;
void _confirmed();
void _node_assign();
@@ -64,9 +64,7 @@ class EditorInspectorRootMotionPlugin : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual void parse_begin(Object *p_object) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
- virtual void parse_end() override;
};
#endif // ROOT_MOTION_EDITOR_PLUGIN_H
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index aad378ecec..0d33a7bdc6 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -36,8 +36,10 @@
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
+#include "core/version.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/script_editor_debugger.h"
+#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_run_script.h"
#include "editor/editor_scale.h"
@@ -46,7 +48,7 @@
#include "editor/find_in_files.h"
#include "editor/node_dock.h"
#include "editor/plugins/shader_editor_plugin.h"
-#include "modules/visual_script/visual_script_editor.h"
+#include "modules/visual_script/editor/visual_script_editor.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
#include "script_text_editor.h"
@@ -159,7 +161,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
if (E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP) {
continue;
}
- if (name.find("/") != -1) {
+ if (name.contains("/")) {
continue;
}
highlighter->add_member_keyword_color(name, member_variable_color);
@@ -179,7 +181,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
for (const String &comment : comments) {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
- highlighter->add_color_region(beg, end, comment_color, end == "");
+ highlighter->add_color_region(beg, end, comment_color, end.is_empty());
}
/* Strings */
@@ -189,7 +191,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
for (const String &string : strings) {
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
- highlighter->add_color_region(beg, end, string_color, end == "");
+ highlighter->add_color_region(beg, end, string_color, end.is_empty());
}
}
}
@@ -230,7 +232,7 @@ void ScriptEditorBase::_bind_methods() {
class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache {
struct Cache {
uint64_t time_loaded = 0;
- RES cache;
+ Ref<Resource> cache;
};
Map<String, Cache> cached;
@@ -256,7 +258,7 @@ public:
}
}
- virtual RES get_cached_resource(const String &p_path) {
+ virtual Ref<Resource> get_cached_resource(const String &p_path) {
Map<String, Cache>::Element *E = cached.find(p_path);
if (!E) {
Cache c;
@@ -309,7 +311,7 @@ void ScriptEditorQuickOpen::_text_changed(const String &p_newtext) {
void ScriptEditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
Ref<InputEventKey> k = p_ie;
- if (k.is_valid() && (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_PAGEUP || k->get_keycode() == KEY_PAGEDOWN)) {
+ if (k.is_valid() && (k->get_keycode() == Key::UP || k->get_keycode() == Key::DOWN || k->get_keycode() == Key::PAGEUP || k->get_keycode() == Key::PAGEDOWN)) {
search_options->gui_input(k);
search_box->accept_event();
}
@@ -321,7 +323,7 @@ void ScriptEditorQuickOpen::_update_search() {
for (int i = 0; i < functions.size(); i++) {
String file = functions[i];
- if ((search_box->get_text() == "" || file.findn(search_box->get_text()) != -1)) {
+ if ((search_box->get_text().is_empty() || file.findn(search_box->get_text()) != -1)) {
TreeItem *ti = search_options->create_item(root);
ti->set_text(0, file);
if (root->get_first_child() == ti) {
@@ -355,6 +357,7 @@ void ScriptEditorQuickOpen::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
search_box->set_right_icon(search_options->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
} break;
+
case NOTIFICATION_EXIT_TREE: {
disconnect("confirmed", callable_mp(this, &ScriptEditorQuickOpen::_confirmed));
} break;
@@ -392,7 +395,7 @@ ScriptEditor *ScriptEditor::script_editor = nullptr;
String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) {
String val = EditorDebuggerNode::get_singleton()->get_var_value(p_text);
- if (val != String()) {
+ if (!val.is_empty()) {
return p_text + ": " + val;
} else {
return String();
@@ -404,8 +407,8 @@ void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) {
return;
}
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -415,7 +418,7 @@ void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) {
}
void ScriptEditor::_script_created(Ref<Script> p_script) {
- editor->push_item(p_script.operator->());
+ EditorNode::get_singleton()->push_item(p_script.operator->());
}
void ScriptEditor::_goto_script_line2(int p_line) {
@@ -425,11 +428,11 @@ void ScriptEditor::_goto_script_line2(int p_line) {
}
}
-void ScriptEditor::_goto_script_line(REF p_script, int p_line) {
+void ScriptEditor::_goto_script_line(Ref<RefCounted> p_script, int p_line) {
Ref<Script> script = Object::cast_to<Script>(*p_script);
if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
if (edit(p_script, p_line, 0)) {
- editor->push_item(p_script.ptr());
+ EditorNode::get_singleton()->push_item(p_script.ptr());
ScriptEditorBase *current = _get_current_editor();
if (ScriptTextEditor *script_text_editor = Object::cast_to<ScriptTextEditor>(current)) {
@@ -441,11 +444,11 @@ void ScriptEditor::_goto_script_line(REF p_script, int p_line) {
}
}
-void ScriptEditor::_set_execution(REF p_script, int p_line) {
+void ScriptEditor::_set_execution(Ref<RefCounted> p_script, int p_line) {
Ref<Script> script = Object::cast_to<Script>(*p_script);
if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -457,11 +460,11 @@ void ScriptEditor::_set_execution(REF p_script, int p_line) {
}
}
-void ScriptEditor::_clear_execution(REF p_script) {
+void ScriptEditor::_clear_execution(Ref<RefCounted> p_script) {
Ref<Script> script = Object::cast_to<Script>(*p_script);
if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -473,12 +476,12 @@ void ScriptEditor::_clear_execution(REF p_script) {
}
}
-void ScriptEditor::_set_breakpoint(REF p_script, int p_line, bool p_enabled) {
+void ScriptEditor::_set_breakpoint(Ref<RefCounted> p_script, int p_line, bool p_enabled) {
Ref<Script> script = Object::cast_to<Script>(*p_script);
if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
// Update if open.
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se && se->get_edited_resource()->get_path() == script->get_path()) {
se->set_breakpoint(p_line, p_enabled);
return;
@@ -506,8 +509,8 @@ void ScriptEditor::_set_breakpoint(REF p_script, int p_line, bool p_enabled) {
}
void ScriptEditor::_clear_breakpoints() {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se) {
se->clear_breakpoints();
}
@@ -544,11 +547,11 @@ Array ScriptEditor::_get_cached_breakpoints_for_script(const String &p_path) con
ScriptEditorBase *ScriptEditor::_get_current_editor() const {
int selected = tab_container->get_current_tab();
- if (selected < 0 || selected >= tab_container->get_child_count()) {
+ if (selected < 0 || selected >= tab_container->get_tab_count()) {
return nullptr;
}
- return Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected));
+ return Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(selected));
}
void ScriptEditor::_update_history_arrows() {
@@ -587,7 +590,7 @@ void ScriptEditor::_go_to_tab(int p_idx) {
}
}
- Control *c = Object::cast_to<Control>(tab_container->get_child(p_idx));
+ Control *c = Object::cast_to<Control>(tab_container->get_tab_control(p_idx));
if (!c) {
return;
}
@@ -677,8 +680,9 @@ void ScriptEditor::_update_recent_scripts() {
recent_scripts->add_separator();
recent_scripts->add_shortcut(ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Files")));
+ recent_scripts->set_item_disabled(recent_scripts->get_item_id(recent_scripts->get_item_count() - 1), rc.is_empty());
- recent_scripts->set_as_minsize();
+ recent_scripts->reset_size();
}
void ScriptEditor::_open_recent_script(int p_idx) {
@@ -713,7 +717,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
return;
}
// if it's a path then it's most likely a deleted file not help
- } else if (path.find("::") != -1) {
+ } else if (path.contains("::")) {
// built-in script
String res_path = path.get_slice("::", 0);
if (ResourceLoader::get_resource_type(res_path) == "PackedScene") {
@@ -733,7 +737,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
return;
}
- rc.remove(p_idx);
+ rc.remove_at(p_idx);
EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", rc);
_update_recent_scripts();
_show_error_dialog(path);
@@ -746,19 +750,19 @@ void ScriptEditor::_show_error_dialog(String p_path) {
void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
int selected = p_idx;
- if (selected < 0 || selected >= tab_container->get_child_count()) {
+ if (selected < 0 || selected >= tab_container->get_tab_count()) {
return;
}
- Node *tselected = tab_container->get_child(selected);
+ Node *tselected = tab_container->get_tab_control(selected);
ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tselected);
if (current) {
- RES file = current->get_edited_resource();
+ Ref<Resource> file = current->get_edited_resource();
if (p_save && file.is_valid()) {
// Do not try to save internal scripts, but prompt to save in-memory
// scripts which are not saved to disk yet (have empty path).
- if (file->is_built_in()) {
+ if (!file->is_built_in()) {
save_current_script();
}
}
@@ -785,7 +789,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
for (int i = 0; i < history.size(); i++) {
if (history[i].control == tselected) {
- history.remove(i);
+ history.remove_at(i);
i--;
history_pos--;
}
@@ -801,12 +805,12 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
_save_editor_state(current);
}
memdelete(tselected);
- if (idx >= tab_container->get_child_count()) {
- idx = tab_container->get_child_count() - 1;
+ if (idx >= tab_container->get_tab_count()) {
+ idx = tab_container->get_tab_count() - 1;
}
if (idx >= 0) {
if (history_pos >= 0) {
- idx = history[history_pos].control->get_index();
+ idx = tab_container->get_tab_idx_from_control(history[history_pos].control);
}
tab_container->set_current_tab(idx);
} else {
@@ -832,9 +836,9 @@ void ScriptEditor::_close_discard_current_tab(const String &p_str) {
}
void ScriptEditor::_close_docs_tab() {
- int child_count = tab_container->get_child_count();
+ int child_count = tab_container->get_tab_count();
for (int i = child_count - 1; i >= 0; i--) {
- EditorHelp *se = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+ EditorHelp *se = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
if (se) {
_close_tab(i, true, false);
@@ -845,14 +849,14 @@ void ScriptEditor::_close_docs_tab() {
void ScriptEditor::_copy_script_path() {
ScriptEditorBase *se = _get_current_editor();
if (se) {
- RES script = se->get_edited_resource();
+ Ref<Resource> script = se->get_edited_resource();
DisplayServer::get_singleton()->clipboard_set(script->get_path());
}
}
void ScriptEditor::_close_other_tabs() {
int current_idx = tab_container->get_current_tab();
- for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+ for (int i = tab_container->get_tab_count() - 1; i >= 0; i--) {
if (i != current_idx) {
script_close_queue.push_back(i);
}
@@ -861,7 +865,7 @@ void ScriptEditor::_close_other_tabs() {
}
void ScriptEditor::_close_all_tabs() {
- for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+ for (int i = tab_container->get_tab_count() - 1; i >= 0; i--) {
script_close_queue.push_back(i);
}
_queue_close_tabs();
@@ -873,7 +877,7 @@ void ScriptEditor::_queue_close_tabs() {
script_close_queue.pop_front();
tab_container->set_current_tab(idx);
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(idx));
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(idx));
if (se) {
// Maybe there are unsaved changes.
if (se->is_unsaved()) {
@@ -896,13 +900,13 @@ void ScriptEditor::_ask_close_current_unsaved_tab(ScriptEditorBase *current) {
void ScriptEditor::_resave_scripts(const String &p_str) {
apply_scripts();
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
- RES script = se->get_edited_resource();
+ Ref<Resource> script = se->get_edited_resource();
if (script->is_built_in()) {
continue; //internal script, who cares
@@ -928,7 +932,7 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
_save_text_file(text_file, text_file->get_path());
break;
} else {
- editor->save_resource(script);
+ EditorNode::get_singleton()->save_resource(script);
}
se->tag_saved_version();
}
@@ -937,13 +941,13 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
}
void ScriptEditor::_reload_scripts() {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
- RES edited_res = se->get_edited_resource();
+ Ref<Resource> edited_res = se->get_edited_resource();
if (edited_res->is_built_in()) {
continue; //internal script, who cares
@@ -981,17 +985,13 @@ void ScriptEditor::_reload_scripts() {
}
void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
- RES script = se->get_edited_resource();
-
- if (script->is_built_in()) {
- continue; //internal script, who cares
- }
+ Ref<Resource> script = se->get_edited_resource();
if (script == p_res) {
se->tag_saved_version();
@@ -1002,6 +1002,31 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
_trigger_live_script_reload();
}
+void ScriptEditor::_scene_saved_callback(const String &p_path) {
+ // If scene was saved, mark all built-in scripts from that scene as saved.
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
+ if (!se) {
+ continue;
+ }
+
+ Ref<Resource> edited_res = se->get_edited_resource();
+
+ if (!edited_res->is_built_in()) {
+ continue; // External script, who cares.
+ }
+
+ if (edited_res->get_path().get_slice("::", 0) == p_path) {
+ se->tag_saved_version();
+ }
+
+ Ref<Script> scr = edited_res;
+ if (scr.is_valid() && scr->is_tool()) {
+ scr->reload(true);
+ }
+ }
+}
+
void ScriptEditor::_trigger_live_script_reload() {
if (!pending_auto_reload && auto_reload_running_scripts) {
call_deferred(SNAME("_live_auto_reload_running_scripts"));
@@ -1014,19 +1039,19 @@ void ScriptEditor::_live_auto_reload_running_scripts() {
EditorDebuggerNode::get_singleton()->reload_scripts();
}
-bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) {
+bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) {
disk_changed_list->clear();
TreeItem *r = disk_changed_list->create_item();
disk_changed_list->set_hide_root(true);
bool need_ask = false;
bool need_reload = false;
- bool use_autoreload = bool(EDITOR_DEF("text_editor/behavior/files/auto_reload_scripts_on_external_change", false));
+ bool use_autoreload = bool(EDITOR_GET("text_editor/behavior/files/auto_reload_scripts_on_external_change"));
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se) {
- RES edited_res = se->get_edited_resource();
+ Ref<Resource> edited_res = se->get_edited_resource();
if (p_for_script.is_valid() && edited_res.is_valid() && p_for_script != edited_res) {
continue;
}
@@ -1066,13 +1091,13 @@ void ScriptEditor::_file_dialog_action(String p_file) {
switch (file_dialog_option) {
case FILE_NEW_TEXTFILE: {
Error err;
- FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
- if (err) {
- editor->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!"));
- break;
+ {
+ Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
+ if (err) {
+ EditorNode::get_singleton()->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!"));
+ break;
+ }
}
- file->close();
- memdelete(file);
if (EditorFileSystem::get_singleton()) {
if (textfile_extensions.has(p_file.get_extension())) {
@@ -1092,12 +1117,12 @@ void ScriptEditor::_file_dialog_action(String p_file) {
case FILE_SAVE_AS: {
ScriptEditorBase *current = _get_current_editor();
if (current) {
- RES resource = current->get_edited_resource();
+ Ref<Resource> resource = current->get_edited_resource();
String path = ProjectSettings::get_singleton()->localize_path(p_file);
Error err = _save_text_file(resource, path);
if (err != OK) {
- editor->show_accept(TTR("Error saving file!"), TTR("OK"));
+ EditorNode::get_singleton()->show_accept(TTR("Error saving file!"), TTR("OK"));
return;
}
@@ -1107,12 +1132,12 @@ void ScriptEditor::_file_dialog_action(String p_file) {
} break;
case THEME_SAVE_AS: {
if (!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) {
- editor->show_warning(TTR("Error while saving theme."), TTR("Error Saving"));
+ EditorNode::get_singleton()->show_warning(TTR("Error while saving theme."), TTR("Error Saving"));
}
} break;
case THEME_IMPORT: {
if (!EditorSettings::get_singleton()->import_text_editor_theme(p_file)) {
- editor->show_warning(TTR("Error importing theme."), TTR("Error Importing"));
+ EditorNode::get_singleton()->show_warning(TTR("Error importing theme."), TTR("Error Importing"));
}
} break;
}
@@ -1207,9 +1232,6 @@ void ScriptEditor::_menu_option(int p_option) {
if (ResourceLoader::get_resource_type(res_path) == "PackedScene") {
if (!EditorNode::get_singleton()->is_scene_open(res_path)) {
EditorNode::get_singleton()->load_scene(res_path);
- script_editor->call_deferred(SNAME("_menu_option"), p_option);
- previous_scripts.push_back(path); //repeat the operation
- return;
}
} else {
EditorNode::get_singleton()->load_resource(res_path);
@@ -1218,25 +1240,23 @@ void ScriptEditor::_menu_option(int p_option) {
Ref<Script> scr = ResourceLoader::load(path);
if (!scr.is_valid()) {
- editor->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!"));
+ EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!"));
file_dialog_option = -1;
return;
}
edit(scr);
file_dialog_option = -1;
- return;
} else {
Error error;
Ref<TextFile> text_file = _load_text_file(path, &error);
if (error != OK) {
- editor->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!"));
+ EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!"));
}
if (text_file.is_valid()) {
edit(text_file);
file_dialog_option = -1;
- return;
}
}
} break;
@@ -1257,7 +1277,7 @@ void ScriptEditor::_menu_option(int p_option) {
help_search_dialog->popup_dialog();
} break;
case SEARCH_WEBSITE: {
- OS::get_singleton()->shell_open("https://docs.godotengine.org/");
+ OS::get_singleton()->shell_open(VERSION_DOCS_URL "/");
} break;
case WINDOW_NEXT: {
_history_forward();
@@ -1303,7 +1323,7 @@ void ScriptEditor::_menu_option(int p_option) {
}
}
- RES resource = current->get_edited_resource();
+ Ref<Resource> resource = current->get_edited_resource();
Ref<TextFile> text_file = resource;
Ref<Script> script = resource;
@@ -1323,7 +1343,7 @@ void ScriptEditor::_menu_option(int p_option) {
}
if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ Vector<DocData::ClassDoc> documentations = script->get_documentation();
for (int j = 0; j < documentations.size(); j++) {
const DocData::ClassDoc &doc = documentations.get(j);
if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
@@ -1332,11 +1352,11 @@ void ScriptEditor::_menu_option(int p_option) {
}
}
- editor->push_item(resource.ptr());
- editor->save_resource_as(resource);
+ EditorNode::get_singleton()->push_item(resource.ptr());
+ EditorNode::get_singleton()->save_resource_as(resource);
if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ Vector<DocData::ClassDoc> documentations = script->get_documentation();
for (int j = 0; j < documentations.size(); j++) {
const DocData::ClassDoc &doc = documentations.get(j);
EditorHelp::get_doc_data()->add_doc(doc);
@@ -1393,14 +1413,18 @@ void ScriptEditor::_menu_option(int p_option) {
_copy_script_path();
} break;
case SHOW_IN_FILE_SYSTEM: {
- const RES script = current->get_edited_resource();
- const String path = script->get_path();
+ const Ref<Resource> script = current->get_edited_resource();
+ String path = script->get_path();
if (!path.is_empty()) {
- FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock();
+ if (script->is_built_in()) {
+ path = path.get_slice("::", 0); // Show the scene instead.
+ }
+
+ FileSystemDock *file_system_dock = FileSystemDock::get_singleton();
file_system_dock->navigate_to_path(path);
// Ensure that the FileSystem dock is visible.
TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
- tab_container->set_current_tab(file_system_dock->get_index());
+ tab_container->set_current_tab(tab_container->get_tab_idx_from_control(file_system_dock));
}
} break;
case CLOSE_DOCS: {
@@ -1420,7 +1444,7 @@ void ScriptEditor::_menu_option(int p_option) {
}
} break;
case WINDOW_MOVE_DOWN: {
- if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) {
+ if (tab_container->get_current_tab() < tab_container->get_tab_count() - 1) {
tab_container->move_child(current, tab_container->get_current_tab() + 1);
tab_container->set_current_tab(tab_container->get_current_tab() + 1);
_update_script_names();
@@ -1466,7 +1490,7 @@ void ScriptEditor::_menu_option(int p_option) {
}
} break;
case WINDOW_MOVE_DOWN: {
- if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) {
+ if (tab_container->get_current_tab() < tab_container->get_tab_count() - 1) {
tab_container->move_child(help, tab_container->get_current_tab() + 1);
tab_container->set_current_tab(tab_container->get_current_tab() + 1);
_update_script_names();
@@ -1495,7 +1519,7 @@ void ScriptEditor::_theme_option(int p_option) {
if (EditorSettings::get_singleton()->is_default_text_editor_theme()) {
ScriptEditor::_show_save_theme_as_dialog();
} else if (!EditorSettings::get_singleton()->save_text_editor_theme()) {
- editor->show_warning(TTR("Error while saving theme"), TTR("Error saving"));
+ EditorNode::get_singleton()->show_warning(TTR("Error while saving theme"), TTR("Error saving"));
}
} break;
case THEME_SAVE_AS: {
@@ -1515,6 +1539,51 @@ void ScriptEditor::_show_save_theme_as_dialog() {
file_dialog->set_title(TTR("Save Theme As..."));
}
+bool ScriptEditor::_has_docs_tab() const {
+ const int child_count = tab_container->get_tab_count();
+ for (int i = 0; i < child_count; i++) {
+ if (Object::cast_to<EditorHelp>(tab_container->get_tab_control(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ScriptEditor::_has_script_tab() const {
+ const int child_count = tab_container->get_tab_count();
+ for (int i = 0; i < child_count; i++) {
+ if (Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ScriptEditor::_prepare_file_menu() {
+ PopupMenu *menu = file_menu->get_popup();
+ const bool current_is_doc = _get_current_editor() == nullptr;
+
+ menu->set_item_disabled(menu->get_item_index(FILE_REOPEN_CLOSED), previous_scripts.is_empty());
+
+ menu->set_item_disabled(menu->get_item_index(FILE_SAVE), current_is_doc);
+ menu->set_item_disabled(menu->get_item_index(FILE_SAVE_AS), current_is_doc);
+ menu->set_item_disabled(menu->get_item_index(FILE_SAVE_ALL), !_has_script_tab());
+
+ menu->set_item_disabled(menu->get_item_index(FILE_TOOL_RELOAD_SOFT), current_is_doc);
+ menu->set_item_disabled(menu->get_item_index(FILE_COPY_PATH), current_is_doc);
+ menu->set_item_disabled(menu->get_item_index(SHOW_IN_FILE_SYSTEM), current_is_doc);
+
+ menu->set_item_disabled(menu->get_item_index(WINDOW_PREV), history_pos <= 0);
+ menu->set_item_disabled(menu->get_item_index(WINDOW_NEXT), history_pos >= history.size() - 1);
+
+ menu->set_item_disabled(menu->get_item_index(FILE_CLOSE), tab_container->get_tab_count() < 1);
+ menu->set_item_disabled(menu->get_item_index(CLOSE_ALL), tab_container->get_tab_count() < 1);
+ menu->set_item_disabled(menu->get_item_index(CLOSE_OTHER_TABS), tab_container->get_tab_count() <= 1);
+ menu->set_item_disabled(menu->get_item_index(CLOSE_DOCS), !_has_docs_tab());
+
+ menu->set_item_disabled(menu->get_item_index(FILE_RUN), current_is_doc);
+}
+
void ScriptEditor::_tab_changed(int p_which) {
ensure_select_current();
}
@@ -1522,16 +1591,18 @@ void ScriptEditor::_tab_changed(int p_which) {
void ScriptEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- editor->connect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
- editor->connect("script_add_function_request", callable_mp(this, &ScriptEditor::_add_callback));
- editor->connect("resource_saved", callable_mp(this, &ScriptEditor::_res_saved_callback));
- editor->get_filesystem_dock()->connect("files_moved", callable_mp(this, &ScriptEditor::_files_moved));
- editor->get_filesystem_dock()->connect("file_removed", callable_mp(this, &ScriptEditor::_file_removed));
+ EditorNode::get_singleton()->connect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
+ EditorNode::get_singleton()->connect("script_add_function_request", callable_mp(this, &ScriptEditor::_add_callback));
+ EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &ScriptEditor::_res_saved_callback));
+ EditorNode::get_singleton()->connect("scene_saved", callable_mp(this, &ScriptEditor::_scene_saved_callback));
+ FileSystemDock::get_singleton()->connect("files_moved", callable_mp(this, &ScriptEditor::_files_moved));
+ FileSystemDock::get_singleton()->connect("file_removed", callable_mp(this, &ScriptEditor::_file_removed));
script_list->connect("item_selected", callable_mp(this, &ScriptEditor::_script_selected));
members_overview->connect("item_selected", callable_mp(this, &ScriptEditor::_members_overview_selected));
help_overview->connect("item_selected", callable_mp(this, &ScriptEditor::_help_overview_selected));
- script_split->connect("dragged", callable_mp(this, &ScriptEditor::_script_split_dragged));
+ script_split->connect("dragged", callable_mp(this, &ScriptEditor::_split_dragged));
+ list_split->connect("dragged", callable_mp(this, &ScriptEditor::_split_dragged));
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ScriptEditor::_editor_settings_changed));
EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &ScriptEditor::_filesystem_changed));
@@ -1542,7 +1613,7 @@ void ScriptEditor::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
help_search->set_icon(get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")));
- site_search->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
+ site_search->set_icon(get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
if (is_layout_rtl()) {
script_forward->set_icon(get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
@@ -1557,9 +1628,9 @@ void ScriptEditor::_notification(int p_what) {
filter_scripts->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
filter_methods->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- filename->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox(SNAME("normal"), SNAME("LineEdit")));
+ filename->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("normal"), SNAME("LineEdit")));
- recent_scripts->set_as_minsize();
+ recent_scripts->reset_size();
if (is_inside_tree()) {
_update_script_colors();
@@ -1569,12 +1640,12 @@ void ScriptEditor::_notification(int p_what) {
case NOTIFICATION_READY: {
get_tree()->connect("tree_changed", callable_mp(this, &ScriptEditor::_tree_changed));
- editor->get_inspector_dock()->connect("request_help", callable_mp(this, &ScriptEditor::_help_class_open));
- editor->connect("request_help_search", callable_mp(this, &ScriptEditor::_help_search));
+ InspectorDock::get_singleton()->connect("request_help", callable_mp(this, &ScriptEditor::_help_class_open));
+ EditorNode::get_singleton()->connect("request_help_search", callable_mp(this, &ScriptEditor::_help_search));
} break;
case NOTIFICATION_EXIT_TREE: {
- editor->disconnect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
+ EditorNode::get_singleton()->disconnect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
@@ -1587,15 +1658,12 @@ void ScriptEditor::_notification(int p_what) {
find_in_files_button->show();
} else {
if (find_in_files->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
find_in_files_button->hide();
}
} break;
-
- default:
- break;
}
}
@@ -1609,8 +1677,8 @@ bool ScriptEditor::can_take_away_focus() const {
}
void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se) {
Ref<Script> script = se->get_edited_resource();
@@ -1619,7 +1687,7 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) {
}
if (script->is_built_in() && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed
- _close_tab(i);
+ _close_tab(i, false);
i--;
}
}
@@ -1640,8 +1708,8 @@ void ScriptEditor::notify_script_changed(const Ref<Script> &p_script) {
void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
Set<String> loaded_scripts;
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -1653,7 +1721,7 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
String base = script->get_path();
loaded_scripts.insert(base);
- if (base.begins_with("local://") || base == "") {
+ if (base.begins_with("local://") || base.is_empty()) {
continue;
}
@@ -1693,7 +1761,7 @@ void ScriptEditor::_members_overview_selected(int p_idx) {
}
void ScriptEditor::_help_overview_selected(int p_idx) {
- Node *current = tab_container->get_child(tab_container->get_current_tab());
+ Node *current = tab_container->get_tab_control(tab_container->get_current_tab());
EditorHelp *se = Object::cast_to<EditorHelp>(current);
if (!se) {
return;
@@ -1702,14 +1770,14 @@ void ScriptEditor::_help_overview_selected(int p_idx) {
}
void ScriptEditor::_script_selected(int p_idx) {
- grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT); //amazing hack, simply amazing
+ grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT); //amazing hack, simply amazing
_go_to_tab(script_list->get_item_metadata(p_idx));
grab_focus_block = false;
}
void ScriptEditor::ensure_select_current() {
- if (tab_container->get_child_count() && tab_container->get_current_tab() >= 0) {
+ if (tab_container->get_tab_count() && tab_container->get_current_tab() >= 0) {
ScriptEditorBase *se = _get_current_editor();
if (se) {
se->enable_editor();
@@ -1745,6 +1813,7 @@ struct _ScriptEditorItemData {
String name;
String sort_key;
Ref<Texture2D> icon;
+ bool tool = false;
int index = 0;
String tooltip;
bool used = false;
@@ -1805,9 +1874,9 @@ void ScriptEditor::_update_members_overview() {
for (int i = 0; i < functions.size(); i++) {
String filter = filter_methods->get_text();
String name = functions[i].get_slice(":", 0);
- if (filter == "" || filter.is_subsequence_ofi(name)) {
+ if (filter.is_empty() || filter.is_subsequence_ofn(name)) {
members_overview->add_item(name);
- members_overview->set_item_metadata(members_overview->get_item_count() - 1, functions[i].get_slice(":", 1).to_int() - 1);
+ members_overview->set_item_metadata(-1, functions[i].get_slice(":", 1).to_int() - 1);
}
}
@@ -1819,12 +1888,12 @@ void ScriptEditor::_update_members_overview() {
void ScriptEditor::_update_help_overview_visibility() {
int selected = tab_container->get_current_tab();
- if (selected < 0 || selected >= tab_container->get_child_count()) {
+ if (selected < 0 || selected >= tab_container->get_tab_count()) {
help_overview->set_visible(false);
return;
}
- Node *current = tab_container->get_child(tab_container->get_current_tab());
+ Node *current = tab_container->get_tab_control(tab_container->get_current_tab());
EditorHelp *se = Object::cast_to<EditorHelp>(current);
if (!se) {
help_overview->set_visible(false);
@@ -1846,11 +1915,11 @@ void ScriptEditor::_update_help_overview() {
help_overview->clear();
int selected = tab_container->get_current_tab();
- if (selected < 0 || selected >= tab_container->get_child_count()) {
+ if (selected < 0 || selected >= tab_container->get_tab_count()) {
return;
}
- Node *current = tab_container->get_child(tab_container->get_current_tab());
+ Node *current = tab_container->get_tab_control(tab_container->get_current_tab());
EditorHelp *se = Object::cast_to<EditorHelp>(current);
if (!se) {
return;
@@ -1868,11 +1937,12 @@ void ScriptEditor::_update_script_colors() {
int hist_size = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_history_size");
Color hot_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ hot_color.set_s(hot_color.get_s() * 0.9);
Color cold_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
for (int i = 0; i < script_list->get_item_count(); i++) {
int c = script_list->get_item_metadata(i);
- Node *n = tab_container->get_child(c);
+ Node *n = tab_container->get_tab_control(c);
if (!n) {
continue;
}
@@ -1915,8 +1985,8 @@ void ScriptEditor::_update_script_names() {
Vector<_ScriptEditorItemData> sedata;
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se) {
Ref<Texture2D> icon = se->get_theme_icon();
String path = se->get_edited_resource()->get_path();
@@ -1926,20 +1996,8 @@ void ScriptEditor::_update_script_names() {
// to update original path to previously edited resource.
se->set_meta("_edit_res_path", path);
}
- bool built_in = !path.is_resource_file();
- String name;
-
- if (built_in) {
- name = path.get_file();
- const String &resource_name = se->get_edited_resource()->get_name();
- if (resource_name != "") {
- // If the built-in script has a custom resource name defined,
- // display the built-in script name as follows: `ResourceName (scene_file.tscn)`
- name = vformat("%s (%s)", resource_name, name.substr(0, name.find("::", 0)));
- }
- } else {
- name = se->get_name();
- }
+ String name = se->get_name();
+ Ref<Script> scr = se->get_edited_resource();
_ScriptEditorItemData sd;
sd.icon = icon;
@@ -1949,6 +2007,9 @@ void ScriptEditor::_update_script_names() {
sd.used = used.has(se->get_edited_resource());
sd.category = 0;
sd.ref = se;
+ if (scr.is_valid()) {
+ sd.tool = scr->is_tool();
+ }
switch (sort_by) {
case SORT_BY_NAME: {
@@ -2014,7 +2075,7 @@ void ScriptEditor::_update_script_names() {
}
}
- EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+ EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
if (eh) {
String name = eh->get_class();
Ref<Texture2D> icon = get_theme_icon(SNAME("Help"), SNAME("EditorIcons"));
@@ -2063,13 +2124,19 @@ void ScriptEditor::_update_script_names() {
Vector<_ScriptEditorItemData> sedata_filtered;
for (int i = 0; i < sedata.size(); i++) {
String filter = filter_scripts->get_text();
- if (filter == "" || filter.is_subsequence_ofi(sedata[i].name)) {
+ if (filter.is_empty() || filter.is_subsequence_ofn(sedata[i].name)) {
sedata_filtered.push_back(sedata[i]);
}
}
+ Color tool_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ tool_color.set_s(tool_color.get_s() * 1.5);
for (int i = 0; i < sedata_filtered.size(); i++) {
script_list->add_item(sedata_filtered[i].name, sedata_filtered[i].icon);
+ if (sedata_filtered[i].tool) {
+ script_list->set_item_icon_modulate(-1, tool_color);
+ }
+
int index = script_list->get_item_count() - 1;
script_list->set_item_tooltip(index, sedata_filtered[i].tooltip);
script_list->set_item_metadata(index, sedata_filtered[i].index); /* Saving as metadata the script's index in the tab container and not the filtered one */
@@ -2097,13 +2164,11 @@ void ScriptEditor::_update_script_names() {
_update_members_overview_visibility();
_update_help_overview_visibility();
_update_script_colors();
-
- file_menu->get_popup()->set_item_disabled(file_menu->get_popup()->get_item_index(FILE_REOPEN_CLOSED), previous_scripts.is_empty());
}
void ScriptEditor::_update_script_connections() {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(tab_container->get_tab_control(i));
if (!ste) {
continue;
}
@@ -2123,7 +2188,7 @@ Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error
Ref<TextFile> text_res(text_file);
Error err = text_file->load_text(path);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load text file '" + path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot load text file '" + path + "'.");
text_file->set_file_path(local_path);
text_file->set_path(local_path, true);
@@ -2146,17 +2211,16 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p
String source = sqscr->get_text();
Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ {
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot save text file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save text file '" + p_path + "'.");
- file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
- return ERR_CANT_CREATE;
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
- file->close();
- memdelete(file);
if (ResourceSaver::get_timestamp_on_save()) {
p_text_file->set_last_modified_time(FileAccess::get_modified_time(p_path));
@@ -2166,7 +2230,7 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p
return OK;
}
-bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_grab_focus) {
+bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col, bool p_grab_focus) {
if (p_resource.is_null()) {
return false;
}
@@ -2195,7 +2259,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
if (use_external_editor &&
(EditorDebuggerNode::get_singleton()->get_dump_stack_script() != p_resource || EditorDebuggerNode::get_singleton()->get_debug_with_external_editor()) &&
p_resource->get_path().is_resource_file() &&
- p_resource->get_class_name() != StringName("VisualScript")) {
+ !p_resource->is_class("VisualScript")) {
String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path");
String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags");
@@ -2223,7 +2287,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
} else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) {
String arg = flags.substr(from, num_chars);
- if (arg.find("{file}") != -1) {
+ if (arg.contains("{file}")) {
has_file_flag = true;
}
@@ -2252,8 +2316,8 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
WARN_PRINT("Couldn't open external text editor, using internal");
}
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -2294,7 +2358,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
se->set_edited_resource(p_resource);
- if (p_resource->get_class_name() != StringName("VisualScript")) {
+ if (!p_resource->is_class("VisualScript")) {
bool highlighter_set = false;
for (int i = 0; i < syntax_highlighters.size(); i++) {
Ref<EditorSyntaxHighlighter> highlighter = syntax_highlighters[i]->_create();
@@ -2322,7 +2386,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
// If we delete a script within the filesystem, the original resource path
// is lost, so keep it as metadata to figure out the exact tab to delete.
se->set_meta("_edit_res_path", p_resource->get_path());
- se->set_tooltip_request_func("_get_debug_tooltip", this);
+ se->set_tooltip_request_func(callable_mp(this, &ScriptEditor::_get_debug_tooltip));
if (se->get_edit_menu()) {
se->get_edit_menu()->hide();
menu_hb->add_child(se->get_edit_menu());
@@ -2383,7 +2447,7 @@ void ScriptEditor::save_current_script() {
}
}
- RES resource = current->get_edited_resource();
+ Ref<Resource> resource = current->get_edited_resource();
Ref<TextFile> text_file = resource;
Ref<Script> script = resource;
@@ -2394,7 +2458,7 @@ void ScriptEditor::save_current_script() {
}
if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ Vector<DocData::ClassDoc> documentations = script->get_documentation();
for (int j = 0; j < documentations.size(); j++) {
const DocData::ClassDoc &doc = documentations.get(j);
if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
@@ -2403,10 +2467,20 @@ void ScriptEditor::save_current_script() {
}
}
- editor->save_resource(resource);
+ if (resource->is_built_in()) {
+ // If built-in script, save the scene instead.
+ const String scene_path = resource->get_path().get_slice("::", 0);
+ if (!scene_path.is_empty()) {
+ Vector<String> scene_to_save;
+ scene_to_save.push_back(scene_path);
+ EditorNode::get_singleton()->save_scene_list(scene_to_save);
+ }
+ } else {
+ EditorNode::get_singleton()->save_resource(resource);
+ }
if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ Vector<DocData::ClassDoc> documentations = script->get_documentation();
for (int j = 0; j < documentations.size(); j++) {
const DocData::ClassDoc &doc = documentations.get(j);
EditorHelp::get_doc_data()->add_doc(doc);
@@ -2416,8 +2490,10 @@ void ScriptEditor::save_current_script() {
}
void ScriptEditor::save_all_scripts() {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ Vector<String> scenes_to_save;
+
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -2440,7 +2516,7 @@ void ScriptEditor::save_all_scripts() {
continue;
}
- RES edited_res = se->get_edited_resource();
+ Ref<Resource> edited_res = se->get_edited_resource();
if (edited_res.is_valid()) {
se->apply_code();
}
@@ -2455,7 +2531,7 @@ void ScriptEditor::save_all_scripts() {
}
if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ Vector<DocData::ClassDoc> documentations = script->get_documentation();
for (int j = 0; j < documentations.size(); j++) {
const DocData::ClassDoc &doc = documentations.get(j);
if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
@@ -2464,26 +2540,36 @@ void ScriptEditor::save_all_scripts() {
}
}
- editor->save_resource(edited_res); //external script, save it
+ EditorNode::get_singleton()->save_resource(edited_res); //external script, save it
if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ Vector<DocData::ClassDoc> documentations = script->get_documentation();
for (int j = 0; j < documentations.size(); j++) {
const DocData::ClassDoc &doc = documentations.get(j);
EditorHelp::get_doc_data()->add_doc(doc);
update_doc(doc.name);
}
}
+ } else {
+ // For built-in scripts, save their scenes instead.
+ const String scene_path = edited_res->get_path().get_slice("::", 0);
+ if (!scenes_to_save.has(scene_path)) {
+ scenes_to_save.push_back(scene_path);
+ }
}
}
+ if (!scenes_to_save.is_empty()) {
+ EditorNode::get_singleton()->save_scene_list(scenes_to_save);
+ }
+
_update_script_names();
EditorFileSystem::get_singleton()->update_script_classes();
}
void ScriptEditor::apply_scripts() const {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -2503,14 +2589,14 @@ void ScriptEditor::open_text_file_create_dialog(const String &p_base_path, const
open_textfile_after_create = false;
}
-RES ScriptEditor::open_file(const String &p_file) {
+Ref<Resource> ScriptEditor::open_file(const String &p_file) {
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
if (extensions.find(p_file.get_extension())) {
Ref<Script> scr = ResourceLoader::load(p_file);
if (!scr.is_valid()) {
- editor->show_warning(TTR("Could not load file at:") + "\n\n" + p_file, TTR("Error!"));
- return RES();
+ EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + p_file, TTR("Error!"));
+ return Ref<Resource>();
}
edit(scr);
@@ -2520,20 +2606,20 @@ RES ScriptEditor::open_file(const String &p_file) {
Error error;
Ref<TextFile> text_file = _load_text_file(p_file, &error);
if (error != OK) {
- editor->show_warning(TTR("Could not load file at:") + "\n\n" + p_file, TTR("Error!"));
- return RES();
+ EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + p_file, TTR("Error!"));
+ return Ref<Resource>();
}
if (text_file.is_valid()) {
edit(text_file);
return text_file;
}
- return RES();
+ return Ref<Resource>();
}
void ScriptEditor::_editor_stop() {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -2547,10 +2633,10 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const
Ref<Script> script = p_obj->get_script();
ERR_FAIL_COND(!script.is_valid());
- editor->push_item(script.ptr());
+ EditorNode::get_singleton()->push_item(script.ptr());
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -2592,7 +2678,7 @@ void ScriptEditor::_save_layout() {
return;
}
- editor->save_layout();
+ EditorNode::get_singleton()->save_layout();
}
void ScriptEditor::_editor_settings_changed() {
@@ -2613,15 +2699,15 @@ void ScriptEditor::_editor_settings_changed() {
_update_autosave_timer();
- if (current_theme == "") {
+ if (current_theme.is_empty()) {
current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
} else if (current_theme != String(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))) {
current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
EditorSettings::get_singleton()->load_text_editor_theme();
}
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -2631,7 +2717,7 @@ void ScriptEditor::_editor_settings_changed() {
_update_script_colors();
_update_script_names();
- ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save", true));
+ ScriptServer::set_reload_scripts_on_save(EDITOR_GET("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save"));
}
void ScriptEditor::_filesystem_changed() {
@@ -2659,8 +2745,8 @@ void ScriptEditor::_files_moved(const String &p_old_file, const String &p_new_fi
}
void ScriptEditor::_file_removed(const String &p_removed_file) {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -2718,16 +2804,16 @@ void ScriptEditor::_tree_changed() {
call_deferred(SNAME("_update_script_connections"));
}
-void ScriptEditor::_script_split_dragged(float) {
+void ScriptEditor::_split_dragged(float) {
_save_layout();
}
Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
- if (tab_container->get_child_count() == 0) {
+ if (tab_container->get_tab_count() == 0) {
return Variant();
}
- Node *cur_node = tab_container->get_child(tab_container->get_current_tab());
+ Node *cur_node = tab_container->get_tab_control(tab_container->get_current_tab());
HBoxContainer *drag_preview = memnew(HBoxContainer);
String preview_name = "";
@@ -2747,6 +2833,7 @@ Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
if (!preview_icon.is_null()) {
TextureRect *tf = memnew(TextureRect);
tf->set_texture(preview_icon);
+ tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
drag_preview->add_child(tf);
}
Label *label = memnew(Label(preview_name));
@@ -2767,7 +2854,7 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (String(d["type"]) == "script_list_element") {
- Node *node = d["script_list_element"];
+ Node *node = Object::cast_to<Node>(d["script_list_element"]);
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
if (se) {
@@ -2805,7 +2892,7 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data
for (int i = 0; i < files.size(); i++) {
String file = files[i];
- if (file == "" || !FileAccess::exists(file)) {
+ if (file.is_empty() || !FileAccess::exists(file)) {
continue;
}
if (ResourceLoader::exists(file, "Script")) {
@@ -2840,7 +2927,7 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
}
if (String(d["type"]) == "script_list_element") {
- Node *node = d["script_list_element"];
+ Node *node = Object::cast_to<Node>(d["script_list_element"]);
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
EditorHelp *eh = Object::cast_to<EditorHelp>(node);
@@ -2882,10 +2969,10 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
if (script_list->get_item_count() > 0) {
new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
}
- int num_tabs_before = tab_container->get_child_count();
+ int num_tabs_before = tab_container->get_tab_count();
for (int i = 0; i < files.size(); i++) {
String file = files[i];
- if (file == "" || !FileAccess::exists(file)) {
+ if (file.is_empty() || !FileAccess::exists(file)) {
continue;
}
@@ -2893,13 +2980,13 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
continue;
}
- RES res = open_file(file);
+ Ref<Resource> res = open_file(file);
if (res.is_valid()) {
- if (tab_container->get_child_count() > num_tabs_before) {
- tab_container->move_child(tab_container->get_child(tab_container->get_child_count() - 1), new_index);
- num_tabs_before = tab_container->get_child_count();
+ if (tab_container->get_tab_count() > num_tabs_before) {
+ tab_container->move_child(tab_container->get_tab_control(tab_container->get_tab_count() - 1), new_index);
+ num_tabs_before = tab_container->get_tab_count();
} else { /* Maybe script was already open */
- tab_container->move_child(tab_container->get_child(tab_container->get_current_tab()), new_index);
+ tab_container->move_child(tab_container->get_tab_control(tab_container->get_current_tab()), new_index);
}
}
}
@@ -2920,18 +3007,18 @@ void ScriptEditor::input(const Ref<InputEvent> &p_event) {
// This must be hardcoded as the editor shortcuts dialog doesn't allow assigning
// more than one shortcut per action.
if (mb.is_valid() && mb->is_pressed() && is_visible_in_tree()) {
- if (mb->get_button_index() == MOUSE_BUTTON_XBUTTON1) {
+ if (mb->get_button_index() == MouseButton::MB_XBUTTON1) {
_history_back();
}
- if (mb->get_button_index() == MOUSE_BUTTON_XBUTTON2) {
+ if (mb->get_button_index() == MouseButton::MB_XBUTTON2) {
_history_forward();
}
}
}
}
-void ScriptEditor::unhandled_key_input(const Ref<InputEvent> &p_event) {
+void ScriptEditor::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo()) {
@@ -2965,7 +3052,7 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid() && mb->is_pressed()) {
switch (mb->get_button_index()) {
- case MOUSE_BUTTON_MIDDLE: {
+ case MouseButton::MIDDLE: {
// Right-click selects automatically; middle-click does not.
int idx = script_list->get_item_at_position(mb->get_position(), true);
if (idx >= 0) {
@@ -2975,7 +3062,7 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
}
} break;
- case MOUSE_BUTTON_RIGHT: {
+ case MouseButton::RIGHT: {
_make_script_list_context_menu();
} break;
default:
@@ -2988,11 +3075,11 @@ void ScriptEditor::_make_script_list_context_menu() {
context_menu->clear();
int selected = tab_container->get_current_tab();
- if (selected < 0 || selected >= tab_container->get_child_count()) {
+ if (selected < 0 || selected >= tab_container->get_tab_count()) {
return;
}
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected));
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(selected));
if (se) {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save"), FILE_SAVE);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save_as"), FILE_SAVE_AS);
@@ -3020,13 +3107,19 @@ void ScriptEditor::_make_script_list_context_menu() {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_sort"), WINDOW_SORT);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/toggle_scripts_panel"), TOGGLE_SCRIPTS_PANEL);
- context_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_ALL), tab_container->get_tab_count() <= 0);
+ context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_OTHER_TABS), tab_container->get_tab_count() <= 1);
+ context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_MOVE_UP), tab_container->get_current_tab() <= 0);
+ context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_MOVE_DOWN), tab_container->get_current_tab() >= tab_container->get_tab_count() - 1);
+ context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_SORT), tab_container->get_tab_count() <= 1);
+
+ context_menu->set_position(get_screen_position() + get_local_mouse_position());
+ context_menu->reset_size();
context_menu->popup();
}
void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
- if (!bool(EDITOR_DEF("text_editor/behavior/files/restore_scripts_on_load", true))) {
+ if (!bool(EDITOR_GET("text_editor/behavior/files/restore_scripts_on_load"))) {
return;
}
@@ -3082,7 +3175,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
}
if (!script_info.is_empty()) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(tab_container->get_tab_count() - 1));
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(tab_container->get_tab_count() - 1));
if (se) {
se->set_edit_state(script_info["state"]);
}
@@ -3091,18 +3184,22 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
for (int i = 0; i < helps.size(); i++) {
String path = helps[i];
- if (path == "") { // invalid, skip
+ if (path.is_empty()) { // invalid, skip
continue;
}
_help_class_open(path);
}
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- tab_container->get_child(i)->set_meta("__editor_pass", Variant());
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ tab_container->get_tab_control(i)->set_meta("__editor_pass", Variant());
}
- if (p_layout->has_section_key("ScriptEditor", "split_offset")) {
- script_split->set_split_offset(p_layout->get_value("ScriptEditor", "split_offset"));
+ if (p_layout->has_section_key("ScriptEditor", "script_split_offset")) {
+ script_split->set_split_offset(p_layout->get_value("ScriptEditor", "script_split_offset"));
+ }
+
+ if (p_layout->has_section_key("ScriptEditor", "list_split_offset")) {
+ list_split->set_split_offset(p_layout->get_value("ScriptEditor", "list_split_offset"));
}
// Remove any deleted editors that have been removed between launches.
@@ -3134,8 +3231,8 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
Array scripts;
Array helps;
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se) {
String path = se->get_edited_resource()->get_path();
if (!path.is_resource_file()) {
@@ -3146,7 +3243,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
scripts.push_back(path);
}
- EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+ EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
if (eh) {
helps.push_back(eh->get_class());
@@ -3155,19 +3252,20 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
p_layout->set_value("ScriptEditor", "open_scripts", scripts);
p_layout->set_value("ScriptEditor", "open_help", helps);
- p_layout->set_value("ScriptEditor", "split_offset", script_split->get_split_offset());
+ p_layout->set_value("ScriptEditor", "script_split_offset", script_split->get_split_offset());
+ p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset());
// Save the cache.
script_editor_cache->save(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
}
void ScriptEditor::_help_class_open(const String &p_class) {
- if (p_class == "") {
+ if (p_class.is_empty()) {
return;
}
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
if (eh && eh->get_class() == p_class) {
_go_to_tab(i);
@@ -3192,15 +3290,8 @@ void ScriptEditor::_help_class_open(const String &p_class) {
void ScriptEditor::_help_class_goto(const String &p_desc) {
String cname = p_desc.get_slice(":", 1);
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
-
- if (eh && eh->get_class() == cname) {
- _go_to_tab(i);
- eh->go_to_help(p_desc);
- _update_script_names();
- return;
- }
+ if (_help_tab_goto(cname, p_desc)) {
+ return;
}
EditorHelp *eh = memnew(EditorHelp);
@@ -3214,13 +3305,29 @@ void ScriptEditor::_help_class_goto(const String &p_desc) {
_sort_list_on_update = true;
_update_script_names();
_save_layout();
+
+ call_deferred("_help_tab_goto", cname, p_desc);
+}
+
+bool ScriptEditor::_help_tab_goto(const String &p_name, const String &p_desc) {
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
+
+ if (eh && eh->get_class() == p_name) {
+ _go_to_tab(i);
+ eh->go_to_help(p_desc);
+ _update_script_names();
+ return true;
+ }
+ }
+ return false;
}
void ScriptEditor::update_doc(const String &p_name) {
ERR_FAIL_COND(!EditorHelp::get_doc_data()->has_doc(p_name));
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
if (eh && eh->get_class() == p_name) {
eh->update_doc();
return;
@@ -3229,10 +3336,10 @@ void ScriptEditor::update_doc(const String &p_name) {
}
void ScriptEditor::_update_selected_editor_menu() {
- for (int i = 0; i < tab_container->get_child_count(); i++) {
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
bool current = tab_container->get_current_tab() == i;
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se && se->get_edit_menu()) {
if (current) {
se->get_edit_menu()->show();
@@ -3245,15 +3352,15 @@ void ScriptEditor::_update_selected_editor_menu() {
EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_current_tab_control());
script_search_menu->get_popup()->clear();
if (eh) {
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F), HELP_SEARCH_FIND);
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT);
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3), HELP_SEARCH_FIND_PREVIOUS);
+ script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KeyModifierMask::CMD | Key::F), HELP_SEARCH_FIND);
+ script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), Key::F3), HELP_SEARCH_FIND_NEXT);
+ script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KeyModifierMask::SHIFT | Key::F3), HELP_SEARCH_FIND_PREVIOUS);
script_search_menu->get_popup()->add_separator();
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES);
+ script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
script_search_menu->show();
} else {
- if (tab_container->get_child_count() == 0) {
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES);
+ if (tab_container->get_tab_count() == 0) {
+ script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
script_search_menu->show();
} else {
script_search_menu->hide();
@@ -3272,7 +3379,7 @@ void ScriptEditor::_update_history_pos(int p_new_pos) {
}
history_pos = p_new_pos;
- tab_container->set_current_tab(history[history_pos].control->get_index());
+ tab_container->set_current_tab(tab_container->get_tab_idx_from_control(history[history_pos].control));
n = history[history_pos].control;
@@ -3312,8 +3419,8 @@ void ScriptEditor::_history_back() {
Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
Vector<Ref<Script>> out_scripts = Vector<Ref<Script>>();
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -3329,8 +3436,8 @@ Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
Array ScriptEditor::_get_open_script_editors() const {
Array script_editors;
- for (int i = 0; i < tab_container->get_child_count(); i++) {
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
continue;
}
@@ -3388,7 +3495,7 @@ void ScriptEditor::_open_script_request(const String &p_path) {
void ScriptEditor::register_syntax_highlighter(const Ref<EditorSyntaxHighlighter> &p_syntax_highlighter) {
ERR_FAIL_COND(p_syntax_highlighter.is_null());
- if (syntax_highlighters.find(p_syntax_highlighter) == -1) {
+ if (!syntax_highlighters.has(p_syntax_highlighter)) {
syntax_highlighters.push_back(p_syntax_highlighter);
}
}
@@ -3408,7 +3515,7 @@ void ScriptEditor::register_create_script_editor_function(CreateScriptEditorFunc
}
void ScriptEditor::_script_changed() {
- NodeDock::singleton->update_lists();
+ NodeDock::get_singleton()->update_lists();
}
void ScriptEditor::_on_find_in_files_requested(String text) {
@@ -3426,7 +3533,7 @@ void ScriptEditor::_on_replace_in_files_requested(String text) {
void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) {
if (ResourceLoader::exists(fpath)) {
- RES res = ResourceLoader::load(fpath);
+ Ref<Resource> res = ResourceLoader::load(fpath);
if (fpath.get_extension() == "gdshader") {
ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_singleton()->get_editor_data().get_editor("Shader"));
@@ -3434,6 +3541,9 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb
shader_editor->make_visible(true);
shader_editor->get_shader_editor()->goto_line_selection(line_number - 1, begin, end);
return;
+ } else if (fpath.get_extension() == "tscn") {
+ EditorNode::get_singleton()->load_scene(fpath);
+ return;
} else {
Ref<Script> script = res;
if (script.is_valid()) {
@@ -3474,7 +3584,7 @@ void ScriptEditor::_start_find_in_files(bool with_replace) {
find_in_files->set_replace_text(find_in_files_dialog->get_replace_text());
find_in_files->start_search();
- editor->make_bottom_panel_item_visible(find_in_files);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(find_in_files);
}
void ScriptEditor::_on_find_in_files_modified_files(PackedStringArray paths) {
@@ -3497,9 +3607,9 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2);
ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path);
- ClassDB::bind_method("_get_debug_tooltip", &ScriptEditor::_get_debug_tooltip);
ClassDB::bind_method("_update_script_connections", &ScriptEditor::_update_script_connections);
ClassDB::bind_method("_help_class_open", &ScriptEditor::_help_class_open);
+ ClassDB::bind_method("_help_tab_goto", &ScriptEditor::_help_tab_goto);
ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts);
ClassDB::bind_method("_update_members_overview", &ScriptEditor::_update_members_overview);
ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts);
@@ -3523,7 +3633,7 @@ void ScriptEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("script_close", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script")));
}
-ScriptEditor::ScriptEditor(EditorNode *p_editor) {
+ScriptEditor::ScriptEditor() {
current_theme = "";
script_editor_cache.instantiate();
@@ -3536,7 +3646,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
auto_reload_running_scripts = true;
members_overview_enabled = EditorSettings::get_singleton()->get("text_editor/script_list/show_members_overview");
help_overview_enabled = EditorSettings::get_singleton()->get("text_editor/help/show_help_index");
- editor = p_editor;
VBoxContainer *main_container = memnew(VBoxContainer);
add_child(main_container);
@@ -3634,13 +3743,13 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
find_replace_bar->hide();
ED_SHORTCUT("script_editor/window_sort", TTR("Sort"));
- ED_SHORTCUT("script_editor/window_move_up", TTR("Move Up"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_UP);
- ED_SHORTCUT("script_editor/window_move_down", TTR("Move Down"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_DOWN);
- // FIXME: These should be `KEY_GREATER` and `KEY_LESS` but those don't work.
- ED_SHORTCUT("script_editor/next_script", TTR("Next Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_PERIOD);
- ED_SHORTCUT("script_editor/prev_script", TTR("Previous Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_COMMA);
+ ED_SHORTCUT("script_editor/window_move_up", TTR("Move Up"), KeyModifierMask::SHIFT | KeyModifierMask::ALT | Key::UP);
+ ED_SHORTCUT("script_editor/window_move_down", TTR("Move Down"), KeyModifierMask::SHIFT | KeyModifierMask::ALT | Key::DOWN);
+ // FIXME: These should be `Key::GREATER` and `Key::LESS` but those don't work.
+ ED_SHORTCUT("script_editor/next_script", TTR("Next Script"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::PERIOD);
+ ED_SHORTCUT("script_editor/prev_script", TTR("Previous Script"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::COMMA);
set_process_input(true);
- set_process_unhandled_input(true);
+ set_process_shortcut_input(true);
file_menu = memnew(MenuButton);
file_menu->set_text(TTR("File"));
@@ -3648,10 +3757,10 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
file_menu->set_shortcut_context(this);
menu_hb->add_child(file_menu);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script...")), FILE_NEW);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File...")), FILE_NEW_TEXTFILE);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script..."), KeyModifierMask::CMD | Key::N), FILE_NEW);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::N), FILE_NEW_TEXTFILE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open...")), FILE_OPEN);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_T), FILE_REOPEN_CLOSED);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::T), FILE_REOPEN_CLOSED);
file_menu->get_popup()->add_submenu_item(TTR("Open Recent"), "RecentScripts", FILE_OPEN_RECENT);
recent_scripts = memnew(PopupMenu);
@@ -3661,17 +3770,17 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
_update_recent_scripts();
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KEY_MASK_ALT | KEY_MASK_CMD | KEY_S), FILE_SAVE);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KeyModifierMask::ALT | KeyModifierMask::CMD | Key::S), FILE_SAVE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KeyModifierMask::SHIFT | KeyModifierMask::ALT | Key::S), FILE_SAVE_ALL);
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_R), FILE_TOOL_RELOAD_SOFT);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KeyModifierMask::CMD | KeyModifierMask::ALT | Key::R), FILE_TOOL_RELOAD_SOFT);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/show_in_file_system", TTR("Show in FileSystem")), SHOW_IN_FILE_SYSTEM);
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Previous"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KEY_MASK_ALT | KEY_RIGHT), WINDOW_NEXT);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Previous"), KeyModifierMask::ALT | Key::LEFT), WINDOW_PREV);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KeyModifierMask::ALT | Key::RIGHT), WINDOW_NEXT);
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_submenu_item(TTR("Theme"), "Theme", FILE_THEME);
@@ -3688,17 +3797,18 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme_as", TTR("Save Theme As...")), THEME_SAVE_AS);
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KEY_MASK_CMD | KEY_W), FILE_CLOSE);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KeyModifierMask::CMD | Key::W), FILE_CLOSE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_all", TTR("Close All")), CLOSE_ALL);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_other_tabs", TTR("Close Other Tabs")), CLOSE_OTHER_TABS);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_docs", TTR("Close Docs")), CLOSE_DOCS);
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/run_file", TTR("Run"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_X), FILE_RUN);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/run_file", TTR("Run"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::X), FILE_RUN);
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_scripts_panel", TTR("Toggle Scripts Panel"), KEY_MASK_CMD | KEY_BACKSLASH), TOGGLE_SCRIPTS_PANEL);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_scripts_panel", TTR("Toggle Scripts Panel"), KeyModifierMask::CMD | Key::BACKSLASH), TOGGLE_SCRIPTS_PANEL);
file_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option));
+ file_menu->get_popup()->connect("about_to_popup", callable_mp(this, &ScriptEditor::_prepare_file_menu));
script_search_menu = memnew(MenuButton);
script_search_menu->set_text(TTR("Search"));
@@ -3825,7 +3935,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_REPLACE_REQUESTED, callable_mp(this, &ScriptEditor::_start_find_in_files), varray(true));
add_child(find_in_files_dialog);
find_in_files = memnew(FindInFilesPanel);
- find_in_files_button = editor->add_bottom_panel_item(TTR("Search Results"), find_in_files);
+ find_in_files_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Search Results"), find_in_files);
find_in_files->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
find_in_files->connect(FindInFilesPanel::SIGNAL_RESULT_SELECTED, callable_mp(this, &ScriptEditor::_on_find_in_files_result_selected));
find_in_files->connect(FindInFilesPanel::SIGNAL_FILES_MODIFIED, callable_mp(this, &ScriptEditor::_on_find_in_files_modified_files));
@@ -3841,8 +3951,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
ScriptServer::edit_request_func = _open_script_request;
- add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditorPanel"), SNAME("EditorStyles")));
- tab_container->add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditor"), SNAME("EditorStyles")));
+ add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditorPanel"), SNAME("EditorStyles")));
+ tab_container->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditor"), SNAME("EditorStyles")));
}
ScriptEditor::~ScriptEditor() {
@@ -3854,7 +3964,7 @@ void ScriptEditorPlugin::edit(Object *p_object) {
Script *p_script = Object::cast_to<Script>(p_object);
String res_path = p_script->get_path().get_slice("::", 0);
- if (p_script->is_built_in()) {
+ if (p_script->is_built_in() && !res_path.is_empty()) {
if (ResourceLoader::get_resource_type(res_path) == "PackedScene") {
if (!EditorNode::get_singleton()->is_scene_open(res_path)) {
EditorNode::get_singleton()->load_scene(res_path);
@@ -3926,15 +4036,14 @@ void ScriptEditorPlugin::edited_scene_changed() {
script_editor->edited_scene_changed();
}
-ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- script_editor = memnew(ScriptEditor(p_node));
- editor->get_main_control()->add_child(script_editor);
+ScriptEditorPlugin::ScriptEditorPlugin() {
+ script_editor = memnew(ScriptEditor);
+ EditorNode::get_singleton()->get_main_control()->add_child(script_editor);
script_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
script_editor->hide();
- EDITOR_DEF("text_editor/behavior/files/auto_reload_scripts_on_external_change", true);
+ EDITOR_GET("text_editor/behavior/files/auto_reload_scripts_on_external_change");
ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save", true));
EDITOR_DEF("text_editor/behavior/files/open_dominant_script_on_scene_change", true);
EDITOR_DEF("text_editor/external/use_external_editor", false);
@@ -3950,7 +4059,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
EDITOR_DEF("text_editor/external/exec_flags", "{file}");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_flags", PROPERTY_HINT_PLACEHOLDER_TEXT, "Call flags with placeholders: {project}, {file}, {col}, {line}."));
- ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_T);
+ ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::T);
ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Scripts"));
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 2b0bdfd109..41b311f745 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -47,11 +47,13 @@
#include "scene/main/timer.h"
#include "scene/resources/text_file.h"
+class EditorFileDialog;
+
class EditorSyntaxHighlighter : public SyntaxHighlighter {
GDCLASS(EditorSyntaxHighlighter, SyntaxHighlighter)
private:
- REF edited_resourse;
+ Ref<RefCounted> edited_resourse;
protected:
static void _bind_methods();
@@ -63,8 +65,8 @@ public:
virtual String _get_name() const;
virtual Array _get_supported_languages() const;
- void _set_edited_resource(const RES &p_res) { edited_resourse = p_res; }
- REF _get_edited_resource() { return edited_resourse; }
+ void _set_edited_resource(const Ref<Resource> &p_res) { edited_resourse = p_res; }
+ Ref<RefCounted> _get_edited_resource() { return edited_resourse; }
virtual Ref<EditorSyntaxHighlighter> _create() const;
};
@@ -100,8 +102,8 @@ public:
class ScriptEditorQuickOpen : public ConfirmationDialog {
GDCLASS(ScriptEditorQuickOpen, ConfirmationDialog);
- LineEdit *search_box;
- Tree *search_options;
+ LineEdit *search_box = nullptr;
+ Tree *search_options = nullptr;
String function;
void _update_search();
@@ -134,9 +136,9 @@ public:
virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) = 0;
virtual void apply_code() = 0;
- virtual RES get_edited_resource() const = 0;
+ virtual Ref<Resource> get_edited_resource() const = 0;
virtual Vector<String> get_functions() = 0;
- virtual void set_edited_resource(const RES &p_res) = 0;
+ virtual void set_edited_resource(const Ref<Resource> &p_res) = 0;
virtual void enable_editor() = 0;
virtual void reload_text() = 0;
virtual String get_name() = 0;
@@ -165,7 +167,7 @@ public:
virtual bool show_members_overview() = 0;
- virtual void set_tooltip_request_func(String p_method, Object *p_obj) = 0;
+ virtual void set_tooltip_request_func(const Callable &p_toolip_callback) = 0;
virtual Control *get_edit_menu() = 0;
virtual void clear_edit_menu() = 0;
virtual void set_find_replace_bar(FindReplaceBar *p_bar) = 0;
@@ -177,7 +179,7 @@ public:
ScriptEditorBase() {}
};
-typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const RES &p_resource);
+typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const Ref<Resource> &p_resource);
class EditorScriptCodeCompletionCache;
class FindInFilesDialog;
@@ -186,7 +188,6 @@ class FindInFilesPanel;
class ScriptEditor : public PanelContainer {
GDCLASS(ScriptEditor, PanelContainer);
- EditorNode *editor;
enum {
FILE_NEW,
FILE_NEW_TEXTFILE,
@@ -241,55 +242,55 @@ class ScriptEditor : public PanelContainer {
DISPLAY_FULL_PATH,
};
- HBoxContainer *menu_hb;
- MenuButton *file_menu;
- MenuButton *edit_menu;
- MenuButton *script_search_menu;
- MenuButton *debug_menu;
- PopupMenu *context_menu;
- Timer *autosave_timer;
- uint64_t idle;
-
- PopupMenu *recent_scripts;
- PopupMenu *theme_submenu;
-
- Button *help_search;
- Button *site_search;
- EditorHelpSearch *help_search_dialog;
-
- ItemList *script_list;
- HSplitContainer *script_split;
- ItemList *members_overview;
- LineEdit *filter_scripts;
- LineEdit *filter_methods;
- VBoxContainer *scripts_vbox;
- VBoxContainer *overview_vbox;
- HBoxContainer *buttons_hbox;
- Label *filename;
- Button *members_overview_alphabeta_sort_button;
+ HBoxContainer *menu_hb = nullptr;
+ MenuButton *file_menu = nullptr;
+ MenuButton *edit_menu = nullptr;
+ MenuButton *script_search_menu = nullptr;
+ MenuButton *debug_menu = nullptr;
+ PopupMenu *context_menu = nullptr;
+ Timer *autosave_timer = nullptr;
+ uint64_t idle = 0;
+
+ PopupMenu *recent_scripts = nullptr;
+ PopupMenu *theme_submenu = nullptr;
+
+ Button *help_search = nullptr;
+ Button *site_search = nullptr;
+ EditorHelpSearch *help_search_dialog = nullptr;
+
+ ItemList *script_list = nullptr;
+ HSplitContainer *script_split = nullptr;
+ ItemList *members_overview = nullptr;
+ LineEdit *filter_scripts = nullptr;
+ LineEdit *filter_methods = nullptr;
+ VBoxContainer *scripts_vbox = nullptr;
+ VBoxContainer *overview_vbox = nullptr;
+ HBoxContainer *buttons_hbox = nullptr;
+ Label *filename = nullptr;
+ Button *members_overview_alphabeta_sort_button = nullptr;
bool members_overview_enabled;
- ItemList *help_overview;
+ ItemList *help_overview = nullptr;
bool help_overview_enabled;
- VSplitContainer *list_split;
- TabContainer *tab_container;
- EditorFileDialog *file_dialog;
- AcceptDialog *error_dialog;
- ConfirmationDialog *erase_tab_confirm;
- ScriptCreateDialog *script_create_dialog;
- Button *scripts_visible;
- FindReplaceBar *find_replace_bar;
+ VSplitContainer *list_split = nullptr;
+ TabContainer *tab_container = nullptr;
+ EditorFileDialog *file_dialog = nullptr;
+ AcceptDialog *error_dialog = nullptr;
+ ConfirmationDialog *erase_tab_confirm = nullptr;
+ ScriptCreateDialog *script_create_dialog = nullptr;
+ Button *scripts_visible = nullptr;
+ FindReplaceBar *find_replace_bar = nullptr;
String current_theme;
- TextureRect *script_icon;
- Label *script_name_label;
+ TextureRect *script_icon = nullptr;
+ Label *script_name_label = nullptr;
- Button *script_back;
- Button *script_forward;
+ Button *script_back = nullptr;
+ Button *script_forward = nullptr;
- FindInFilesDialog *find_in_files_dialog;
- FindInFilesPanel *find_in_files;
- Button *find_in_files_button;
+ FindInFilesDialog *find_in_files_dialog = nullptr;
+ FindInFilesPanel *find_in_files = nullptr;
+ Button *find_in_files_button = nullptr;
enum {
SCRIPT_EDITOR_FUNC_MAX = 32,
@@ -315,9 +316,12 @@ class ScriptEditor : public PanelContainer {
void _menu_option(int p_option);
void _theme_option(int p_option);
void _show_save_theme_as_dialog();
+ bool _has_docs_tab() const;
+ bool _has_script_tab() const;
+ void _prepare_file_menu();
- Tree *disk_changed_list;
- ConfirmationDialog *disk_changed;
+ Tree *disk_changed_list = nullptr;
+ ConfirmationDialog *disk_changed = nullptr;
bool restoring_layout;
@@ -326,7 +330,7 @@ class ScriptEditor : public PanelContainer {
void _resave_scripts(const String &p_str);
void _reload_scripts();
- bool _test_script_times_on_disk(RES p_for_script = Ref<Resource>());
+ bool _test_script_times_on_disk(Ref<Resource> p_for_script = Ref<Resource>());
void _add_recent_script(String p_path);
void _update_recent_scripts();
@@ -357,7 +361,7 @@ class ScriptEditor : public PanelContainer {
void _update_selected_editor_menu();
- EditorScriptCodeCompletionCache *completion_cache;
+ EditorScriptCodeCompletionCache *completion_cache = nullptr;
void _editor_stop();
@@ -365,6 +369,7 @@ class ScriptEditor : public PanelContainer {
void _add_callback(Object *p_obj, const String &p_function, const PackedStringArray &p_args);
void _res_saved_callback(const Ref<Resource> &p_res);
+ void _scene_saved_callback(const String &p_path);
bool open_textfile_after_create = true;
bool trim_trailing_whitespace_on_save;
@@ -372,12 +377,12 @@ class ScriptEditor : public PanelContainer {
bool convert_indent_on_save;
void _goto_script_line2(int p_line);
- void _goto_script_line(REF p_script, int p_line);
- void _set_execution(REF p_script, int p_line);
- void _clear_execution(REF p_script);
+ void _goto_script_line(Ref<RefCounted> p_script, int p_line);
+ void _set_execution(Ref<RefCounted> p_script, int p_line);
+ void _clear_execution(Ref<RefCounted> p_script);
void _breaked(bool p_breaked, bool p_can_debug);
void _script_created(Ref<Script> p_script);
- void _set_breakpoint(REF p_scrpt, int p_line, bool p_enabled);
+ void _set_breakpoint(Ref<RefCounted> p_scrpt, int p_line, bool p_enabled);
void _clear_breakpoints();
Array _get_cached_breakpoints_for_script(const String &p_path) const;
@@ -414,14 +419,14 @@ class ScriptEditor : public PanelContainer {
void _tree_changed();
- void _script_split_dragged(float);
+ void _split_dragged(float);
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
virtual void input(const Ref<InputEvent> &p_event) override;
- virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _script_list_gui_input(const Ref<InputEvent> &ev);
void _make_script_list_context_menu();
@@ -435,6 +440,7 @@ class ScriptEditor : public PanelContainer {
void _help_class_open(const String &p_class);
void _help_class_goto(const String &p_desc);
+ bool _help_tab_goto(const String &p_name, const String &p_desc);
void _update_history_arrows();
void _save_history();
void _go_to_tab(int p_idx);
@@ -475,12 +481,12 @@ public:
void apply_scripts() const;
void open_script_create_dialog(const String &p_base_name, const String &p_base_path);
void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = "");
- RES open_file(const String &p_file);
+ Ref<Resource> open_file(const String &p_file);
void ensure_select_current();
- _FORCE_INLINE_ bool edit(const RES &p_resource, bool p_grab_focus = true) { return edit(p_resource, -1, 0, p_grab_focus); }
- bool edit(const RES &p_resource, int p_line, int p_col, bool p_grab_focus = true);
+ _FORCE_INLINE_ bool edit(const Ref<Resource> &p_resource, bool p_grab_focus = true) { return edit(p_resource, -1, 0, p_grab_focus); }
+ bool edit(const Ref<Resource> &p_resource, int p_line, int p_col, bool p_grab_focus = true);
void get_breakpoints(List<String> *p_breakpoints);
@@ -516,15 +522,14 @@ public:
static void register_create_script_editor_function(CreateScriptEditorFunc p_func);
- ScriptEditor(EditorNode *p_editor);
+ ScriptEditor();
~ScriptEditor();
};
class ScriptEditorPlugin : public EditorPlugin {
GDCLASS(ScriptEditorPlugin, EditorPlugin);
- ScriptEditor *script_editor;
- EditorNode *editor;
+ ScriptEditor *script_editor = nullptr;
public:
virtual String get_name() const override { return "Script"; }
@@ -547,7 +552,7 @@ public:
virtual void edited_scene_changed() override;
- ScriptEditorPlugin(EditorNode *p_node);
+ ScriptEditorPlugin();
~ScriptEditorPlugin();
};
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 24cdc06d78..981881fb9b 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,7 @@
#include "script_text_editor.h"
+#include "core/config/project_settings.h"
#include "core/math/expression.h"
#include "core/os/keyboard.h"
#include "editor/debugger/editor_debugger_node.h"
@@ -90,7 +91,7 @@ ConnectionInfoDialog::ConnectionInfoDialog() {
add_child(vbc);
method = memnew(Label);
- method->set_align(Label::ALIGN_CENTER);
+ method->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
vbc->add_child(method);
tree = memnew(Tree);
@@ -132,11 +133,11 @@ void ScriptTextEditor::apply_code() {
code_editor->get_text_editor()->get_syntax_highlighter()->update_cache();
}
-RES ScriptTextEditor::get_edited_resource() const {
+Ref<Resource> ScriptTextEditor::get_edited_resource() const {
return script;
}
-void ScriptTextEditor::set_edited_resource(const RES &p_res) {
+void ScriptTextEditor::set_edited_resource(const Ref<Resource> &p_res) {
ERR_FAIL_COND(script.is_valid());
ERR_FAIL_COND(p_res.is_null());
@@ -205,7 +206,7 @@ void ScriptTextEditor::_set_theme_for_script() {
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
if (!text_edit->has_string_delimiter(beg)) {
- text_edit->add_string_delimiter(beg, end, end == "");
+ text_edit->add_string_delimiter(beg, end, end.is_empty());
}
if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) {
@@ -219,7 +220,7 @@ void ScriptTextEditor::_set_theme_for_script() {
for (const String &comment : comments) {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
- text_edit->add_comment_delimiter(beg, end, end == "");
+ text_edit->add_comment_delimiter(beg, end, end.is_empty());
if (!end.is_empty() && !text_edit->has_auto_brace_completion_open_key(beg)) {
text_edit->add_auto_brace_completion_pair(beg, end);
@@ -240,7 +241,26 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) {
goto_line_centered(p_line.operator int64_t());
} else if (p_line.get_type() == Variant::DICTIONARY) {
Dictionary meta = p_line.operator Dictionary();
- code_editor->get_text_editor()->insert_line_at(meta["line"].operator int64_t() - 1, "# warning-ignore:" + meta["code"].operator String());
+ const int line = meta["line"].operator int64_t() - 1;
+
+ CodeEdit *text_editor = code_editor->get_text_editor();
+ String prev_line = line > 0 ? text_editor->get_line(line - 1) : "";
+ if (prev_line.contains("@warning_ignore")) {
+ const int closing_bracket_idx = prev_line.find(")");
+ const String text_to_insert = ", " + meta["code"].operator String();
+ prev_line = prev_line.insert(closing_bracket_idx, text_to_insert);
+ text_editor->set_line(line - 1, prev_line);
+ } else {
+ const int indent = text_editor->get_indent_level(line) / text_editor->get_indent_size();
+ String annotation_indent;
+ if (!text_editor->is_indent_using_spaces()) {
+ annotation_indent = String("\t").repeat(indent);
+ } else {
+ annotation_indent = String(" ").repeat(text_editor->get_indent_size() * indent);
+ }
+ text_editor->insert_line_at(line, annotation_indent + "@warning_ignore(" + meta["code"].operator String() + ")");
+ }
+
_validate_script();
}
}
@@ -375,26 +395,38 @@ void ScriptTextEditor::ensure_focus() {
String ScriptTextEditor::get_name() {
String name;
- if (!script->is_built_in()) {
- name = script->get_path().get_file();
- if (is_unsaved()) {
- if (script->get_path().is_empty()) {
- name = TTR("[unsaved]");
- }
- name += "(*)";
+ name = script->get_path().get_file();
+ if (name.is_empty()) {
+ // This appears for newly created built-in scripts before saving the scene.
+ name = TTR("[unsaved]");
+ } else if (script->is_built_in()) {
+ const String &script_name = script->get_name();
+ if (!script_name.is_empty()) {
+ // If the built-in script has a custom resource name defined,
+ // display the built-in script name as follows: `ResourceName (scene_file.tscn)`
+ name = vformat("%s (%s)", script_name, name.get_slice("::", 0));
}
- } else if (script->get_name() != "") {
- name = script->get_name();
- } else {
- name = script->get_class() + "(" + itos(script->get_instance_id()) + ")";
+ }
+
+ if (is_unsaved()) {
+ name += "(*)";
}
return name;
}
Ref<Texture2D> ScriptTextEditor::get_theme_icon() {
- if (get_parent_control() && get_parent_control()->has_theme_icon(script->get_class(), "EditorIcons")) {
- return get_parent_control()->get_theme_icon(script->get_class(), "EditorIcons");
+ if (get_parent_control()) {
+ String icon_name = script->get_class();
+ if (script->is_built_in()) {
+ icon_name += "Internal";
+ }
+
+ if (get_parent_control()->has_theme_icon(icon_name, SNAME("EditorIcons"))) {
+ return get_parent_control()->get_theme_icon(icon_name, SNAME("EditorIcons"));
+ } else if (get_parent_control()->has_theme_icon(script->get_class(), SNAME("EditorIcons"))) {
+ return get_parent_control()->get_theme_icon(script->get_class(), SNAME("EditorIcons"));
+ }
}
return Ref<Texture2D>();
@@ -405,12 +437,14 @@ void ScriptTextEditor::_validate_script() {
String text = te->get_text();
List<String> fnc;
- Set<int> safe_lines;
- List<ScriptLanguage::Warning> warnings;
- List<ScriptLanguage::ScriptError> errors;
+
+ warnings.clear();
+ errors.clear();
+ safe_lines.clear();
if (!script->get_language()->validate(text, script->get_path(), &fnc, &errors, &warnings, &safe_lines)) {
- String error_text = TTR("Error at ") + "(" + itos(errors[0].line) + "," + itos(errors[0].column) + "): " + errors[0].message;
+ // TRANSLATORS: Script error pointing to a line and column number.
+ String error_text = vformat(TTR("Error at (%d, %d):"), errors[0].line, errors[0].column) + " " + errors[0].message;
code_editor->set_error(error_text);
code_editor->set_error_pos(errors[0].line - 1, errors[0].column - 1);
script_is_valid = false;
@@ -429,7 +463,14 @@ void ScriptTextEditor::_validate_script() {
script_is_valid = true;
}
_update_connected_methods();
+ _update_warnings();
+ _update_errors();
+
+ emit_signal(SNAME("name_changed"));
+ emit_signal(SNAME("edited_script_changed"));
+}
+void ScriptTextEditor::_update_warnings() {
int warning_nb = warnings.size();
warnings_panel->clear();
@@ -457,7 +498,6 @@ void ScriptTextEditor::_validate_script() {
}
}
- code_editor->set_error_count(errors.size());
code_editor->set_warning_count(warning_nb);
if (has_connections_table) {
@@ -473,7 +513,7 @@ void ScriptTextEditor::_validate_script() {
warnings_panel->push_cell();
warnings_panel->push_meta(ignore_meta);
warnings_panel->push_color(
- warnings_panel->get_theme_color(SNAME("accent_color"), SNAME("Editor")).lerp(warnings_panel->get_theme_color(SNAME("mono_color"), SNAME("Editor")), 0.5));
+ warnings_panel->get_theme_color(SNAME("accent_color"), SNAME("Editor")).lerp(warnings_panel->get_theme_color(SNAME("mono_color"), SNAME("Editor")), 0.5f));
warnings_panel->add_text(TTR("[Ignore]"));
warnings_panel->pop(); // Color.
warnings_panel->pop(); // Meta ignore.
@@ -493,6 +533,10 @@ void ScriptTextEditor::_validate_script() {
warnings_panel->pop(); // Cell.
}
warnings_panel->pop(); // Table.
+}
+
+void ScriptTextEditor::_update_errors() {
+ code_editor->set_error_count(errors.size());
errors_panel->clear();
errors_panel->push_table(2);
@@ -511,7 +555,8 @@ void ScriptTextEditor::_validate_script() {
}
errors_panel->pop(); // Table
- bool highlight_safe = EDITOR_DEF("text_editor/appearance/gutters/highlight_type_safe_lines", true);
+ CodeEdit *te = code_editor->get_text_editor();
+ bool highlight_safe = EDITOR_GET("text_editor/appearance/gutters/highlight_type_safe_lines");
bool last_is_safe = false;
for (int i = 0; i < te->get_line_count(); i++) {
if (errors.is_empty()) {
@@ -540,14 +585,11 @@ void ScriptTextEditor::_validate_script() {
te->set_line_gutter_item_color(i, 1, default_line_number_color);
}
}
-
- emit_signal(SNAME("name_changed"));
- emit_signal(SNAME("edited_script_changed"));
}
void ScriptTextEditor::_update_bookmark_list() {
bookmarks_menu->clear();
- bookmarks_menu->set_size(Size2(1, 1));
+ bookmarks_menu->reset_size();
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL);
@@ -572,7 +614,7 @@ void ScriptTextEditor::_update_bookmark_list() {
}
bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - `" + line + "`");
- bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]);
+ bookmarks_menu->set_item_metadata(-1, bookmark_list[i]);
}
}
@@ -677,12 +719,12 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo
}
}
-void ScriptTextEditor::_code_complete_scripts(void *p_ud, const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force) {
+void ScriptTextEditor::_code_complete_scripts(void *p_ud, const String &p_code, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_force) {
ScriptTextEditor *ste = (ScriptTextEditor *)p_ud;
ste->_code_complete_script(p_code, r_options, r_force);
}
-void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force) {
+void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_force) {
if (color_panel->is_visible()) {
return;
}
@@ -692,6 +734,9 @@ void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCo
}
String hint;
Error err = script->get_language()->complete_code(p_code, script->get_path(), base, r_options, r_force, hint);
+
+ r_options->sort_custom_inplace<CodeCompletionOptionCompare>();
+
if (err == OK) {
code_editor->get_text_editor()->set_code_hint(hint);
}
@@ -699,7 +744,7 @@ void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCo
void ScriptTextEditor::_update_breakpoint_list() {
breakpoints_menu->clear();
- breakpoints_menu->set_size(Size2(1, 1));
+ breakpoints_menu->reset_size();
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_breakpoint"), DEBUG_TOGGLE_BREAKPOINT);
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_breakpoints"), DEBUG_REMOVE_ALL_BREAKPOINTS);
@@ -724,7 +769,7 @@ void ScriptTextEditor::_update_breakpoint_list() {
}
breakpoints_menu->add_item(String::num((int)breakpoint_list[i] + 1) + " - `" + line + "`");
- breakpoints_menu->set_item_metadata(breakpoints_menu->get_item_count() - 1, breakpoint_list[i]);
+ breakpoints_menu->set_item_metadata(-1, breakpoint_list[i]);
}
}
@@ -764,7 +809,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
_goto_line(p_row);
switch (result.type) {
- case ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION: {
+ case ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION: {
if (result.script.is_valid()) {
emit_signal(SNAME("request_open_script_at_line"), result.script, result.location - 1);
} else {
@@ -772,10 +817,10 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
goto_line_centered(result.location - 1);
}
} break;
- case ScriptLanguage::LookupResult::RESULT_CLASS: {
+ case ScriptLanguage::LOOKUP_RESULT_CLASS: {
emit_signal(SNAME("go_to_help"), "class_name:" + result.class_name);
} break;
- case ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT: {
+ case ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT: {
StringName cname = result.class_name;
bool success;
while (true) {
@@ -791,11 +836,11 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal(SNAME("go_to_help"), "class_constant:" + result.class_name + ":" + result.class_member);
} break;
- case ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY: {
+ case ScriptLanguage::LOOKUP_RESULT_CLASS_PROPERTY: {
emit_signal(SNAME("go_to_help"), "class_property:" + result.class_name + ":" + result.class_member);
} break;
- case ScriptLanguage::LookupResult::RESULT_CLASS_METHOD: {
+ case ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD: {
StringName cname = result.class_name;
while (true) {
@@ -810,7 +855,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal(SNAME("go_to_help"), "class_method:" + result.class_name + ":" + result.class_member);
} break;
- case ScriptLanguage::LookupResult::RESULT_CLASS_ENUM: {
+ case ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM: {
StringName cname = result.class_name;
StringName success;
while (true) {
@@ -826,9 +871,11 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal(SNAME("go_to_help"), "class_enum:" + result.class_name + ":" + result.class_member);
} break;
- case ScriptLanguage::LookupResult::RESULT_CLASS_TBD_GLOBALSCOPE: {
+ case ScriptLanguage::LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE: {
emit_signal(SNAME("go_to_help"), "class_global:" + result.class_name + ":" + result.class_member);
} break;
+ default: {
+ }
}
} else if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) {
// Check for Autoload scenes.
@@ -924,21 +971,22 @@ void ScriptTextEditor::_update_connected_methods() {
continue;
}
- if (methods_found.has(connection.callable.get_method())) {
+ const StringName method = connection.callable.get_method();
+ if (methods_found.has(method)) {
continue;
}
- if (!ClassDB::has_method(script->get_instance_base_type(), connection.callable.get_method())) {
+ if (!ClassDB::has_method(script->get_instance_base_type(), method)) {
int line = -1;
for (int j = 0; j < functions.size(); j++) {
String name = functions[j].get_slice(":", 0);
- if (name == connection.callable.get_method()) {
+ if (name == method) {
line = functions[j].get_slice(":", 1).to_int() - 1;
- text_edit->set_line_gutter_metadata(line, connection_gutter, connection.callable.get_method());
+ text_edit->set_line_gutter_metadata(line, connection_gutter, method);
text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon(SNAME("Slot"), SNAME("EditorIcons")));
text_edit->set_line_gutter_clickable(line, connection_gutter, true);
- methods_found.insert(connection.callable.get_method());
+ methods_found.insert(method);
break;
}
}
@@ -951,7 +999,7 @@ void ScriptTextEditor::_update_connected_methods() {
bool found_inherited_function = false;
Ref<Script> inherited_script = script->get_base_script();
while (!inherited_script.is_null()) {
- if (inherited_script->has_method(connection.callable.get_method())) {
+ if (inherited_script->has_method(method)) {
found_inherited_function = true;
break;
}
@@ -987,7 +1035,7 @@ void ScriptTextEditor::_gutter_clicked(int p_line, int p_gutter) {
}
String method = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter);
- if (method == "") {
+ if (method.is_empty()) {
return;
}
@@ -1134,7 +1182,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() == "") {
+ if (expression.get_error_text().is_empty()) {
results.push_back(whitespace + result.get_construct_string());
} else {
results.push_back(line);
@@ -1260,19 +1308,19 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case HELP_CONTEXTUAL: {
String text = tx->get_selected_text();
- if (text == "") {
+ if (text.is_empty()) {
text = tx->get_word_under_caret();
}
- if (text != "") {
+ if (!text.is_empty()) {
emit_signal(SNAME("request_help"), text);
}
} break;
case LOOKUP_SYMBOL: {
String text = tx->get_word_under_caret();
- if (text == "") {
+ if (text.is_empty()) {
text = tx->get_selected_text();
}
- if (text != "") {
+ if (!text.is_empty()) {
_lookup_symbol(text, tx->get_caret_line(), tx->get_caret_column());
}
} break;
@@ -1289,7 +1337,7 @@ void ScriptTextEditor::_edit_option_toggle_inline_comment() {
script->get_language()->get_comment_delimiters(&comment_delimiters);
for (const String &script_delimiter : comment_delimiters) {
- if (script_delimiter.find(" ") == -1) {
+ if (!script_delimiter.contains(" ")) {
delimiter = script_delimiter;
break;
}
@@ -1327,11 +1375,17 @@ void ScriptTextEditor::_change_syntax_highlighter(int p_idx) {
void ScriptTextEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
+ if (!editor_enabled) {
+ break;
+ }
+ if (is_visible_in_tree()) {
+ _update_warnings();
+ _update_errors();
+ }
+ [[fallthrough]];
case NOTIFICATION_ENTER_TREE: {
code_editor->get_text_editor()->set_gutter_width(connection_gutter, code_editor->get_text_editor()->get_line_height());
} break;
- default:
- break;
}
}
@@ -1362,7 +1416,7 @@ void ScriptTextEditor::reload(bool p_soft) {
return;
}
scr->set_source_code(te->get_text());
- bool soft = p_soft || scr->get_instance_base_type() == "EditorPlugin"; //always soft-reload editor plugins
+ bool soft = p_soft || scr->get_instance_base_type() == "EditorPlugin"; // Always soft-reload editor plugins.
scr->get_language()->reload_tool_script(scr, soft);
}
@@ -1379,8 +1433,10 @@ void ScriptTextEditor::clear_breakpoints() {
code_editor->get_text_editor()->clear_breakpointed_lines();
}
-void ScriptTextEditor::set_tooltip_request_func(String p_method, Object *p_obj) {
- code_editor->get_text_editor()->set_tooltip_request_func(p_obj, p_method, this);
+void ScriptTextEditor::set_tooltip_request_func(const Callable &p_toolip_callback) {
+ Variant args[1] = { this };
+ const Variant *argp[] = { &args[0] };
+ code_editor->get_text_editor()->set_tooltip_request_func(p_toolip_callback.bind(argp, 1));
}
void ScriptTextEditor::set_debugger_active(bool p_active) {
@@ -1459,7 +1515,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
Array files = d["files"];
String text_to_drop;
- bool preload = Input::get_singleton()->is_key_pressed(KEY_CTRL);
+ bool preload = Input::get_singleton()->is_key_pressed(Key::CTRL);
for (int i = 0; i < files.size(); i++) {
if (i > 0) {
text_to_drop += ", ";
@@ -1523,7 +1579,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
bool create_menu = false;
CodeEdit *tx = code_editor->get_text_editor();
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
local_pos = mb->get_global_position() - tx->get_global_position();
create_menu = true;
} else if (k.is_valid() && k->is_action("ui_menu", true)) {
@@ -1557,10 +1613,10 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
}
String word_at_pos = tx->get_word_at_pos(local_pos);
- if (word_at_pos == "") {
+ if (word_at_pos.is_empty()) {
word_at_pos = tx->get_word_under_caret();
}
- if (word_at_pos == "") {
+ if (word_at_pos.is_empty()) {
word_at_pos = tx->get_selected_text();
}
@@ -1608,7 +1664,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
float alpha = color.size() > 3 ? color[3] : 1.0f;
color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha));
}
- color_panel->set_position(get_global_transform().xform(local_pos));
+ color_panel->set_position(get_screen_position() + local_pos);
} else {
has_color = false;
}
@@ -1626,10 +1682,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) {
}
String line = code_editor->get_text_editor()->get_line(color_position.x);
- int color_args_pos = line.find(color_args, color_position.y);
- String line_with_replaced_args = line;
- line_with_replaced_args.erase(color_args_pos, color_args.length());
- line_with_replaced_args = line_with_replaced_args.insert(color_args_pos, new_args);
+ String line_with_replaced_args = line.replace(color_args, new_args);
color_args = new_args;
code_editor->get_text_editor()->begin_complex_operation();
@@ -1688,8 +1741,8 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
context_menu->set_item_disabled(context_menu->get_item_index(EDIT_UNDO), !tx->has_undo());
context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo());
- context_menu->set_position(get_global_transform().xform(p_pos));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->set_position(get_screen_position() + p_pos);
+ context_menu->reset_size();
context_menu->popup();
}
@@ -1804,9 +1857,9 @@ void ScriptTextEditor::_enable_code_editor() {
edit_menu->get_popup()->add_child(convert_case);
edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case");
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KEY_MASK_SHIFT | KEY_F4), EDIT_TO_UPPERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KEY_MASK_SHIFT | KEY_F5), EDIT_TO_LOWERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KEY_MASK_SHIFT | KEY_F6), EDIT_CAPITALIZE);
+ convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
+ convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
+ convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_child(highlighter_menu);
@@ -1945,7 +1998,7 @@ ScriptTextEditor::~ScriptTextEditor() {
}
}
-static ScriptEditorBase *create_editor(const RES &p_resource) {
+static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
if (Object::cast_to<Script>(*p_resource)) {
return memnew(ScriptTextEditor);
}
@@ -1953,60 +2006,60 @@ static ScriptEditorBase *create_editor(const RES &p_resource) {
}
void ScriptTextEditor::register_editor() {
- ED_SHORTCUT("script_text_editor/move_up", TTR("Move Up"), KEY_MASK_ALT | KEY_UP);
- ED_SHORTCUT("script_text_editor/move_down", TTR("Move Down"), KEY_MASK_ALT | KEY_DOWN);
- ED_SHORTCUT("script_text_editor/delete_line", TTR("Delete Line"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K);
+ ED_SHORTCUT("script_text_editor/move_up", TTR("Move Up"), KeyModifierMask::ALT | Key::UP);
+ ED_SHORTCUT("script_text_editor/move_down", TTR("Move Down"), KeyModifierMask::ALT | Key::DOWN);
+ ED_SHORTCUT("script_text_editor/delete_line", TTR("Delete Line"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::K);
// Leave these at zero, same can be accomplished with tab/shift-tab, including selection.
// The next/previous in history shortcut in this case makes a lot more sense.
- ED_SHORTCUT("script_text_editor/indent_left", TTR("Indent Left"), KEY_NONE);
- ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), KEY_NONE);
- ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD | KEY_K);
- ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KEY_MASK_ALT | KEY_F);
- ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), KEY_NONE);
- ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), KEY_NONE);
- ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_D);
- ED_SHORTCUT_OVERRIDE("script_text_editor/duplicate_selection", "macos", KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C);
- ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_E);
- ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_T);
- ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Y);
- ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_I);
- ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD | KEY_I);
+ ED_SHORTCUT("script_text_editor/indent_left", TTR("Indent Left"), Key::NONE);
+ ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), Key::NONE);
+ ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KeyModifierMask::CMD | Key::K);
+ ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KeyModifierMask::ALT | Key::F);
+ ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), Key::NONE);
+ ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), Key::NONE);
+ ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::D);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/duplicate_selection", "macos", KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::C);
+ ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::E);
+ ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KeyModifierMask::CMD | KeyModifierMask::ALT | Key::T);
+ ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::Y);
+ ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::I);
+ ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KeyModifierMask::CMD | Key::I);
- ED_SHORTCUT_AND_COMMAND("script_text_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F);
+ ED_SHORTCUT_AND_COMMAND("script_text_editor/find", TTR("Find..."), KeyModifierMask::CMD | Key::F);
- ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_F3);
- ED_SHORTCUT_OVERRIDE("script_text_editor/find_next", "macos", KEY_MASK_CMD | KEY_G);
+ ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), Key::F3);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/find_next", "macos", KeyModifierMask::CMD | Key::G);
- ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3);
- ED_SHORTCUT_OVERRIDE("script_text_editor/find_previous", "macos", KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G);
+ ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KeyModifierMask::SHIFT | Key::F3);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/find_previous", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G);
- ED_SHORTCUT_AND_COMMAND("script_text_editor/replace", TTR("Replace..."), KEY_MASK_CMD | KEY_R);
- ED_SHORTCUT_OVERRIDE("script_text_editor/replace", "macos", KEY_MASK_ALT | KEY_MASK_CMD | KEY_F);
+ ED_SHORTCUT_AND_COMMAND("script_text_editor/replace", TTR("Replace..."), KeyModifierMask::CMD | Key::R);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/replace", "macos", KeyModifierMask::ALT | KeyModifierMask::CMD | Key::F);
- ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F);
- ED_SHORTCUT("script_text_editor/replace_in_files", TTR("Replace in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R);
+ ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in Files..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F);
+ ED_SHORTCUT("script_text_editor/replace_in_files", TTR("Replace in Files..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::R);
- ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_ALT | KEY_F1);
- ED_SHORTCUT_OVERRIDE("script_text_editor/contextual_help", "macos", KEY_MASK_ALT | KEY_MASK_SHIFT | KEY_SPACE);
+ ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KeyModifierMask::ALT | Key::F1);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/contextual_help", "macos", KeyModifierMask::ALT | KeyModifierMask::SHIFT | Key::SPACE);
- ED_SHORTCUT("script_text_editor/toggle_bookmark", TTR("Toggle Bookmark"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_B);
- ED_SHORTCUT("script_text_editor/goto_next_bookmark", TTR("Go to Next Bookmark"), KEY_MASK_CMD | KEY_B);
- ED_SHORTCUT("script_text_editor/goto_previous_bookmark", TTR("Go to Previous Bookmark"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B);
- ED_SHORTCUT("script_text_editor/remove_all_bookmarks", TTR("Remove All Bookmarks"), KEY_NONE);
+ ED_SHORTCUT("script_text_editor/toggle_bookmark", TTR("Toggle Bookmark"), KeyModifierMask::CMD | KeyModifierMask::ALT | Key::B);
+ ED_SHORTCUT("script_text_editor/goto_next_bookmark", TTR("Go to Next Bookmark"), KeyModifierMask::CMD | Key::B);
+ ED_SHORTCUT("script_text_editor/goto_previous_bookmark", TTR("Go to Previous Bookmark"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::B);
+ ED_SHORTCUT("script_text_editor/remove_all_bookmarks", TTR("Remove All Bookmarks"), Key::NONE);
- ED_SHORTCUT("script_text_editor/goto_function", TTR("Go to Function..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F);
- ED_SHORTCUT_OVERRIDE("script_text_editor/goto_function", "macos", KEY_MASK_CTRL | KEY_MASK_CMD | KEY_J);
+ ED_SHORTCUT("script_text_editor/goto_function", TTR("Go to Function..."), KeyModifierMask::ALT | KeyModifierMask::CMD | Key::F);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/goto_function", "macos", KeyModifierMask::CTRL | KeyModifierMask::CMD | Key::J);
- ED_SHORTCUT("script_text_editor/goto_line", TTR("Go to Line..."), KEY_MASK_CMD | KEY_L);
+ ED_SHORTCUT("script_text_editor/goto_line", TTR("Go to Line..."), KeyModifierMask::CMD | Key::L);
- ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
- ED_SHORTCUT_OVERRIDE("script_text_editor/toggle_breakpoint", "macos", KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B);
+ ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), Key::F9);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/toggle_breakpoint", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::B);
- ED_SHORTCUT("script_text_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F9);
- ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Go to Next Breakpoint"), KEY_MASK_CMD | KEY_PERIOD);
- ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Go to Previous Breakpoint"), KEY_MASK_CMD | KEY_COMMA);
+ ED_SHORTCUT("script_text_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F9);
+ ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Go to Next Breakpoint"), KeyModifierMask::CMD | Key::PERIOD);
+ ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Go to Previous Breakpoint"), KeyModifierMask::CMD | Key::COMMA);
ScriptEditor::register_create_script_editor_function(create_editor);
}
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index afe9a7453d..b3e0c28bb1 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -62,6 +62,9 @@ class ScriptTextEditor : public ScriptEditorBase {
bool editor_enabled = false;
Vector<String> functions;
+ List<ScriptLanguage::Warning> warnings;
+ List<ScriptLanguage::ScriptError> errors;
+ Set<int> safe_lines;
List<Connection> missing_connections;
@@ -154,11 +157,13 @@ protected:
void _breakpoint_toggled(int p_row);
void _validate_script(); // No longer virtual.
+ void _update_warnings();
+ void _update_errors();
void _update_bookmark_list();
void _bookmark_item_pressed(int p_idx);
- static void _code_complete_scripts(void *p_ud, const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force);
- void _code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force);
+ static void _code_complete_scripts(void *p_ud, const String &p_code, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_force);
+ void _code_complete_script(const String &p_code, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_force);
void _load_theme_settings();
void _set_theme_for_script();
@@ -200,8 +205,8 @@ public:
void update_toggle_scripts_button() override;
virtual void apply_code() override;
- virtual RES get_edited_resource() const override;
- virtual void set_edited_resource(const RES &p_res) override;
+ virtual Ref<Resource> get_edited_resource() const override;
+ virtual void set_edited_resource(const Ref<Resource> &p_res) override;
virtual void enable_editor() override;
virtual Vector<String> get_functions() override;
virtual void reload_text() override;
@@ -233,7 +238,7 @@ public:
virtual bool show_members_overview() override;
- virtual void set_tooltip_request_func(String p_method, Object *p_obj) override;
+ virtual void set_tooltip_request_func(const Callable &p_toolip_callback) override;
virtual void set_debugger_active(bool p_active) override;
@@ -251,4 +256,51 @@ public:
~ScriptTextEditor();
};
+const int KIND_COUNT = 10;
+// The order in which to sort code completion options.
+const ScriptLanguage::CodeCompletionKind KIND_SORT_ORDER[KIND_COUNT] = {
+ ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE,
+ ScriptLanguage::CODE_COMPLETION_KIND_MEMBER,
+ ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION,
+ ScriptLanguage::CODE_COMPLETION_KIND_ENUM,
+ ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL,
+ ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT,
+ ScriptLanguage::CODE_COMPLETION_KIND_CLASS,
+ ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH,
+ ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH,
+ ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT,
+};
+
+// The custom comparer which will sort completion options.
+struct CodeCompletionOptionCompare {
+ _FORCE_INLINE_ bool operator()(const ScriptLanguage::CodeCompletionOption &l, const ScriptLanguage::CodeCompletionOption &r) const {
+ if (l.location == r.location) {
+ // If locations are same, sort on kind
+ if (l.kind == r.kind) {
+ // If kinds are same, sort alphanumeric
+ return l.display < r.display;
+ }
+
+ // Sort kinds based on the const sorting array defined above. Lower index = higher priority.
+ int l_index = -1;
+ int r_index = -1;
+ for (int i = 0; i < KIND_COUNT; i++) {
+ const ScriptLanguage::CodeCompletionKind kind = KIND_SORT_ORDER[i];
+ l_index = kind == l.kind ? i : l_index;
+ r_index = kind == r.kind ? i : r_index;
+
+ if (l_index != -1 && r_index != -1) {
+ return l_index < r_index;
+ }
+ }
+
+ // This return should never be hit unless something goes wrong.
+ // l and r should always have a Kind which is in the sort order array.
+ return l.display < r.display;
+ }
+
+ return l.location < r.location;
+ }
+};
+
#endif // SCRIPT_TEXT_EDITOR_H
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 9d2b4c88c5..1bf78cc107 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -34,6 +34,7 @@
#include "core/io/resource_saver.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
+#include "core/version_generated.gen.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -49,6 +50,20 @@ static bool saved_treat_warning_as_errors = false;
static Map<ShaderWarning::Code, bool> saved_warnings;
static uint32_t saved_warning_flags = 0U;
+void ShaderTextEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ if (is_visible_in_tree()) {
+ _load_theme_settings();
+ if (warnings.size() > 0 && last_compile_result == OK) {
+ warnings_panel->clear();
+ _update_warning_panel();
+ }
+ }
+ } break;
+ }
+}
+
Ref<Shader> ShaderTextEditor::get_edited_shader() const {
return shader;
}
@@ -137,15 +152,25 @@ void ShaderTextEditor::_load_theme_settings() {
}
}
- for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())).size(); i++) {
- built_ins.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]);
+ const Vector<ShaderLanguage::ModeInfo> &modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
+
+ for (int i = 0; i < modes.size(); i++) {
+ const ShaderLanguage::ModeInfo &info = modes[i];
+
+ if (!info.options.is_empty()) {
+ for (int j = 0; j < info.options.size(); j++) {
+ built_ins.push_back(String(info.name) + "_" + String(info.options[j]));
+ }
+ } else {
+ built_ins.push_back(String(info.name));
+ }
}
}
- const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
+ const Color user_type_color = EDITOR_GET("text_editor/theme/highlighting/user_type_color");
for (const String &E : built_ins) {
- syntax_highlighter->add_keyword_color(E, member_variable_color);
+ syntax_highlighter->add_keyword_color(E, user_type_color);
}
// Colorize comments.
@@ -194,16 +219,22 @@ void ShaderTextEditor::_check_shader_mode() {
static ShaderLanguage::DataType _get_global_variable_type(const StringName &p_variable) {
RS::GlobalVariableType gvt = RS::get_singleton()->global_variable_get_type(p_variable);
- return RS::global_variable_type_get_shader_datatype(gvt);
+ return (ShaderLanguage::DataType)RS::global_variable_type_get_shader_datatype(gvt);
}
-void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options) {
+void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLanguage::CodeCompletionOption> *r_options) {
_check_shader_mode();
ShaderLanguage sl;
String calltip;
- sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type, r_options, calltip);
+ ShaderLanguage::ShaderCompileInfo info;
+ info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode()));
+ info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
+ info.shader_types = ShaderTypes::get_singleton()->get_types();
+ info.global_variable_type_func = _get_global_variable_type;
+
+ sl.complete(p_code, info, r_options, calltip);
get_text_editor()->set_code_hint(calltip);
}
@@ -215,14 +246,20 @@ void ShaderTextEditor::_validate_script() {
//List<StringName> params;
//shader->get_param_list(&params);
+ ShaderLanguage::ShaderCompileInfo info;
+ info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode()));
+ info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
+ info.shader_types = ShaderTypes::get_singleton()->get_types();
+ info.global_variable_type_func = _get_global_variable_type;
+
ShaderLanguage sl;
sl.enable_warning_checking(saved_warnings_enabled);
sl.set_warning_flags(saved_warning_flags);
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
+ last_compile_result = sl.compile(code, info);
- if (err != OK) {
+ if (last_compile_result != OK) {
String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text();
set_error(error_text);
set_error_pos(sl.get_error_line() - 1, 0);
@@ -237,14 +274,14 @@ void ShaderTextEditor::_validate_script() {
set_error("");
}
- if (warnings.size() > 0 || err != OK) {
+ if (warnings.size() > 0 || last_compile_result != OK) {
warnings_panel->clear();
}
warnings.clear();
for (List<ShaderWarning>::Element *E = sl.get_warnings_ptr(); E; E = E->next()) {
warnings.push_back(E->get());
}
- if (warnings.size() > 0 && err == OK) {
+ if (warnings.size() > 0 && last_compile_result == OK) {
warnings.sort_custom<WarningsComparator>();
_update_warning_panel();
} else {
@@ -270,15 +307,20 @@ void ShaderTextEditor::_update_warning_panel() {
}
warning_count++;
+ int line = w.get_line();
// First cell.
warnings_panel->push_cell();
- warnings_panel->push_meta(w.get_line() - 1);
warnings_panel->push_color(warnings_panel->get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- warnings_panel->add_text(TTR("Line") + " " + itos(w.get_line()));
- warnings_panel->add_text(" (" + w.get_name() + "):");
+ if (line != -1) {
+ warnings_panel->push_meta(line - 1);
+ warnings_panel->add_text(TTR("Line") + " " + itos(line));
+ warnings_panel->add_text(" (" + w.get_name() + "):");
+ warnings_panel->pop(); // Meta goto.
+ } else {
+ warnings_panel->add_text(w.get_name() + ":");
+ }
warnings_panel->pop(); // Color.
- warnings_panel->pop(); // Meta goto.
warnings_panel->pop(); // Cell.
// Second cell.
@@ -384,7 +426,7 @@ void ShaderEditor::_menu_option(int p_option) {
shader_editor->remove_all_bookmarks();
} break;
case HELP_DOCS: {
- OS::get_singleton()->shell_open("https://docs.godotengine.org/en/latest/tutorials/shaders/shader_reference/index.html");
+ OS::get_singleton()->shell_open(vformat("%s/tutorials/shaders/shader_reference/index.html", VERSION_DOCS_URL));
} break;
}
if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) {
@@ -393,8 +435,16 @@ void ShaderEditor::_menu_option(int p_option) {
}
void ShaderEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) {
- _check_for_external_edit();
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ PopupMenu *popup = help_menu->get_popup();
+ popup->set_item_icon(popup->get_item_index(HELP_DOCS), get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ } break;
+
+ case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
+ _check_for_external_edit();
+ } break;
}
}
@@ -422,14 +472,6 @@ void ShaderEditor::_bind_methods() {
}
void ShaderEditor::ensure_select_current() {
- /*
- if (tab_container->get_child_count() && tab_container->get_current_tab()>=0) {
- ShaderTextEditor *ste = Object::cast_to<ShaderTextEditor>(tab_container->get_child(tab_container->get_current_tab()));
- if (!ste)
- return;
- Ref<Shader> shader = ste->get_edited_shader();
- get_scene()->get_root_node()->call("_resource_selected",shader);
- }*/
}
void ShaderEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
@@ -486,7 +528,7 @@ void ShaderEditor::_check_for_external_edit() {
return;
}
- bool use_autoreload = bool(EDITOR_DEF("text_editor/behavior/files/auto_reload_scripts_on_external_change", false));
+ bool use_autoreload = bool(EDITOR_GET("text_editor/behavior/files/auto_reload_scripts_on_external_change"));
if (shader->get_last_modified_time() != FileAccess::get_modified_time(shader->get_path())) {
if (use_autoreload) {
_reload_shader_from_disk();
@@ -552,7 +594,7 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
CodeEdit *tx = shader_editor->get_text_editor();
Point2i pos = tx->get_line_column_at_pos(mb->get_global_position() - tx->get_global_position());
@@ -613,7 +655,7 @@ void ShaderEditor::_update_bookmark_list() {
}
bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\"");
- bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]);
+ bookmarks_menu->set_item_metadata(-1, bookmark_list[i]);
}
}
@@ -644,12 +686,12 @@ void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE);
- context_menu->set_position(get_global_transform().xform(p_position));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->set_position(get_screen_position() + p_position);
+ context_menu->reset_size();
context_menu->popup();
}
-ShaderEditor::ShaderEditor(EditorNode *p_node) {
+ShaderEditor::ShaderEditor() {
GLOBAL_DEF("debug/shader_language/warnings/enable", true);
GLOBAL_DEF("debug/shader_language/warnings/treat_warnings_as_errors", false);
for (int i = 0; i < (int)ShaderWarning::WARNING_MAX; i++) {
@@ -738,7 +780,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
help_menu = memnew(MenuButton);
help_menu->set_text(TTR("Help"));
help_menu->set_switch_on_hover(true);
- help_menu->get_popup()->add_icon_item(p_node->get_gui_base()->get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), TTR("Online Docs"), HELP_DOCS);
+ help_menu->get_popup()->add_item(TTR("Online Docs"), HELP_DOCS);
help_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option));
add_child(main_container);
@@ -747,7 +789,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) {
hbc->add_child(edit_menu);
hbc->add_child(goto_menu);
hbc->add_child(help_menu);
- hbc->add_theme_style_override("panel", p_node->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditorPanel"), SNAME("EditorStyles")));
+ hbc->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditorPanel"), SNAME("EditorStyles")));
VSplitContainer *editor_box = memnew(VSplitContainer);
main_container->add_child(editor_box);
@@ -807,12 +849,12 @@ bool ShaderEditorPlugin::handles(Object *p_object) const {
void ShaderEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
- editor->make_bottom_panel_item_visible(shader_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(shader_editor);
} else {
button->hide();
if (shader_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
shader_editor->apply_shaders();
}
@@ -830,12 +872,11 @@ void ShaderEditorPlugin::apply_changes() {
shader_editor->apply_shaders();
}
-ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- shader_editor = memnew(ShaderEditor(p_node));
+ShaderEditorPlugin::ShaderEditorPlugin() {
+ shader_editor = memnew(ShaderEditor);
shader_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
- button = editor->add_bottom_panel_item(TTR("Shader"), shader_editor);
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Shader"), shader_editor);
button->hide();
_2d = false;
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 77579754d3..bd0c2db824 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -40,7 +40,7 @@
#include "scene/gui/text_edit.h"
#include "scene/main/timer.h"
#include "scene/resources/shader.h"
-#include "servers/rendering/shader_language.h"
+#include "servers/rendering/shader_warnings.h"
class ShaderTextEditor : public CodeTextEditor {
GDCLASS(ShaderTextEditor, CodeTextEditor);
@@ -55,15 +55,17 @@ class ShaderTextEditor : public CodeTextEditor {
RichTextLabel *warnings_panel = nullptr;
Ref<Shader> shader;
List<ShaderWarning> warnings;
+ Error last_compile_result = Error::OK;
void _check_shader_mode();
void _update_warning_panel();
protected:
+ void _notification(int p_what);
static void _bind_methods();
virtual void _load_theme_settings() override;
- virtual void _code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options) override;
+ virtual void _code_complete_script(const String &p_code, List<ScriptLanguage::CodeCompletionOption> *r_options) override;
public:
virtual void _validate_script() override;
@@ -106,19 +108,19 @@ class ShaderEditor : public PanelContainer {
HELP_DOCS,
};
- MenuButton *edit_menu;
- MenuButton *search_menu;
- PopupMenu *bookmarks_menu;
- MenuButton *help_menu;
- PopupMenu *context_menu;
+ MenuButton *edit_menu = nullptr;
+ MenuButton *search_menu = nullptr;
+ PopupMenu *bookmarks_menu = nullptr;
+ MenuButton *help_menu = nullptr;
+ PopupMenu *context_menu = nullptr;
RichTextLabel *warnings_panel = nullptr;
- uint64_t idle;
+ uint64_t idle = 0;
- GotoLineDialog *goto_line_dialog;
- ConfirmationDialog *erase_tab_confirm;
- ConfirmationDialog *disk_changed;
+ GotoLineDialog *goto_line_dialog = nullptr;
+ ConfirmationDialog *erase_tab_confirm = nullptr;
+ ConfirmationDialog *disk_changed = nullptr;
- ShaderTextEditor *shader_editor;
+ ShaderTextEditor *shader_editor = nullptr;
void _menu_option(int p_option);
mutable Ref<Shader> shader;
@@ -152,16 +154,15 @@ public:
virtual Size2 get_minimum_size() const override { return Size2(0, 200); }
void save_external_data(const String &p_str = "");
- ShaderEditor(EditorNode *p_node);
+ ShaderEditor();
};
class ShaderEditorPlugin : public EditorPlugin {
GDCLASS(ShaderEditorPlugin, EditorPlugin);
bool _2d;
- ShaderEditor *shader_editor;
- EditorNode *editor;
- Button *button;
+ ShaderEditor *shader_editor = nullptr;
+ Button *button = nullptr;
public:
virtual String get_name() const override { return "Shader"; }
@@ -176,7 +177,7 @@ public:
virtual void save_external_data() override;
virtual void apply_changes() override;
- ShaderEditorPlugin(EditorNode *p_node);
+ ShaderEditorPlugin();
~ShaderEditorPlugin();
};
diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp
index 1e62261244..4458555de2 100644
--- a/editor/plugins/shader_file_editor_plugin.cpp
+++ b/editor/plugins/shader_file_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -97,7 +97,7 @@ void ShaderFileEditor::_version_selected(int p_option) {
error_text->push_font(get_theme_font(SNAME("source"), SNAME("EditorFonts")));
- if (error == String()) {
+ if (error.is_empty()) {
error_text->add_text(TTR("Shader stage compiled without errors."));
} else {
error_text->add_text(error);
@@ -107,7 +107,7 @@ void ShaderFileEditor::_version_selected(int p_option) {
void ShaderFileEditor::_update_options() {
ERR_FAIL_COND(shader_file.is_null());
- if (shader_file->get_base_error() != String()) {
+ if (!shader_file->get_base_error().is_empty()) {
stage_hb->hide();
versions->hide();
error_text->clear();
@@ -136,7 +136,7 @@ void ShaderFileEditor::_update_options() {
for (int i = 0; i < version_list.size(); i++) {
String title = version_list[i];
- if (title == "") {
+ if (title.is_empty()) {
title = "default";
}
@@ -148,7 +148,7 @@ void ShaderFileEditor::_update_options() {
bool failed = false;
for (int j = 0; j < RD::SHADER_STAGE_MAX; j++) {
String error = bytecode->get_stage_compile_error(RD::ShaderStage(j));
- if (error != String()) {
+ if (!error.is_empty()) {
failed = true;
}
}
@@ -182,7 +182,7 @@ void ShaderFileEditor::_update_options() {
for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
Vector<uint8_t> bc = bytecode->get_stage_bytecode(RD::ShaderStage(i));
String error = bytecode->get_stage_compile_error(RD::ShaderStage(i));
- bool disable = error == String() && bc.is_empty();
+ bool disable = error.is_empty() && bc.is_empty();
stages[i]->set_disabled(disable);
if (!disable) {
if (stages[i]->is_pressed()) {
@@ -200,10 +200,12 @@ void ShaderFileEditor::_update_options() {
}
void ShaderFileEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) {
- if (is_visible_in_tree() && shader_file.is_valid()) {
- _update_options();
- }
+ switch (p_what) {
+ case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
+ if (is_visible_in_tree() && shader_file.is_valid()) {
+ _update_options();
+ }
+ } break;
}
}
@@ -245,7 +247,7 @@ void ShaderFileEditor::_shader_changed() {
ShaderFileEditor *ShaderFileEditor::singleton = nullptr;
-ShaderFileEditor::ShaderFileEditor(EditorNode *p_node) {
+ShaderFileEditor::ShaderFileEditor() {
singleton = this;
HSplitContainer *main_hs = memnew(HSplitContainer);
@@ -301,22 +303,21 @@ bool ShaderFileEditorPlugin::handles(Object *p_object) const {
void ShaderFileEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
- editor->make_bottom_panel_item_visible(shader_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(shader_editor);
} else {
button->hide();
if (shader_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
}
}
-ShaderFileEditorPlugin::ShaderFileEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- shader_editor = memnew(ShaderFileEditor(p_node));
+ShaderFileEditorPlugin::ShaderFileEditorPlugin() {
+ shader_editor = memnew(ShaderFileEditor);
shader_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
- button = editor->add_bottom_panel_item(TTR("ShaderFile"), shader_editor);
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("ShaderFile"), shader_editor);
button->hide();
}
diff --git a/editor/plugins/shader_file_editor_plugin.h b/editor/plugins/shader_file_editor_plugin.h
index 7d6e503b6c..1ebd644282 100644
--- a/editor/plugins/shader_file_editor_plugin.h
+++ b/editor/plugins/shader_file_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -41,15 +41,17 @@
#include "scene/main/timer.h"
#include "servers/rendering/rendering_device_binds.h"
+class ItemList;
+
class ShaderFileEditor : public PanelContainer {
GDCLASS(ShaderFileEditor, PanelContainer);
Ref<RDShaderFile> shader_file;
- HBoxContainer *stage_hb;
- ItemList *versions;
+ HBoxContainer *stage_hb = nullptr;
+ ItemList *versions = nullptr;
Button *stages[RD::SHADER_STAGE_MAX];
- RichTextLabel *error_text;
+ RichTextLabel *error_text = nullptr;
void _update_version(const StringName &p_version_txt, const RenderingDevice::ShaderStage p_stage);
void _version_selected(int p_stage);
@@ -66,15 +68,14 @@ public:
static ShaderFileEditor *singleton;
void edit(const Ref<RDShaderFile> &p_shader);
- ShaderFileEditor(EditorNode *p_node);
+ ShaderFileEditor();
};
class ShaderFileEditorPlugin : public EditorPlugin {
GDCLASS(ShaderFileEditorPlugin, EditorPlugin);
- ShaderFileEditor *shader_editor;
- EditorNode *editor;
- Button *button;
+ ShaderFileEditor *shader_editor = nullptr;
+ Button *button = nullptr;
public:
virtual String get_name() const override { return "ShaderFile"; }
@@ -85,7 +86,7 @@ public:
ShaderFileEditor *get_shader_editor() const { return shader_editor; }
- ShaderFileEditorPlugin(EditorNode *p_node);
+ ShaderFileEditorPlugin();
~ShaderFileEditorPlugin();
};
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index c350004f0f..5a1505c232 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,6 +31,7 @@
#include "skeleton_2d_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
+#include "editor/editor_node.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/gui/box_container.h"
#include "thirdparty/misc/clipper.hpp"
@@ -52,34 +53,34 @@ void Skeleton2DEditor::_menu_option(int p_option) {
}
switch (p_option) {
- case MENU_OPTION_MAKE_REST: {
+ case MENU_OPTION_SET_REST: {
if (node->get_bone_count() == 0) {
err_dialog->set_text(TTR("This skeleton has no bones, create some children Bone2D nodes."));
err_dialog->popup_centered();
return;
}
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Create Rest Pose from Bones"));
+ ur->create_action(TTR("Set Rest Pose to Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
- ur->add_do_method(bone, "set_rest", bone->get_transform());
- ur->add_undo_method(bone, "set_rest", bone->get_rest());
+ ur->add_do_method(bone, "set_transform", bone->get_rest());
+ ur->add_undo_method(bone, "set_transform", bone->get_transform());
}
ur->commit_action();
} break;
- case MENU_OPTION_SET_REST: {
+ case MENU_OPTION_MAKE_REST: {
if (node->get_bone_count() == 0) {
err_dialog->set_text(TTR("This skeleton has no bones, create some children Bone2D nodes."));
err_dialog->popup_centered();
return;
}
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Set Rest Pose to Bones"));
+ ur->create_action(TTR("Create Rest Pose from Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
- ur->add_do_method(bone, "set_transform", bone->get_rest());
- ur->add_undo_method(bone, "set_transform", bone->get_transform());
+ ur->add_do_method(bone, "set_rest", bone->get_transform());
+ ur->add_undo_method(bone, "set_rest", bone->get_rest());
}
ur->commit_action();
@@ -98,10 +99,10 @@ Skeleton2DEditor::Skeleton2DEditor() {
options->set_text(TTR("Skeleton2D"));
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Skeleton2D"), SNAME("EditorIcons")));
- options->get_popup()->add_item(TTR("Reset to Rest Pose"), MENU_OPTION_MAKE_REST);
+ options->get_popup()->add_item(TTR("Reset to Rest Pose"), MENU_OPTION_SET_REST);
options->get_popup()->add_separator();
// Use the "Overwrite" word to highlight that this is a destructive operation.
- options->get_popup()->add_item(TTR("Overwrite Rest Pose"), MENU_OPTION_SET_REST);
+ options->get_popup()->add_item(TTR("Overwrite Rest Pose"), MENU_OPTION_MAKE_REST);
options->set_switch_on_hover(true);
options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton2DEditor::_menu_option));
@@ -127,10 +128,9 @@ void Skeleton2DEditorPlugin::make_visible(bool p_visible) {
}
}
-Skeleton2DEditorPlugin::Skeleton2DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+Skeleton2DEditorPlugin::Skeleton2DEditorPlugin() {
sprite_editor = memnew(Skeleton2DEditor);
- editor->get_main_control()->add_child(sprite_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(sprite_editor);
make_visible(false);
//sprite_editor->options->hide();
diff --git a/editor/plugins/skeleton_2d_editor_plugin.h b/editor/plugins/skeleton_2d_editor_plugin.h
index dacd8fe43f..295725b751 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.h
+++ b/editor/plugins/skeleton_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef SKELETON_2D_EDITOR_PLUGIN_H
#define SKELETON_2D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/skeleton_2d.h"
#include "scene/gui/spin_box.h"
@@ -40,14 +39,14 @@ class Skeleton2DEditor : public Control {
GDCLASS(Skeleton2DEditor, Control);
enum Menu {
- MENU_OPTION_MAKE_REST,
MENU_OPTION_SET_REST,
+ MENU_OPTION_MAKE_REST,
};
- Skeleton2D *node;
+ Skeleton2D *node = nullptr;
- MenuButton *options;
- AcceptDialog *err_dialog;
+ MenuButton *options = nullptr;
+ AcceptDialog *err_dialog = nullptr;
void _menu_option(int p_option);
@@ -66,8 +65,7 @@ public:
class Skeleton2DEditorPlugin : public EditorPlugin {
GDCLASS(Skeleton2DEditorPlugin, EditorPlugin);
- Skeleton2DEditor *sprite_editor;
- EditorNode *editor;
+ Skeleton2DEditor *sprite_editor = nullptr;
public:
virtual String get_name() const override { return "Skeleton2D"; }
@@ -76,7 +74,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- Skeleton2DEditorPlugin(EditorNode *p_node);
+ Skeleton2DEditorPlugin();
~Skeleton2DEditorPlugin();
};
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 0b8a56503c..1b703a097c 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,6 +32,7 @@
#include "core/io/resource_saver.h"
#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
#include "editor/plugins/animation_player_editor_plugin.h"
@@ -102,8 +103,7 @@ void BoneTransformEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
create_editors();
- break;
- }
+ } break;
}
}
@@ -149,6 +149,9 @@ void BoneTransformEditor::set_target(const String &p_prop) {
void BoneTransformEditor::_property_keyed(const String &p_path, bool p_advance) {
AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
+ if (!te->has_keying()) {
+ return;
+ }
PackedStringArray split = p_path.split("/");
if (split.size() == 3 && split[0] == "bones") {
int bone_idx = split[1].to_int();
@@ -380,7 +383,7 @@ void Skeleton3DEditor::create_physical_skeleton() {
if (!bones_infos[parent].physical_bone) {
bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);
- ur->create_action(TTR("Create physical bones"));
+ ur->create_action(TTR("Create physical bones"), UndoRedo::MERGE_ALL);
ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
ur->add_do_reference(bones_infos[parent].physical_bone);
ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);
@@ -416,8 +419,14 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0));
bone_shape->set_transform(capsule_transform);
+ /// Get an up vector not collinear with child rest origin
+ Vector3 up = Vector3(0, 1, 0);
+ if (up.cross(child_rest.origin).is_equal_approx(Vector3())) {
+ up = Vector3(0, 0, 1);
+ }
+
Transform3D body_transform;
- body_transform.basis = Basis::looking_at(child_rest.origin);
+ body_transform.basis = Basis::looking_at(child_rest.origin, up);
body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height));
Transform3D joint_transform;
@@ -527,18 +536,23 @@ void Skeleton3DEditor::_joint_tree_selection_changed() {
TreeItem *selected = joint_tree->get_selected();
if (selected) {
const String path = selected->get_metadata(0);
-
- if (path.begins_with("bones/")) {
- const int b_idx = path.get_slicec('/', 1).to_int();
+ if (!path.begins_with("bones/")) {
+ return;
+ }
+ const int b_idx = path.get_slicec('/', 1).to_int();
+ selected_bone = b_idx;
+ if (pose_editor) {
const String bone_path = "bones/" + itos(b_idx) + "/";
-
pose_editor->set_target(bone_path);
pose_editor->set_keyable(keyable);
- selected_bone = b_idx;
}
}
- pose_editor->set_visible(selected);
+
+ if (pose_editor && pose_editor->is_inside_tree()) {
+ pose_editor->set_visible(selected);
+ }
set_bone_options_enabled(selected);
+
_update_properties();
_update_gizmo_visible();
}
@@ -681,7 +695,7 @@ void Skeleton3DEditor::create_editors() {
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys), varray(false));
key_insert_button->set_tooltip(TTR("Insert key of bone poses already exist track."));
- key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTR("Insert Key (Existing Tracks)"), KEY_INSERT));
+ key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTR("Insert Key (Existing Tracks)"), Key::INSERT));
animation_hb->add_child(key_insert_button);
key_insert_all_button = memnew(Button);
@@ -689,7 +703,7 @@ void Skeleton3DEditor::create_editors() {
key_insert_all_button->set_focus_mode(FOCUS_NONE);
key_insert_all_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys), varray(true));
key_insert_all_button->set_tooltip(TTR("Insert key of all bone poses."));
- key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTR("Insert Key (All Bones)"), KEY_MASK_CMD + KEY_INSERT));
+ key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTR("Insert Key (All Bones)"), KeyModifierMask::CMD + Key::INSERT));
animation_hb->add_child(key_insert_all_button);
// Bone tree.
@@ -783,8 +797,7 @@ void Skeleton3DEditor::edit_mode_toggled(const bool pressed) {
_update_gizmo_visible();
}
-Skeleton3DEditor::Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *p_skeleton) :
- editor(p_editor),
+Skeleton3DEditor::Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, Skeleton3D *p_skeleton) :
editor_plugin(e_plugin),
skeleton(p_skeleton) {
singleton = this;
@@ -804,7 +817,7 @@ void vertex() {
COLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );
}
VERTEX = VERTEX;
- POSITION=PROJECTION_MATRIX*INV_CAMERA_MATRIX*WORLD_MATRIX*vec4(VERTEX.xyz,1.0);
+ POSITION = PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * vec4(VERTEX.xyz, 1.0);
POSITION.z = mix(POSITION.z, 0, 0.999);
POINT_SIZE = point_size;
}
@@ -818,7 +831,7 @@ void fragment() {
}
)");
handle_material->set_shader(handle_shader);
- Ref<Texture2D> handle = editor->get_gui_base()->get_theme_icon("EditorBoneHandle", "EditorIcons");
+ Ref<Texture2D> handle = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("EditorBoneHandle"), SNAME("EditorIcons"));
handle_material->set_shader_param("point_size", handle->get_width());
handle_material->set_shader_param("texture_albedo", handle);
@@ -964,6 +977,7 @@ void Skeleton3DEditor::select_bone(int p_idx) {
Skeleton3DEditor::~Skeleton3DEditor() {
if (skeleton) {
+ select_bone(-1);
#ifdef TOOLS_ENABLED
skeleton->disconnect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
skeleton->disconnect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
@@ -973,6 +987,7 @@ Skeleton3DEditor::~Skeleton3DEditor() {
#endif
handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance);
}
+ edit_mode_toggled(false);
handles_mesh_instance->queue_delete();
@@ -1007,15 +1022,12 @@ void EditorInspectorPluginSkeleton::parse_begin(Object *p_object) {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_object);
ERR_FAIL_COND(!skeleton);
- skel_editor = memnew(Skeleton3DEditor(this, editor, skeleton));
+ skel_editor = memnew(Skeleton3DEditor(this, skeleton));
add_custom_control(skel_editor);
}
-Skeleton3DEditorPlugin::Skeleton3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
-
+Skeleton3DEditorPlugin::Skeleton3DEditorPlugin() {
skeleton_plugin = memnew(EditorInspectorPluginSkeleton);
- skeleton_plugin->editor = editor;
EditorInspector::add_inspector_plugin(skeleton_plugin);
@@ -1028,7 +1040,7 @@ EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_spatial_gui_input(Ca
Node3DEditor *ne = Node3DEditor::get_singleton();
if (se->is_edit_mode()) {
const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (ne->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) {
if (!ne->is_gizmo_visible()) {
return EditorPlugin::AFTER_GUI_INPUT_STOP;
@@ -1098,7 +1110,7 @@ void vertex() {
COLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );
}
VERTEX = VERTEX;
- POSITION=PROJECTION_MATRIX*INV_CAMERA_MATRIX*WORLD_MATRIX*vec4(VERTEX.xyz,1.0);
+ POSITION = PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * vec4(VERTEX.xyz, 1.0);
POSITION.z = mix(POSITION.z, 0, 0.998);
}
void fragment() {
@@ -1108,7 +1120,7 @@ void fragment() {
)");
selected_mat->set_shader(selected_sh);
- // Regist properties in editor settings.
+ // Register properties in editor settings.
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0));
EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1);
@@ -1197,8 +1209,7 @@ void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gi
t.basis = to_local * p_transform.get_basis();
// Origin.
- Vector3 orig = Vector3();
- orig = skeleton->get_bone_pose(p_id).origin;
+ Vector3 orig = skeleton->get_bone_pose(p_id).origin;
Vector3 sub = p_transform.origin - skeleton->get_bone_global_pose(p_id).origin;
t.origin = orig + to_local.xform(sub);
@@ -1271,9 +1282,6 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->set_material(unselected_mat);
}
- Vector<Transform3D> grests;
- grests.resize(skeleton->get_bone_count());
-
LocalVector<int> bones;
LocalVector<float> weights;
bones.resize(4);
@@ -1297,11 +1305,6 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
child_bones_vector = skeleton->get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
- // You have children but no parent, then you must be a root/parentless bone.
- if (skeleton->get_bone_parent(current_bone_idx) < 0) {
- grests.write[current_bone_idx] = skeleton->get_bone_rest(current_bone_idx);
- }
-
for (int i = 0; i < child_bones_size; i++) {
// Something wrong.
if (child_bones_vector[i] < 0) {
@@ -1310,10 +1313,8 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
int child_bone_idx = child_bones_vector[i];
- grests.write[child_bone_idx] = grests[current_bone_idx] * skeleton->get_bone_rest(child_bone_idx);
-
- Vector3 v0 = grests[current_bone_idx].origin;
- Vector3 v1 = grests[child_bone_idx].origin;
+ Vector3 v0 = skeleton->get_bone_global_rest(current_bone_idx).origin;
+ Vector3 v1 = skeleton->get_bone_global_rest(child_bone_idx).origin;
Vector3 d = (v1 - v0).normalized();
real_t dist = v0.distance_to(v1);
@@ -1321,7 +1322,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
int closest = -1;
real_t closest_d = 0.0;
for (int j = 0; j < 3; j++) {
- real_t dp = Math::abs(grests[current_bone_idx].basis[j].normalized().dot(d));
+ real_t dp = Math::abs(skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
if (j == 0 || dp > closest_d) {
closest = j;
}
@@ -1348,7 +1349,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int j = 0; j < 3; j++) {
Vector3 axis;
if (first == Vector3()) {
- axis = d.cross(d.cross(grests[current_bone_idx].basis[j])).normalized();
+ axis = d.cross(d.cross(skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
first = axis;
} else {
axis = d.cross(first).normalized();
@@ -1403,7 +1404,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->add_vertex(v0);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
- surface_tool->add_vertex(v0 + (grests[current_bone_idx].basis.inverse())[j].normalized() * dist * bone_axis_length);
+ surface_tool->add_vertex(v0 + (skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
if (j == closest) {
continue;
@@ -1420,7 +1421,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->add_vertex(v1);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
- surface_tool->add_vertex(v1 + (grests[child_bone_idx].basis.inverse())[j].normalized() * dist * bone_axis_length);
+ surface_tool->add_vertex(v1 + (skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
if (j == closest) {
continue;
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 1dd2d2281d..f4a82225f2 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef SKELETON_3D_EDITOR_PLUGIN_H
#define SKELETON_3D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
#include "node_3d_editor_plugin.h"
@@ -61,10 +60,10 @@ class BoneTransformEditor : public VBoxContainer {
Rect2 background_rects[5];
- Skeleton3D *skeleton;
+ Skeleton3D *skeleton = nullptr;
// String property;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
bool toggle_enabled = false;
bool updating = false;
@@ -109,31 +108,30 @@ class Skeleton3DEditor : public VBoxContainer {
Transform3D relative_rest; // Relative to skeleton node.
};
- EditorNode *editor;
- EditorInspectorPluginSkeleton *editor_plugin;
+ EditorInspectorPluginSkeleton *editor_plugin = nullptr;
- Skeleton3D *skeleton;
+ Skeleton3D *skeleton = nullptr;
Tree *joint_tree = nullptr;
BoneTransformEditor *rest_editor = nullptr;
BoneTransformEditor *pose_editor = nullptr;
- VSeparator *separator;
+ VSeparator *separator = nullptr;
MenuButton *skeleton_options = nullptr;
- Button *edit_mode_button;
+ Button *edit_mode_button = nullptr;
bool edit_mode = false;
- HBoxContainer *animation_hb;
- Button *key_loc_button;
- Button *key_rot_button;
- Button *key_scale_button;
- Button *key_insert_button;
- Button *key_insert_all_button;
+ HBoxContainer *animation_hb = nullptr;
+ Button *key_loc_button = nullptr;
+ Button *key_rot_button = nullptr;
+ Button *key_scale_button = nullptr;
+ Button *key_insert_button = nullptr;
+ Button *key_insert_all_button = nullptr;
EditorFileDialog *file_dialog = nullptr;
- bool keyable;
+ bool keyable = false;
static Skeleton3DEditor *singleton;
@@ -165,7 +163,7 @@ class Skeleton3DEditor : public VBoxContainer {
void set_bone_options_enabled(const bool p_bone_options_enabled);
// Handle.
- MeshInstance3D *handles_mesh_instance;
+ MeshInstance3D *handles_mesh_instance = nullptr;
Ref<ImmediateMesh> handles_mesh;
Ref<ShaderMaterial> handle_material;
Ref<Shader> handle_shader;
@@ -213,7 +211,7 @@ public:
Quaternion get_bone_original_rotation() const { return bone_original_rotation; };
Vector3 get_bone_original_scale() const { return bone_original_scale; };
- Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *skeleton);
+ Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, Skeleton3D *skeleton);
~Skeleton3DEditor();
};
@@ -222,8 +220,7 @@ class EditorInspectorPluginSkeleton : public EditorInspectorPlugin {
friend class Skeleton3DEditorPlugin;
- Skeleton3DEditor *skel_editor;
- EditorNode *editor;
+ Skeleton3DEditor *skel_editor = nullptr;
public:
virtual bool can_handle(Object *p_object) override;
@@ -233,8 +230,7 @@ public:
class Skeleton3DEditorPlugin : public EditorPlugin {
GDCLASS(Skeleton3DEditorPlugin, EditorPlugin);
- EditorInspectorPluginSkeleton *skeleton_plugin;
- EditorNode *editor;
+ EditorInspectorPluginSkeleton *skeleton_plugin = nullptr;
public:
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
@@ -244,7 +240,7 @@ public:
virtual String get_name() const override { return "Skeleton3D"; }
- Skeleton3DEditorPlugin(EditorNode *p_node);
+ Skeleton3DEditorPlugin();
};
class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
index 85632cf481..7dc34a0874 100644
--- a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,7 @@
#include "skeleton_ik_3d_editor_plugin.h"
+#include "editor/editor_node.h"
#include "scene/3d/skeleton_ik_3d.h"
void SkeletonIK3DEditorPlugin::_play() {
@@ -80,10 +81,9 @@ void SkeletonIK3DEditorPlugin::make_visible(bool p_visible) {
void SkeletonIK3DEditorPlugin::_bind_methods() {
}
-SkeletonIK3DEditorPlugin::SkeletonIK3DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+SkeletonIK3DEditorPlugin::SkeletonIK3DEditorPlugin() {
play_btn = memnew(Button);
- play_btn->set_icon(editor->get_gui_base()->get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
+ play_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
play_btn->set_text(TTR("Play IK"));
play_btn->set_toggle_mode(true);
play_btn->hide();
diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.h b/editor/plugins/skeleton_ik_3d_editor_plugin.h
index b0d2138115..26aead6d67 100644
--- a/editor/plugins/skeleton_ik_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_ik_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef SKELETON_IK_3D_EDITOR_PLUGIN_H
#define SKELETON_IK_3D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
class SkeletonIK3D;
@@ -39,10 +38,9 @@ class SkeletonIK3D;
class SkeletonIK3DEditorPlugin : public EditorPlugin {
GDCLASS(SkeletonIK3DEditorPlugin, EditorPlugin);
- SkeletonIK3D *skeleton_ik;
+ SkeletonIK3D *skeleton_ik = nullptr;
- Button *play_btn;
- EditorNode *editor;
+ Button *play_btn = nullptr;
void _play();
@@ -56,7 +54,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- SkeletonIK3DEditorPlugin(EditorNode *p_node);
+ SkeletonIK3DEditorPlugin();
~SkeletonIK3DEditorPlugin();
};
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index eb5e527640..6a63875324 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,7 +32,9 @@
#include "canvas_item_editor_plugin.h"
#include "core/math/geometry_2d.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/scene_tree_dock.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/mesh_instance_2d.h"
@@ -120,8 +122,8 @@ void Sprite2DEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CONVERT_TO_MESH_2D: {
- debug_uv_dialog->get_ok_button()->set_text(TTR("Create Mesh2D"));
- debug_uv_dialog->set_title(TTR("Mesh2D Preview"));
+ debug_uv_dialog->get_ok_button()->set_text(TTR("Create MeshInstance2D"));
+ debug_uv_dialog->set_title(TTR("MeshInstance2D Preview"));
_update_mesh_data();
debug_uv_dialog->popup_centered();
@@ -336,10 +338,10 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() {
mesh_instance->set_mesh(mesh);
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Convert to Mesh2D"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, mesh_instance, true, false);
+ ur->create_action(TTR("Convert to MeshInstance2D"));
+ ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, mesh_instance, true, false);
ur->add_do_reference(mesh_instance);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", mesh_instance, node, false, false);
+ ur->add_undo_method(SceneTreeDock::get_singleton(), "replace_node", mesh_instance, node, false, false);
ur->add_undo_reference(node);
ur->commit_action();
}
@@ -395,9 +397,9 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() {
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to Polygon2D"));
- ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, polygon_2d_instance, true, false);
+ ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, polygon_2d_instance, true, false);
ur->add_do_reference(polygon_2d_instance);
- ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", polygon_2d_instance, node, false, false);
+ ur->add_undo_method(SceneTreeDock::get_singleton(), "replace_node", polygon_2d_instance, node, false, false);
ur->add_undo_reference(node);
ur->commit_action();
}
@@ -496,6 +498,20 @@ void Sprite2DEditor::_debug_uv_draw() {
}
}
+void Sprite2DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ options->set_icon(get_theme_icon(SNAME("Sprite2D"), SNAME("EditorIcons")));
+
+ options->get_popup()->set_item_icon(MENU_OPTION_CONVERT_TO_MESH_2D, get_theme_icon(SNAME("MeshInstance2D"), SNAME("EditorIcons")));
+ options->get_popup()->set_item_icon(MENU_OPTION_CONVERT_TO_POLYGON_2D, get_theme_icon(SNAME("Polygon2D"), SNAME("EditorIcons")));
+ options->get_popup()->set_item_icon(MENU_OPTION_CREATE_COLLISION_POLY_2D, get_theme_icon(SNAME("CollisionPolygon2D"), SNAME("EditorIcons")));
+ options->get_popup()->set_item_icon(MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D, get_theme_icon(SNAME("LightOccluder2D"), SNAME("EditorIcons")));
+ } break;
+ }
+}
+
void Sprite2DEditor::_bind_methods() {
ClassDB::bind_method("_add_as_sibling_or_child", &Sprite2DEditor::_add_as_sibling_or_child);
}
@@ -506,9 +522,8 @@ Sprite2DEditor::Sprite2DEditor() {
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text(TTR("Sprite2D"));
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Sprite2D"), SNAME("EditorIcons")));
- options->get_popup()->add_item(TTR("Convert to Mesh2D"), MENU_OPTION_CONVERT_TO_MESH_2D);
+ options->get_popup()->add_item(TTR("Convert to MeshInstance2D"), MENU_OPTION_CONVERT_TO_MESH_2D);
options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D);
options->get_popup()->add_item(TTR("Create CollisionPolygon2D Sibling"), MENU_OPTION_CREATE_COLLISION_POLY_2D);
options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D);
@@ -520,14 +535,10 @@ Sprite2DEditor::Sprite2DEditor() {
add_child(err_dialog);
debug_uv_dialog = memnew(ConfirmationDialog);
- debug_uv_dialog->get_ok_button()->set_text(TTR("Create Mesh2D"));
- debug_uv_dialog->set_title(TTR("Mesh 2D Preview"));
VBoxContainer *vb = memnew(VBoxContainer);
debug_uv_dialog->add_child(vb);
ScrollContainer *scroll = memnew(ScrollContainer);
scroll->set_custom_minimum_size(Size2(800, 500) * EDSCALE);
- scroll->set_enable_h_scroll(true);
- scroll->set_enable_v_scroll(true);
vb->add_margin_child(TTR("Preview:"), scroll, true);
debug_uv = memnew(Control);
debug_uv->connect("draw", callable_mp(this, &Sprite2DEditor::_debug_uv_draw));
@@ -585,10 +596,9 @@ void Sprite2DEditorPlugin::make_visible(bool p_visible) {
}
}
-Sprite2DEditorPlugin::Sprite2DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+Sprite2DEditorPlugin::Sprite2DEditorPlugin() {
sprite_editor = memnew(Sprite2DEditor);
- editor->get_main_control()->add_child(sprite_editor);
+ EditorNode::get_singleton()->get_main_control()->add_child(sprite_editor);
make_visible(false);
//sprite_editor->options->hide();
diff --git a/editor/plugins/sprite_2d_editor_plugin.h b/editor/plugins/sprite_2d_editor_plugin.h
index d4a1ef4312..8e3dc19c7e 100644
--- a/editor/plugins/sprite_2d_editor_plugin.h
+++ b/editor/plugins/sprite_2d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef SPRITE_EDITOR_PLUGIN_H
#define SPRITE_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/sprite_2d.h"
#include "scene/gui/spin_box.h"
@@ -48,16 +47,16 @@ class Sprite2DEditor : public Control {
Menu selected_menu_item;
- Sprite2D *node;
+ Sprite2D *node = nullptr;
- MenuButton *options;
+ MenuButton *options = nullptr;
- ConfirmationDialog *outline_dialog;
+ ConfirmationDialog *outline_dialog = nullptr;
- AcceptDialog *err_dialog;
+ AcceptDialog *err_dialog = nullptr;
- ConfirmationDialog *debug_uv_dialog;
- Control *debug_uv;
+ ConfirmationDialog *debug_uv_dialog = nullptr;
+ Control *debug_uv = nullptr;
Vector<Vector2> uv_lines;
Vector<Vector<Vector2>> outline_lines;
Vector<Vector<Vector2>> computed_outline_lines;
@@ -65,10 +64,10 @@ class Sprite2DEditor : public Control {
Vector<Vector2> computed_uv;
Vector<int> computed_indices;
- SpinBox *simplification;
- SpinBox *grow_pixels;
- SpinBox *shrink_pixels;
- Button *update_preview;
+ SpinBox *simplification = nullptr;
+ SpinBox *grow_pixels = nullptr;
+ SpinBox *shrink_pixels = nullptr;
+ Button *update_preview = nullptr;
void _menu_option(int p_option);
@@ -88,6 +87,7 @@ class Sprite2DEditor : public Control {
protected:
void _node_removed(Node *p_node);
+ void _notification(int p_what);
static void _bind_methods();
public:
@@ -98,8 +98,7 @@ public:
class Sprite2DEditorPlugin : public EditorPlugin {
GDCLASS(Sprite2DEditorPlugin, EditorPlugin);
- Sprite2DEditor *sprite_editor;
- EditorNode *editor;
+ Sprite2DEditor *sprite_editor = nullptr;
public:
virtual String get_name() const override { return "Sprite2D"; }
@@ -108,7 +107,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- Sprite2DEditorPlugin(EditorNode *p_node);
+ Sprite2DEditorPlugin();
~Sprite2DEditorPlugin();
};
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 8a8d80891a..7b6aeb3679 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,14 +33,19 @@
#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/scene_tree_dock.h"
#include "scene/3d/sprite_3d.h"
#include "scene/gui/center_container.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/panel_container.h"
-void SpriteFramesEditor::gui_input(const Ref<InputEvent> &p_event) {
+static void _draw_shadowed_line(Control *p_control, const Point2 &p_from, const Size2 &p_size, const Size2 &p_shadow_offset, Color p_color, Color p_shadow_color) {
+ p_control->draw_line(p_from, p_from + p_size, p_color);
+ p_control->draw_line(p_from + p_shadow_offset, p_from + p_size + p_shadow_offset, p_shadow_color);
}
void SpriteFramesEditor::_open_sprite_sheet() {
@@ -55,46 +60,62 @@ void SpriteFramesEditor::_open_sprite_sheet() {
}
int SpriteFramesEditor::_sheet_preview_position_to_frame_index(const Point2 &p_position) {
- if (p_position.x < 0 || p_position.y < 0) {
- return -1;
- }
+ const Size2i offset = _get_offset();
+ const Size2i frame_size = _get_frame_size();
+ const Size2i separation = _get_separation();
+ const Size2i block_size = frame_size + separation;
+ const Point2i position = p_position / sheet_zoom - offset;
- Size2i texture_size = split_sheet_preview->get_texture()->get_size();
- int h = split_sheet_h->get_value();
- int v = split_sheet_v->get_value();
- if (h > texture_size.width || v > texture_size.height) {
- return -1;
+ if (position.x % block_size.x > frame_size.x || position.y % block_size.y > frame_size.y) {
+ return -1; // Gap between frames.
}
- int x = int(p_position.x / sheet_zoom) / (texture_size.width / h);
- int y = int(p_position.y / sheet_zoom) / (texture_size.height / v);
- if (x >= h || y >= v) {
- return -1;
+ const Point2i frame = position / block_size;
+ const Size2i frame_count = _get_frame_count();
+ if (frame.x < 0 || frame.y < 0 || frame.x >= frame_count.x || frame.y >= frame_count.y) {
+ return -1; // Out of bound.
}
- return h * y + x;
+
+ return frame_count.x * frame.y + frame.x;
}
void SpriteFramesEditor::_sheet_preview_draw() {
- Size2i texture_size = split_sheet_preview->get_texture()->get_size();
- int h = split_sheet_h->get_value();
- int v = split_sheet_v->get_value();
-
- real_t width = (texture_size.width / h) * sheet_zoom;
- real_t height = (texture_size.height / v) * sheet_zoom;
- const float a = 0.3;
-
- real_t y_end = v * height;
- for (int i = 0; i <= h; i++) {
- real_t x = i * width;
- split_sheet_preview->draw_line(Point2(x, 0), Point2(x, y_end), Color(1, 1, 1, a));
- split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, y_end), Color(0, 0, 0, a));
+ const Size2i frame_count = _get_frame_count();
+ const Size2i separation = _get_separation();
+
+ const Size2 draw_offset = Size2(_get_offset()) * sheet_zoom;
+ const Size2 draw_sep = Size2(separation) * sheet_zoom;
+ const Size2 draw_frame_size = Size2(_get_frame_size()) * sheet_zoom;
+ const Size2 draw_size = draw_frame_size * frame_count + draw_sep * (frame_count - Size2i(1, 1));
+
+ const Color line_color = Color(1, 1, 1, 0.3);
+ const Color shadow_color = Color(0, 0, 0, 0.3);
+
+ // Vertical lines.
+ _draw_shadowed_line(split_sheet_preview, draw_offset, Vector2(0, draw_size.y), Vector2(1, 0), line_color, shadow_color);
+ for (int i = 0; i < frame_count.x - 1; i++) {
+ const Point2 start = draw_offset + Vector2(i * draw_sep.x + (i + 1) * draw_frame_size.x, 0);
+ if (separation.x == 0) {
+ _draw_shadowed_line(split_sheet_preview, start, Vector2(0, draw_size.y), Vector2(1, 0), line_color, shadow_color);
+ } else {
+ const Size2 size = Size2(draw_sep.x, draw_size.y);
+ split_sheet_preview->draw_rect(Rect2(start, size), line_color);
+ }
}
- real_t x_end = h * width;
- for (int i = 0; i <= v; i++) {
- real_t y = i * height;
- split_sheet_preview->draw_line(Point2(0, y), Point2(x_end, y), Color(1, 1, 1, a));
- split_sheet_preview->draw_line(Point2(0, y + 1), Point2(x_end, y + 1), Color(0, 0, 0, a));
+ _draw_shadowed_line(split_sheet_preview, draw_offset + Vector2(draw_size.x, 0), Vector2(0, draw_size.y), Vector2(1, 0), line_color, shadow_color);
+
+ // Horizontal lines.
+ _draw_shadowed_line(split_sheet_preview, draw_offset, Vector2(draw_size.x, 0), Vector2(0, 1), line_color, shadow_color);
+ for (int i = 0; i < frame_count.y - 1; i++) {
+ const Point2 start = draw_offset + Vector2(0, i * draw_sep.y + (i + 1) * draw_frame_size.y);
+ if (separation.y == 0) {
+ _draw_shadowed_line(split_sheet_preview, start, Vector2(draw_size.x, 0), Vector2(0, 1), line_color, shadow_color);
+ } else {
+ const Size2 size = Size2(draw_size.x, draw_sep.y);
+ split_sheet_preview->draw_rect(Rect2(start, size), line_color);
+ }
}
+ _draw_shadowed_line(split_sheet_preview, draw_offset + Vector2(0, draw_size.y), Vector2(draw_size.x, 0), Vector2(0, 1), line_color, shadow_color);
if (frames_selected.size() == 0) {
split_sheet_dialog->get_ok_button()->set_disabled(true);
@@ -102,22 +123,20 @@ void SpriteFramesEditor::_sheet_preview_draw() {
return;
}
- Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ Color accent = get_theme_color("accent_color", "Editor");
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
- int idx = E->get();
- int xp = idx % h;
- int yp = idx / h;
- real_t x = xp * width;
- real_t y = yp * height;
-
- split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 0.35), true);
- split_sheet_preview->draw_rect(Rect2(x + 0, y + 0, width - 0, height - 0), Color(0, 0, 0, 1), false);
- split_sheet_preview->draw_rect(Rect2(x + 1, y + 1, width - 2, height - 2), Color(0, 0, 0, 1), false);
- split_sheet_preview->draw_rect(Rect2(x + 2, y + 2, width - 4, height - 4), accent, false);
- split_sheet_preview->draw_rect(Rect2(x + 3, y + 3, width - 6, height - 6), accent, false);
- split_sheet_preview->draw_rect(Rect2(x + 4, y + 4, width - 8, height - 8), Color(0, 0, 0, 1), false);
- split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 1), false);
+ const int idx = E->get();
+ const int x = idx % frame_count.x;
+ const int y = idx / frame_count.x;
+ const Point2 pos = draw_offset + Point2(x, y) * (draw_frame_size + draw_sep);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(5, 5), draw_frame_size - Size2(10, 10)), Color(0, 0, 0, 0.35), true);
+ split_sheet_preview->draw_rect(Rect2(pos, draw_frame_size), Color(0, 0, 0, 1), false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(1, 1), draw_frame_size - Size2(2, 2)), Color(0, 0, 0, 1), false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(2, 2), draw_frame_size - Size2(4, 4)), accent, false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(3, 3), draw_frame_size - Size2(6, 6)), accent, false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(4, 4), draw_frame_size - Size2(8, 8)), Color(0, 0, 0, 1), false);
+ split_sheet_preview->draw_rect(Rect2(pos + Size2(5, 5), draw_frame_size - Size2(10, 10)), Color(0, 0, 0, 1), false);
}
split_sheet_dialog->get_ok_button()->set_disabled(false);
@@ -126,7 +145,7 @@ void SpriteFramesEditor::_sheet_preview_draw() {
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
const int idx = _sheet_preview_position_to_frame_index(mb->get_position());
if (idx != -1) {
@@ -166,12 +185,12 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
frames_toggled_by_mouse_hover.clear();
}
const Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
// Select by holding down the mouse button on frames.
const int idx = _sheet_preview_position_to_frame_index(mm->get_position());
@@ -200,50 +219,43 @@ void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
// to allow performing this action anywhere, even if the cursor isn't
// hovering the texture in the workspace.
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->is_ctrl_pressed()) {
- _sheet_zoom_in();
+ if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_pressed() && mb->is_ctrl_pressed()) {
+ _sheet_zoom_on_position(scale_ratio, mb->get_position());
// Don't scroll up after zooming in.
- accept_event();
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->is_ctrl_pressed()) {
- _sheet_zoom_out();
+ split_sheet_scroll->accept_event();
+ } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_pressed() && mb->is_ctrl_pressed()) {
+ _sheet_zoom_on_position(1 / scale_ratio, mb->get_position());
// Don't scroll down after zooming out.
- accept_event();
+ split_sheet_scroll->accept_event();
}
}
+
+ const Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_MIDDLE) != MouseButton::NONE) {
+ const Vector2 dragged = Input::get_singleton()->warp_mouse_motion(mm, split_sheet_scroll->get_global_rect());
+ split_sheet_scroll->set_h_scroll(split_sheet_scroll->get_h_scroll() - dragged.x);
+ split_sheet_scroll->set_v_scroll(split_sheet_scroll->get_v_scroll() - dragged.y);
+ }
}
void SpriteFramesEditor::_sheet_add_frames() {
- Size2i texture_size = split_sheet_preview->get_texture()->get_size();
- int frame_count_x = split_sheet_h->get_value();
- int frame_count_y = split_sheet_v->get_value();
- Size2 frame_size(texture_size.width / frame_count_x, texture_size.height / frame_count_y);
+ const Size2i frame_count = _get_frame_count();
+ const Size2i frame_size = _get_frame_size();
+ const Size2i offset = _get_offset();
+ const Size2i separation = _get_separation();
undo_redo->create_action(TTR("Add Frame"));
int fc = frames->get_frame_count(edited_anim);
- Point2 src_origin;
- Rect2 src_region(Point2(), texture_size);
-
- AtlasTexture *src_atlas = Object::cast_to<AtlasTexture>(*split_sheet_preview->get_texture());
- if (src_atlas && src_atlas->get_atlas().is_valid()) {
- src_origin = src_atlas->get_region().position - src_atlas->get_margin().position;
- src_region = src_atlas->get_region();
- }
-
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
int idx = E->get();
- Point2 frame_coords(idx % frame_count_x, idx / frame_count_x);
-
- Rect2 frame(frame_coords * frame_size + src_origin, frame_size);
- Rect2 region = frame.intersection(src_region);
- Rect2 margin(region == Rect2() ? Point2() : region.position - frame.position, frame.size - region.size);
+ const Point2 frame_coords(idx % frame_count.x, idx / frame_count.x);
Ref<AtlasTexture> at;
at.instantiate();
at->set_atlas(split_sheet_preview->get_texture());
- at->set_region(region);
- at->set_margin(margin);
+ at->set_region(Rect2(offset + frame_coords * (frame_size + separation), frame_size));
undo_redo->add_do_method(frames, "add_frame", edited_anim, at, -1);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, fc);
@@ -254,20 +266,25 @@ void SpriteFramesEditor::_sheet_add_frames() {
undo_redo->commit_action();
}
+void SpriteFramesEditor::_sheet_zoom_on_position(float p_zoom, const Vector2 &p_position) {
+ const float old_zoom = sheet_zoom;
+ sheet_zoom = CLAMP(sheet_zoom * p_zoom, min_sheet_zoom, max_sheet_zoom);
+
+ const Size2 texture_size = split_sheet_preview->get_texture()->get_size();
+ split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
+
+ Vector2 offset = Vector2(split_sheet_scroll->get_h_scroll(), split_sheet_scroll->get_v_scroll());
+ offset = (offset + p_position) / old_zoom * sheet_zoom - p_position;
+ split_sheet_scroll->set_h_scroll(offset.x);
+ split_sheet_scroll->set_v_scroll(offset.y);
+}
+
void SpriteFramesEditor::_sheet_zoom_in() {
- if (sheet_zoom < max_sheet_zoom) {
- sheet_zoom *= scale_ratio;
- Size2 texture_size = split_sheet_preview->get_texture()->get_size();
- split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
- }
+ _sheet_zoom_on_position(scale_ratio, Vector2());
}
void SpriteFramesEditor::_sheet_zoom_out() {
- if (sheet_zoom > min_sheet_zoom) {
- sheet_zoom /= scale_ratio;
- Size2 texture_size = split_sheet_preview->get_texture()->get_size();
- split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom);
- }
+ _sheet_zoom_on_position(1 / scale_ratio, Vector2());
}
void SpriteFramesEditor::_sheet_zoom_reset() {
@@ -292,14 +309,64 @@ void SpriteFramesEditor::_sheet_select_clear_all_frames() {
split_sheet_preview->update();
}
-void SpriteFramesEditor::_sheet_spin_changed(double) {
+void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) {
+ if (updating_split_settings) {
+ return;
+ }
+ updating_split_settings = true;
+
+ if (p_dominant_param != PARAM_USE_CURRENT) {
+ dominant_param = p_dominant_param;
+ }
+
+ const Size2i texture_size = split_sheet_preview->get_texture()->get_size();
+ const Size2i size = texture_size - _get_offset();
+
+ switch (dominant_param) {
+ case PARAM_SIZE: {
+ const Size2i frame_size = _get_frame_size();
+
+ const Size2i offset_max = texture_size - frame_size;
+ split_sheet_offset_x->set_max(offset_max.x);
+ split_sheet_offset_y->set_max(offset_max.y);
+
+ const Size2i sep_max = size - frame_size * 2;
+ split_sheet_sep_x->set_max(sep_max.x);
+ split_sheet_sep_y->set_max(sep_max.y);
+
+ const Size2i separation = _get_separation();
+ const Size2i count = (size + separation) / (frame_size + separation);
+ split_sheet_h->set_value(count.x);
+ split_sheet_v->set_value(count.y);
+ } break;
+
+ case PARAM_FRAME_COUNT: {
+ const Size2i count = _get_frame_count();
+
+ const Size2i offset_max = texture_size - count;
+ split_sheet_offset_x->set_max(offset_max.x);
+ split_sheet_offset_y->set_max(offset_max.y);
+
+ const Size2i gap_count = count - Size2i(1, 1);
+ split_sheet_sep_x->set_max(gap_count.x == 0 ? size.x : (size.x - count.x) / gap_count.x);
+ split_sheet_sep_y->set_max(gap_count.y == 0 ? size.y : (size.y - count.y) / gap_count.y);
+
+ const Size2i separation = _get_separation();
+ const Size2i frame_size = (size - separation * gap_count) / count;
+ split_sheet_size_x->set_value(frame_size.x);
+ split_sheet_size_y->set_value(frame_size.y);
+ } break;
+ }
+
+ updating_split_settings = false;
+
frames_selected.clear();
last_frame_selected = -1;
split_sheet_preview->update();
}
void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
- Ref<Resource> texture = ResourceLoader::load(p_file);
+ Ref<Texture2D> texture = ResourceLoader::load(p_file);
if (!texture.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("Unable to load images"));
ERR_FAIL_COND(!texture.is_valid());
@@ -310,10 +377,29 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
bool new_texture = texture != split_sheet_preview->get_texture();
split_sheet_preview->set_texture(texture);
if (new_texture) {
- //different texture, reset to 4x4
+ // Reset spin max.
+ const Size2i size = texture->get_size();
+ split_sheet_size_x->set_max(size.x);
+ split_sheet_size_y->set_max(size.y);
+ split_sheet_sep_x->set_max(size.x);
+ split_sheet_sep_y->set_max(size.y);
+ split_sheet_offset_x->set_max(size.x);
+ split_sheet_offset_y->set_max(size.y);
+
+ // Different texture, reset to 4x4.
+ dominant_param = PARAM_FRAME_COUNT;
+ updating_split_settings = true;
split_sheet_h->set_value(4);
split_sheet_v->set_value(4);
- //reset zoom
+ split_sheet_size_x->set_value(size.x / 4);
+ split_sheet_size_y->set_value(size.y / 4);
+ split_sheet_sep_x->set_value(0);
+ split_sheet_sep_y->set_value(0);
+ split_sheet_offset_x->set_value(0);
+ split_sheet_offset_y->set_value(0);
+ updating_split_settings = false;
+
+ // Reset zoom.
_sheet_zoom_reset();
}
split_sheet_dialog->popup_centered_ratio(0.65);
@@ -321,7 +407,8 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
void SpriteFramesEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
load->set_icon(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")));
load_sheet->set_icon(get_theme_icon(SNAME("SpriteSheet"), SNAME("EditorIcons")));
copy->set_icon(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")));
@@ -339,11 +426,9 @@ void SpriteFramesEditor::_notification(int p_what) {
split_sheet_zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
split_sheet_zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
split_sheet_zoom_in->set_icon(get_theme_icon(SNAME("ZoomMore"), SNAME("EditorIcons")));
- [[fallthrough]];
- }
- case NOTIFICATION_THEME_CHANGED: {
split_sheet_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
} break;
+
case NOTIFICATION_READY: {
add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up.
} break;
@@ -392,6 +477,22 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
undo_redo->commit_action();
}
+Size2i SpriteFramesEditor::_get_frame_count() const {
+ return Size2i(split_sheet_h->get_value(), split_sheet_v->get_value());
+}
+
+Size2i SpriteFramesEditor::_get_frame_size() const {
+ return Size2i(split_sheet_size_x->get_value(), split_sheet_size_y->get_value());
+}
+
+Size2i SpriteFramesEditor::_get_offset() const {
+ return Size2i(split_sheet_offset_x->get_value(), split_sheet_offset_y->get_value());
+}
+
+Size2i SpriteFramesEditor::_get_separation() const {
+ return Size2i(split_sheet_sep_x->get_value(), split_sheet_sep_y->get_value());
+}
+
void SpriteFramesEditor::_load_pressed() {
ERR_FAIL_COND(!frames->has_animation(edited_anim));
loading_scene = false;
@@ -746,11 +847,11 @@ void SpriteFramesEditor::_tree_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->is_ctrl_pressed()) {
+ if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_pressed() && mb->is_ctrl_pressed()) {
_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->is_ctrl_pressed()) {
+ } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_pressed() && mb->is_ctrl_pressed()) {
_zoom_out();
// Don't scroll down after zooming out.
accept_event();
@@ -835,19 +936,30 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
for (int i = 0; i < frames->get_frame_count(edited_anim); i++) {
String name;
- Ref<Texture2D> icon;
+ Ref<Texture2D> frame = frames->get_frame(edited_anim, i);
- if (frames->get_frame(edited_anim, i).is_null()) {
+ if (frame.is_null()) {
name = itos(i) + ": " + TTR("(empty)");
-
} else {
- name = itos(i) + ": " + frames->get_frame(edited_anim, i)->get_name();
- icon = frames->get_frame(edited_anim, i);
+ name = itos(i) + ": " + frame->get_name();
}
- tree->add_item(name, icon);
- if (frames->get_frame(edited_anim, i).is_valid()) {
- tree->set_item_tooltip(tree->get_item_count() - 1, frames->get_frame(edited_anim, i)->get_path());
+ tree->add_item(name, frame);
+ if (frame.is_valid()) {
+ String tooltip = frame->get_path();
+
+ // Frame is often saved as an AtlasTexture subresource within a scene/resource file,
+ // thus its path might be not what the user is looking for. So we're also showing
+ // subsequent source texture paths.
+ String prefix = String::utf8("┖╴");
+ Ref<AtlasTexture> at = frame;
+ while (at.is_valid() && at->get_atlas().is_valid()) {
+ tooltip += "\n" + prefix + at->get_atlas()->get_path();
+ prefix = " " + prefix;
+ at = at->get_atlas();
+ }
+
+ tree->set_item_tooltip(-1, tooltip);
}
if (sel == i) {
tree->select(tree->get_item_count() - 1);
@@ -900,7 +1012,7 @@ Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
return Variant();
}
- RES frame = frames->get_frame(edited_anim, idx);
+ Ref<Resource> frame = frames->get_frame(edited_anim, idx);
if (frame.is_null()) {
return Variant();
@@ -924,7 +1036,7 @@ bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant &
}
if (String(d["type"]) == "resource" && d.has("resource")) {
- RES r = d["resource"];
+ Ref<Resource> r = d["resource"];
Ref<Texture2D> texture = r;
@@ -968,7 +1080,7 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
int at_pos = tree->get_item_at_position(p_point, true);
if (String(d["type"]) == "resource" && d.has("resource")) {
- RES r = d["resource"];
+ Ref<Resource> r = d["resource"];
Ref<Texture2D> texture = r;
@@ -1006,7 +1118,7 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
if (String(d["type"]) == "files") {
Vector<String> files = d["files"];
- if (Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
_prepare_sprite_sheet(files[0]);
} else {
_file_load_request(files, at_pos);
@@ -1199,23 +1311,66 @@ SpriteFramesEditor::SpriteFramesEditor() {
HBoxContainer *split_sheet_hb = memnew(HBoxContainer);
- Label *ss_label = memnew(Label(TTR("Horizontal:")));
- split_sheet_hb->add_child(ss_label);
+ split_sheet_hb->add_child(memnew(Label(TTR("Horizontal:"))));
split_sheet_h = memnew(SpinBox);
split_sheet_h->set_min(1);
split_sheet_h->set_max(128);
split_sheet_h->set_step(1);
split_sheet_hb->add_child(split_sheet_h);
- split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed));
+ split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_FRAME_COUNT));
- ss_label = memnew(Label(TTR("Vertical:")));
- split_sheet_hb->add_child(ss_label);
+ split_sheet_hb->add_child(memnew(Label(TTR("Vertical:"))));
split_sheet_v = memnew(SpinBox);
split_sheet_v->set_min(1);
split_sheet_v->set_max(128);
split_sheet_v->set_step(1);
split_sheet_hb->add_child(split_sheet_v);
- split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed));
+ split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_FRAME_COUNT));
+
+ split_sheet_hb->add_child(memnew(VSeparator));
+ split_sheet_hb->add_child(memnew(Label(TTR("Size:"))));
+ split_sheet_size_x = memnew(SpinBox);
+ split_sheet_size_x->set_min(1);
+ split_sheet_size_x->set_step(1);
+ split_sheet_size_x->set_suffix("px");
+ split_sheet_size_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_SIZE));
+ split_sheet_hb->add_child(split_sheet_size_x);
+ split_sheet_size_y = memnew(SpinBox);
+ split_sheet_size_y->set_min(1);
+ split_sheet_size_y->set_step(1);
+ split_sheet_size_y->set_suffix("px");
+ split_sheet_size_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_SIZE));
+ split_sheet_hb->add_child(split_sheet_size_y);
+
+ split_sheet_hb->add_child(memnew(VSeparator));
+ split_sheet_hb->add_child(memnew(Label(TTR("Separation:"))));
+ split_sheet_sep_x = memnew(SpinBox);
+ split_sheet_sep_x->set_min(0);
+ split_sheet_sep_x->set_step(1);
+ split_sheet_sep_x->set_suffix("px");
+ split_sheet_sep_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_sep_x);
+ split_sheet_sep_y = memnew(SpinBox);
+ split_sheet_sep_y->set_min(0);
+ split_sheet_sep_y->set_step(1);
+ split_sheet_sep_y->set_suffix("px");
+ split_sheet_sep_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_sep_y);
+
+ split_sheet_hb->add_child(memnew(VSeparator));
+ split_sheet_hb->add_child(memnew(Label(TTR("Offset:"))));
+ split_sheet_offset_x = memnew(SpinBox);
+ split_sheet_offset_x->set_min(0);
+ split_sheet_offset_x->set_step(1);
+ split_sheet_offset_x->set_suffix("px");
+ split_sheet_offset_x->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_offset_x);
+ split_sheet_offset_y = memnew(SpinBox);
+ split_sheet_offset_y->set_min(0);
+ split_sheet_offset_y->set_step(1);
+ split_sheet_offset_y->set_suffix("px");
+ split_sheet_offset_y->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed), varray(PARAM_USE_CURRENT));
+ split_sheet_hb->add_child(split_sheet_offset_y);
split_sheet_hb->add_spacer();
@@ -1232,14 +1387,12 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_vb->add_child(split_sheet_panel);
split_sheet_preview = memnew(TextureRect);
- split_sheet_preview->set_expand(true);
+ split_sheet_preview->set_ignore_texture_size(true);
split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS);
split_sheet_preview->connect("draw", callable_mp(this, &SpriteFramesEditor::_sheet_preview_draw));
split_sheet_preview->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_preview_input));
split_sheet_scroll = memnew(ScrollContainer);
- split_sheet_scroll->set_enable_h_scroll(true);
- split_sheet_scroll->set_enable_v_scroll(true);
split_sheet_scroll->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_scroll_input));
split_sheet_panel->add_child(split_sheet_scroll);
CenterContainer *cc = memnew(CenterContainer);
@@ -1331,20 +1484,19 @@ bool SpriteFramesEditorPlugin::handles(Object *p_object) const {
void SpriteFramesEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
- editor->make_bottom_panel_item_visible(frames_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(frames_editor);
} else {
button->hide();
if (frames_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
}
}
-SpriteFramesEditorPlugin::SpriteFramesEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+SpriteFramesEditorPlugin::SpriteFramesEditorPlugin() {
frames_editor = memnew(SpriteFramesEditor);
frames_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
- button = editor->add_bottom_panel_item(TTR("SpriteFrames"), frames_editor);
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("SpriteFrames"), frames_editor);
button->hide();
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 9732384000..3230228fdd 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,64 +31,81 @@
#ifndef SPRITE_FRAMES_EDITOR_PLUGIN_H
#define SPRITE_FRAMES_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/animated_sprite_2d.h"
+#include "scene/gui/button.h"
+#include "scene/gui/check_button.h"
#include "scene/gui/dialogs.h"
-#include "scene/gui/file_dialog.h"
+#include "scene/gui/item_list.h"
#include "scene/gui/scroll_container.h"
+#include "scene/gui/spin_box.h"
#include "scene/gui/split_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
+class EditorFileDialog;
+
class SpriteFramesEditor : public HSplitContainer {
GDCLASS(SpriteFramesEditor, HSplitContainer);
- Button *load;
- Button *load_sheet;
- Button *_delete;
- Button *copy;
- Button *paste;
- Button *empty;
- Button *empty2;
- Button *move_up;
- Button *move_down;
- Button *zoom_out;
- Button *zoom_reset;
- Button *zoom_in;
- ItemList *tree;
+ enum {
+ PARAM_USE_CURRENT, // Used in callbacks to indicate `dominant_param` should be not updated.
+ PARAM_FRAME_COUNT, // Keep "Horizontal" & "Vertial" values.
+ PARAM_SIZE, // Keep "Size" values.
+ };
+ int dominant_param = PARAM_FRAME_COUNT;
+
+ Button *load = nullptr;
+ Button *load_sheet = nullptr;
+ Button *_delete = nullptr;
+ Button *copy = nullptr;
+ Button *paste = nullptr;
+ Button *empty = nullptr;
+ Button *empty2 = nullptr;
+ Button *move_up = nullptr;
+ Button *move_down = nullptr;
+ Button *zoom_out = nullptr;
+ Button *zoom_reset = nullptr;
+ Button *zoom_in = nullptr;
+ ItemList *tree = nullptr;
bool loading_scene;
int sel;
- Button *new_anim;
- Button *remove_anim;
+ Button *new_anim = nullptr;
+ Button *remove_anim = nullptr;
- Tree *animations;
- SpinBox *anim_speed;
- CheckButton *anim_loop;
+ Tree *animations = nullptr;
+ SpinBox *anim_speed = nullptr;
+ CheckButton *anim_loop = nullptr;
- EditorFileDialog *file;
+ EditorFileDialog *file = nullptr;
- AcceptDialog *dialog;
+ AcceptDialog *dialog = nullptr;
- SpriteFrames *frames;
+ SpriteFrames *frames = nullptr;
StringName edited_anim;
- ConfirmationDialog *delete_dialog;
-
- ConfirmationDialog *split_sheet_dialog;
- ScrollContainer *split_sheet_scroll;
- TextureRect *split_sheet_preview;
- SpinBox *split_sheet_h;
- SpinBox *split_sheet_v;
- Button *split_sheet_zoom_out;
- Button *split_sheet_zoom_reset;
- Button *split_sheet_zoom_in;
- EditorFileDialog *file_split_sheet;
+ ConfirmationDialog *delete_dialog = nullptr;
+
+ ConfirmationDialog *split_sheet_dialog = nullptr;
+ ScrollContainer *split_sheet_scroll = nullptr;
+ TextureRect *split_sheet_preview = nullptr;
+ SpinBox *split_sheet_h = nullptr;
+ SpinBox *split_sheet_v = nullptr;
+ SpinBox *split_sheet_size_x = nullptr;
+ SpinBox *split_sheet_size_y = nullptr;
+ SpinBox *split_sheet_sep_x = nullptr;
+ SpinBox *split_sheet_sep_y = nullptr;
+ SpinBox *split_sheet_offset_x = nullptr;
+ SpinBox *split_sheet_offset_y = nullptr;
+ Button *split_sheet_zoom_out = nullptr;
+ Button *split_sheet_zoom_reset = nullptr;
+ Button *split_sheet_zoom_in = nullptr;
+ EditorFileDialog *file_split_sheet = nullptr;
Set<int> frames_selected;
Set<int> frames_toggled_by_mouse_hover;
- int last_frame_selected;
+ int last_frame_selected = 0;
float scale_ratio;
int thumbnail_default_size;
@@ -99,6 +116,11 @@ class SpriteFramesEditor : public HSplitContainer {
float max_sheet_zoom;
float min_sheet_zoom;
+ Size2i _get_frame_count() const;
+ Size2i _get_frame_size() const;
+ Size2i _get_offset() const;
+ Size2i _get_separation() const;
+
void _load_pressed();
void _file_load_request(const Vector<String> &p_path, int p_at_pos = -1);
void _copy_pressed();
@@ -124,8 +146,9 @@ class SpriteFramesEditor : public HSplitContainer {
void _zoom_reset();
bool updating;
+ bool updating_split_settings = false; // Skip SpinBox/Range callback when setting value by code.
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
@@ -135,10 +158,11 @@ class SpriteFramesEditor : public HSplitContainer {
void _prepare_sprite_sheet(const String &p_file);
int _sheet_preview_position_to_frame_index(const Vector2 &p_position);
void _sheet_preview_draw();
- void _sheet_spin_changed(double);
+ void _sheet_spin_changed(double p_value, int p_dominant_param);
void _sheet_preview_input(const Ref<InputEvent> &p_event);
void _sheet_scroll_input(const Ref<InputEvent> &p_event);
void _sheet_add_frames();
+ void _sheet_zoom_on_position(float p_zoom, const Vector2 &p_position);
void _sheet_zoom_in();
void _sheet_zoom_out();
void _sheet_zoom_reset();
@@ -146,7 +170,6 @@ class SpriteFramesEditor : public HSplitContainer {
protected:
void _notification(int p_what);
- virtual void gui_input(const Ref<InputEvent> &p_event) override;
static void _bind_methods();
public:
@@ -159,9 +182,8 @@ public:
class SpriteFramesEditorPlugin : public EditorPlugin {
GDCLASS(SpriteFramesEditorPlugin, EditorPlugin);
- SpriteFramesEditor *frames_editor;
- EditorNode *editor;
- Button *button;
+ SpriteFramesEditor *frames_editor = nullptr;
+ Button *button = nullptr;
public:
virtual String get_name() const override { return "SpriteFrames"; }
@@ -170,7 +192,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- SpriteFramesEditorPlugin(EditorNode *p_node);
+ SpriteFramesEditorPlugin();
~SpriteFramesEditorPlugin();
};
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index 91c5e96f08..a3cbaf527e 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -44,13 +44,6 @@ void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) {
add_custom_control(preview);
}
-bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, bool p_wide) {
- return false; //do not want
-}
-
-void EditorInspectorPluginStyleBox::parse_end() {
-}
-
void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
if (stylebox.is_valid()) {
stylebox->disconnect("changed", callable_mp(this, &StyleBoxPreview::_sb_changed));
@@ -91,7 +84,7 @@ StyleBoxPreview::StyleBoxPreview() {
add_margin_child(TTR("Preview:"), preview);
}
-StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) {
+StyleBoxEditorPlugin::StyleBoxEditorPlugin() {
Ref<EditorInspectorPluginStyleBox> inspector_plugin;
inspector_plugin.instantiate();
add_inspector_plugin(inspector_plugin);
diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h
index 8ca348bd80..663440ae31 100644
--- a/editor/plugins/style_box_editor_plugin.h
+++ b/editor/plugins/style_box_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,7 +32,7 @@
#define STYLE_BOX_EDITOR_PLUGIN_H
#include "editor/editor_inspector.h"
-#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
#include "scene/gui/option_button.h"
#include "scene/gui/texture_rect.h"
#include "scene/resources/style_box.h"
@@ -40,7 +40,7 @@
class StyleBoxPreview : public VBoxContainer {
GDCLASS(StyleBoxPreview, VBoxContainer);
- Control *preview;
+ Control *preview = nullptr;
Ref<StyleBox> stylebox;
void _sb_changed();
@@ -61,8 +61,6 @@ class EditorInspectorPluginStyleBox : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
- virtual void parse_end() override;
};
class StyleBoxEditorPlugin : public EditorPlugin {
@@ -71,7 +69,7 @@ class StyleBoxEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "StyleBox"; }
- StyleBoxEditorPlugin(EditorNode *p_node);
+ StyleBoxEditorPlugin();
};
#endif // STYLE_BOX_EDITOR_PLUGIN_H
diff --git a/editor/plugins/sub_viewport_preview_editor_plugin.cpp b/editor/plugins/sub_viewport_preview_editor_plugin.cpp
index 75c47bda2e..c8bb0cd56f 100644
--- a/editor/plugins/sub_viewport_preview_editor_plugin.cpp
+++ b/editor/plugins/sub_viewport_preview_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -43,7 +43,7 @@ void EditorInspectorPluginSubViewportPreview::parse_begin(Object *p_object) {
add_custom_control(sub_viewport_preview);
}
-SubViewportPreviewEditorPlugin::SubViewportPreviewEditorPlugin(EditorNode *p_node) {
+SubViewportPreviewEditorPlugin::SubViewportPreviewEditorPlugin() {
Ref<EditorInspectorPluginSubViewportPreview> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/sub_viewport_preview_editor_plugin.h b/editor/plugins/sub_viewport_preview_editor_plugin.h
index 03b8b678d1..269553ffb1 100644
--- a/editor/plugins/sub_viewport_preview_editor_plugin.h
+++ b/editor/plugins/sub_viewport_preview_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef SUB_VIEWPORT_PREVIEW_EDITOR_PLUGIN_H
#define SUB_VIEWPORT_PREVIEW_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/texture_editor_plugin.h"
#include "scene/main/viewport.h"
@@ -50,7 +49,7 @@ class SubViewportPreviewEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "SubViewportPreview"; }
- SubViewportPreviewEditorPlugin(EditorNode *p_node);
+ SubViewportPreviewEditorPlugin();
};
#endif // SUB_VIEWPORT_PREVIEW_EDITOR_PLUGIN_H
diff --git a/editor/plugins/text_control_editor_plugin.cpp b/editor/plugins/text_control_editor_plugin.cpp
new file mode 100644
index 0000000000..4290888e94
--- /dev/null
+++ b/editor/plugins/text_control_editor_plugin.cpp
@@ -0,0 +1,660 @@
+/*************************************************************************/
+/* text_control_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "text_control_editor_plugin.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/multi_node_edit.h"
+
+void TextControlEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (!EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) {
+ EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts), make_binds(""));
+ }
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ clear_formatting->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) {
+ EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts));
+ }
+ } break;
+ }
+}
+
+void TextControlEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_control"), &TextControlEditor::_update_control);
+}
+
+void TextControlEditor::_find_resources(EditorFileSystemDirectory *p_dir) {
+ for (int i = 0; i < p_dir->get_subdir_count(); i++) {
+ _find_resources(p_dir->get_subdir(i));
+ }
+
+ for (int i = 0; i < p_dir->get_file_count(); i++) {
+ if (p_dir->get_file_type(i) == "FontData") {
+ Ref<FontData> fd = ResourceLoader::load(p_dir->get_file_path(i));
+ if (fd.is_valid()) {
+ String name = fd->get_font_name();
+ String sty = fd->get_font_style_name();
+ if (sty.is_empty()) {
+ sty = "Default";
+ }
+ fonts[name][sty] = p_dir->get_file_path(i);
+ }
+ }
+ }
+}
+
+void TextControlEditor::_reload_fonts(const String &p_path) {
+ fonts.clear();
+ _find_resources(EditorFileSystem::get_singleton()->get_filesystem());
+ _update_control();
+}
+
+void TextControlEditor::_update_fonts_menu() {
+ font_list->clear();
+ font_list->add_item(TTR("[Theme Default]"), FONT_INFO_THEME_DEFAULT);
+ if (custom_font.is_valid()) {
+ font_list->add_item(TTR("[Custom Font]"), FONT_INFO_USER_CUSTOM);
+ }
+
+ int id = FONT_INFO_ID;
+ for (Map<String, Map<String, String>>::Element *E = fonts.front(); E; E = E->next()) {
+ font_list->add_item(E->key(), id++);
+ }
+
+ if (font_list->get_item_count() > 1) {
+ font_list->show();
+ } else {
+ font_list->hide();
+ }
+}
+
+void TextControlEditor::_update_styles_menu() {
+ font_style_list->clear();
+ if ((font_list->get_selected_id() >= FONT_INFO_ID)) {
+ const String &name = font_list->get_item_text(font_list->get_selected());
+ for (Map<String, String>::Element *E = fonts[name].front(); E; E = E->next()) {
+ font_style_list->add_item(E->key());
+ }
+ } else if (font_list->get_selected() >= 0) {
+ font_style_list->add_item("Default");
+ }
+
+ if (font_style_list->get_item_count() > 1) {
+ font_style_list->show();
+ } else {
+ font_style_list->hide();
+ }
+}
+
+void TextControlEditor::_update_control() {
+ if (!edited_controls.is_empty()) {
+ String font_selected;
+ bool same_font = true;
+ String style_selected;
+ bool same_style = true;
+ int font_size = 0;
+ bool same_font_size = true;
+ int outline_size = 0;
+ bool same_outline_size = true;
+ Color font_color = Color{ 1.0f, 1.0f, 1.0f };
+ bool same_font_color = true;
+ Color outline_color = Color{ 1.0f, 1.0f, 1.0f };
+ bool same_outline_color = true;
+
+ int count = edited_controls.size();
+ for (int i = 0; i < count; ++i) {
+ Control *edited_control = edited_controls[i];
+
+ StringName edited_color;
+ StringName edited_font;
+ StringName edited_font_size;
+
+ // Get override names.
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_color = SNAME("default_color");
+ edited_font = SNAME("normal_font");
+ edited_font_size = SNAME("normal_font_size");
+ } else {
+ edited_color = SNAME("font_color");
+ edited_font = SNAME("font");
+ edited_font_size = SNAME("font_size");
+ }
+
+ // Get font override.
+ Ref<Font> font;
+ if (edited_control->has_theme_font_override(edited_font)) {
+ font = edited_control->get_theme_font(edited_font);
+ }
+
+ if (font.is_valid()) {
+ if (font->get_data_count() != 1) {
+ if (i > 0) {
+ same_font = same_font && (custom_font == font);
+ }
+ custom_font = font;
+
+ font_selected = TTR("[Custom Font]");
+ same_style = false;
+ } else {
+ String name = font->get_data(0)->get_font_name();
+ String style = font->get_data(0)->get_font_style_name();
+ if (fonts.has(name) && fonts[name].has(style)) {
+ if (i > 0) {
+ same_font = same_font && (name == font_selected);
+ same_style = same_style && (style == style_selected);
+ }
+ font_selected = name;
+ style_selected = style;
+ } else {
+ if (i > 0) {
+ same_font = same_font && (custom_font == font);
+ }
+ custom_font = font;
+
+ font_selected = TTR("[Custom Font]");
+ same_style = false;
+ }
+ }
+ } else {
+ if (i > 0) {
+ same_font = same_font && (font_selected == TTR("[Theme Default]"));
+ }
+
+ font_selected = TTR("[Theme Default]");
+ same_style = false;
+ }
+
+ int current_font_size = edited_control->get_theme_font_size(edited_font_size);
+ int current_outline_size = edited_control->get_theme_constant(SNAME("outline_size"));
+ Color current_font_color = edited_control->get_theme_color(edited_color);
+ Color current_outline_color = edited_control->get_theme_color(SNAME("font_outline_color"));
+ if (i > 0) {
+ same_font_size = same_font_size && (font_size == current_font_size);
+ same_outline_size = same_outline_size && (outline_size == current_outline_size);
+ same_font_color = same_font_color && (font_color == current_font_color);
+ same_outline_color = same_outline_color && (outline_color == current_outline_color);
+ }
+
+ font_size = current_font_size;
+ outline_size = current_outline_size;
+ font_color = current_font_color;
+ outline_color = current_outline_color;
+ }
+ _update_fonts_menu();
+ if (same_font) {
+ for (int j = 0; j < font_list->get_item_count(); j++) {
+ if (font_list->get_item_text(j) == font_selected) {
+ font_list->select(j);
+ break;
+ }
+ }
+ } else {
+ custom_font = Ref<Font>();
+ font_list->select(-1);
+ }
+
+ _update_styles_menu();
+ if (same_style) {
+ for (int j = 0; j < font_style_list->get_item_count(); j++) {
+ if (font_style_list->get_item_text(j) == style_selected) {
+ font_style_list->select(j);
+ break;
+ }
+ }
+ } else {
+ font_style_list->select(-1);
+ }
+
+ // Get other theme overrides.
+ font_size_list->set_block_signals(true);
+ if (same_font_size) {
+ font_size_list->get_line_edit()->set_text(String::num_uint64(font_size));
+ font_size_list->set_value(font_size);
+ } else {
+ font_size_list->get_line_edit()->set_text("");
+ }
+ font_size_list->set_block_signals(false);
+
+ outline_size_list->set_block_signals(true);
+ if (same_outline_size) {
+ outline_size_list->get_line_edit()->set_text(String::num_uint64(outline_size));
+ outline_size_list->set_value(outline_size);
+ } else {
+ outline_size_list->get_line_edit()->set_text("");
+ }
+ outline_size_list->set_block_signals(false);
+
+ if (!same_font_color) {
+ font_color = Color{ 1.0f, 1.0f, 1.0f };
+ }
+ font_color_picker->set_pick_color(font_color);
+
+ if (!same_outline_color) {
+ outline_color = Color{ 1.0f, 1.0f, 1.0f };
+ }
+ outline_color_picker->set_pick_color(outline_color);
+ }
+}
+
+void TextControlEditor::_font_selected(int p_id) {
+ _update_styles_menu();
+ _set_font();
+}
+
+void TextControlEditor::_font_style_selected(int p_id) {
+ _set_font();
+}
+
+void TextControlEditor::_set_font() {
+ if (edited_controls.is_empty()) {
+ return;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Font"));
+
+ int count = edited_controls.size();
+ for (int i = 0; i < count; ++i) {
+ Control *edited_control = edited_controls[i];
+
+ StringName edited_font;
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_font = SNAME("normal_font");
+ } else {
+ edited_font = SNAME("font");
+ }
+
+ if (font_list->get_selected_id() == FONT_INFO_THEME_DEFAULT) {
+ // Remove font override.
+ ur->add_do_method(edited_control, "remove_theme_font_override", edited_font);
+ } else if (font_list->get_selected_id() == FONT_INFO_USER_CUSTOM) {
+ // Restore "custom_font".
+ ur->add_do_method(edited_control, "add_theme_font_override", edited_font, custom_font);
+ } else if (font_list->get_selected() >= 0) {
+ // Load new font resource using selected name and style.
+ String name = font_list->get_item_text(font_list->get_selected());
+ String style = font_style_list->get_item_text(font_style_list->get_selected());
+ if (style.is_empty()) {
+ style = "Default";
+ }
+ if (fonts.has(name)) {
+ Ref<FontData> fd = ResourceLoader::load(fonts[name][style]);
+ if (fd.is_valid()) {
+ Ref<Font> font;
+ font.instantiate();
+ font->add_data(fd);
+ ur->add_do_method(edited_control, "add_theme_font_override", edited_font, font);
+ }
+ }
+ }
+
+ if (edited_control->has_theme_font_override(edited_font)) {
+ ur->add_undo_method(edited_control, "add_theme_font_override", edited_font, edited_control->get_theme_font(edited_font));
+ } else {
+ ur->add_undo_method(edited_control, "remove_theme_font_override", edited_font);
+ }
+ }
+
+ ur->add_do_method(this, "_update_control");
+ ur->add_undo_method(this, "_update_control");
+
+ ur->commit_action();
+}
+
+void TextControlEditor::_font_size_selected(double p_size) {
+ if (edited_controls.is_empty()) {
+ return;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Font Size"));
+
+ int count = edited_controls.size();
+ for (int i = 0; i < count; ++i) {
+ Control *edited_control = edited_controls[i];
+
+ StringName edited_font_size;
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_font_size = SNAME("normal_font_size");
+ } else {
+ edited_font_size = SNAME("font_size");
+ }
+
+ ur->add_do_method(edited_control, "add_theme_font_size_override", edited_font_size, p_size);
+ if (edited_control->has_theme_font_size_override(edited_font_size)) {
+ ur->add_undo_method(edited_control, "add_theme_font_size_override", edited_font_size, edited_control->get_theme_font_size(edited_font_size));
+ } else {
+ ur->add_undo_method(edited_control, "remove_theme_font_size_override", edited_font_size);
+ }
+ }
+
+ ur->add_do_method(this, "_update_control");
+ ur->add_undo_method(this, "_update_control");
+
+ ur->commit_action();
+}
+
+void TextControlEditor::_outline_size_selected(double p_size) {
+ if (edited_controls.is_empty()) {
+ return;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Font Outline Size"));
+
+ int count = edited_controls.size();
+ for (int i = 0; i < count; ++i) {
+ Control *edited_control = edited_controls[i];
+
+ ur->add_do_method(edited_control, "add_theme_constant_override", "outline_size", p_size);
+ if (edited_control->has_theme_constant_override("outline_size")) {
+ ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant(SNAME("outline_size")));
+ } else {
+ ur->add_undo_method(edited_control, "remove_theme_constant_override", "outline_size");
+ }
+ }
+
+ ur->add_do_method(this, "_update_control");
+ ur->add_undo_method(this, "_update_control");
+
+ ur->commit_action();
+}
+
+void TextControlEditor::_font_color_changed(const Color &p_color) {
+ if (edited_controls.is_empty()) {
+ return;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Font Color"), UndoRedo::MERGE_ENDS);
+
+ int count = edited_controls.size();
+ for (int i = 0; i < count; ++i) {
+ Control *edited_control = edited_controls[i];
+
+ StringName edited_color;
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_color = SNAME("default_color");
+ } else {
+ edited_color = SNAME("font_color");
+ }
+
+ ur->add_do_method(edited_control, "add_theme_color_override", edited_color, p_color);
+ if (edited_control->has_theme_color_override(edited_color)) {
+ ur->add_undo_method(edited_control, "add_theme_color_override", edited_color, edited_control->get_theme_color(edited_color));
+ } else {
+ ur->add_undo_method(edited_control, "remove_theme_color_override", edited_color);
+ }
+ }
+
+ ur->add_do_method(this, "_update_control");
+ ur->add_undo_method(this, "_update_control");
+
+ ur->commit_action();
+}
+
+void TextControlEditor::_outline_color_changed(const Color &p_color) {
+ if (edited_controls.is_empty()) {
+ return;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Font Outline Color"), UndoRedo::MERGE_ENDS);
+
+ int count = edited_controls.size();
+ for (int i = 0; i < count; ++i) {
+ Control *edited_control = edited_controls[i];
+
+ ur->add_do_method(edited_control, "add_theme_color_override", "font_outline_color", p_color);
+ if (edited_control->has_theme_color_override("font_outline_color")) {
+ ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color(SNAME("font_outline_color")));
+ } else {
+ ur->add_undo_method(edited_control, "remove_theme_color_override", "font_outline_color");
+ }
+ }
+
+ ur->add_do_method(this, "_update_control");
+ ur->add_undo_method(this, "_update_control");
+
+ ur->commit_action();
+}
+
+void TextControlEditor::_clear_formatting() {
+ if (edited_controls.is_empty()) {
+ return;
+ }
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Clear Control Formatting"));
+
+ int count = edited_controls.size();
+ for (int i = 0; i < count; ++i) {
+ Control *edited_control = edited_controls[i];
+
+ StringName edited_color;
+ StringName edited_font;
+ StringName edited_font_size;
+
+ // Get override names.
+ if (Object::cast_to<RichTextLabel>(edited_control)) {
+ edited_color = SNAME("default_color");
+ edited_font = SNAME("normal_font");
+ edited_font_size = SNAME("normal_font_size");
+ } else {
+ edited_color = SNAME("font_color");
+ edited_font = SNAME("font");
+ edited_font_size = SNAME("font_size");
+ }
+
+ ur->add_do_method(edited_control, "begin_bulk_theme_override");
+ ur->add_undo_method(edited_control, "begin_bulk_theme_override");
+
+ ur->add_do_method(edited_control, "remove_theme_font_override", edited_font);
+ if (edited_control->has_theme_font_override(edited_font)) {
+ ur->add_undo_method(edited_control, "add_theme_font_override", edited_font, edited_control->get_theme_font(edited_font));
+ }
+
+ ur->add_do_method(edited_control, "remove_theme_font_size_override", edited_font_size);
+ if (edited_control->has_theme_font_size_override(edited_font_size)) {
+ ur->add_undo_method(edited_control, "add_theme_font_size_override", edited_font_size, edited_control->get_theme_font_size(edited_font_size));
+ }
+
+ ur->add_do_method(edited_control, "remove_theme_color_override", edited_color);
+ if (edited_control->has_theme_color_override(edited_color)) {
+ ur->add_undo_method(edited_control, "add_theme_color_override", edited_color, edited_control->get_theme_color(edited_color));
+ }
+
+ ur->add_do_method(edited_control, "remove_theme_color_override", "font_outline_color");
+ if (edited_control->has_theme_color_override("font_outline_color")) {
+ ur->add_undo_method(edited_control, "add_theme_color_override", "font_outline_color", edited_control->get_theme_color(SNAME("font_outline_color")));
+ }
+
+ ur->add_do_method(edited_control, "remove_theme_constant_override", "outline_size");
+ if (edited_control->has_theme_constant_override("outline_size")) {
+ ur->add_undo_method(edited_control, "add_theme_constant_override", "outline_size", edited_control->get_theme_constant(SNAME("outline_size")));
+ }
+
+ ur->add_do_method(edited_control, "end_bulk_theme_override");
+ ur->add_undo_method(edited_control, "end_bulk_theme_override");
+ }
+
+ ur->add_do_method(this, "_update_control");
+ ur->add_undo_method(this, "_update_control");
+
+ ur->commit_action();
+}
+
+void TextControlEditor::edit(Object *p_object) {
+ Control *ctrl = Object::cast_to<Control>(p_object);
+ MultiNodeEdit *multi_node = Object::cast_to<MultiNodeEdit>(p_object);
+
+ edited_controls.clear();
+ custom_font = Ref<Font>();
+ if (ctrl) {
+ edited_controls.append(ctrl);
+ _update_control();
+ } else if (multi_node && handles(multi_node)) {
+ int count = multi_node->get_node_count();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
+
+ for (int i = 0; i < count; ++i) {
+ Control *child = Object::cast_to<Control>(scene->get_node(multi_node->get_node(i)));
+ edited_controls.append(child);
+ }
+ _update_control();
+ }
+}
+
+bool TextControlEditor::handles(Object *p_object) const {
+ Control *ctrl = Object::cast_to<Control>(p_object);
+ MultiNodeEdit *multi_node = Object::cast_to<MultiNodeEdit>(p_object);
+
+ if (!ctrl && !multi_node) {
+ return false;
+ } else if (ctrl) {
+ bool valid = false;
+ ctrl->get("text", &valid);
+ return valid;
+ } else {
+ bool valid = true;
+ int count = multi_node->get_node_count();
+ Node *scene = EditorNode::get_singleton()->get_edited_scene();
+
+ for (int i = 0; i < count; ++i) {
+ bool temp_valid = false;
+ Control *child = Object::cast_to<Control>(scene->get_node(multi_node->get_node(i)));
+ if (child) {
+ child->get("text", &temp_valid);
+ }
+ valid = valid && temp_valid;
+
+ if (!valid) {
+ break;
+ }
+ }
+
+ return valid;
+ }
+}
+
+TextControlEditor::TextControlEditor() {
+ add_child(memnew(VSeparator));
+
+ font_list = memnew(OptionButton);
+ font_list->set_flat(true);
+ font_list->set_tooltip(TTR("Font"));
+ add_child(font_list);
+ font_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_selected));
+
+ font_style_list = memnew(OptionButton);
+ font_style_list->set_flat(true);
+ font_style_list->set_tooltip(TTR("Font style"));
+ font_style_list->set_toggle_mode(true);
+ add_child(font_style_list);
+ font_style_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_style_selected));
+
+ font_size_list = memnew(SpinBox);
+ font_size_list->set_tooltip(TTR("Font Size"));
+ font_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);
+ font_size_list->set_min(6);
+ font_size_list->set_step(1);
+ font_size_list->set_max(96);
+ font_size_list->get_line_edit()->set_flat(true);
+ add_child(font_size_list);
+ font_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_font_size_selected));
+
+ font_color_picker = memnew(ColorPickerButton);
+ font_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE);
+ font_color_picker->set_flat(true);
+ font_color_picker->set_tooltip(TTR("Text Color"));
+ add_child(font_color_picker);
+ font_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_font_color_changed));
+
+ add_child(memnew(VSeparator));
+
+ outline_size_list = memnew(SpinBox);
+ outline_size_list->set_tooltip(TTR("Outline Size"));
+ outline_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);
+ outline_size_list->set_min(0);
+ outline_size_list->set_step(1);
+ outline_size_list->set_max(96);
+ outline_size_list->get_line_edit()->set_flat(true);
+ add_child(outline_size_list);
+ outline_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_outline_size_selected));
+
+ outline_color_picker = memnew(ColorPickerButton);
+ outline_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE);
+ outline_color_picker->set_flat(true);
+ outline_color_picker->set_tooltip(TTR("Outline Color"));
+ add_child(outline_color_picker);
+ outline_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_outline_color_changed));
+
+ add_child(memnew(VSeparator));
+
+ clear_formatting = memnew(Button);
+ clear_formatting->set_flat(true);
+ clear_formatting->set_tooltip(TTR("Clear Formatting"));
+ add_child(clear_formatting);
+ clear_formatting->connect("pressed", callable_mp(this, &TextControlEditor::_clear_formatting));
+}
+
+/*************************************************************************/
+
+void TextControlEditorPlugin::edit(Object *p_object) {
+ text_ctl_editor->edit(p_object);
+}
+
+bool TextControlEditorPlugin::handles(Object *p_object) const {
+ return text_ctl_editor->handles(p_object);
+}
+
+void TextControlEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ text_ctl_editor->show();
+ } else {
+ text_ctl_editor->hide();
+ text_ctl_editor->edit(nullptr);
+ }
+}
+
+TextControlEditorPlugin::TextControlEditorPlugin() {
+ text_ctl_editor = memnew(TextControlEditor);
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(text_ctl_editor);
+
+ text_ctl_editor->hide();
+}
diff --git a/editor/plugins/text_control_editor_plugin.h b/editor/plugins/text_control_editor_plugin.h
new file mode 100644
index 0000000000..a475f6eba3
--- /dev/null
+++ b/editor/plugins/text_control_editor_plugin.h
@@ -0,0 +1,115 @@
+/*************************************************************************/
+/* text_control_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 TEXT_CONTROL_EDITOR_PLUGIN_H
+#define TEXT_CONTROL_EDITOR_PLUGIN_H
+
+#include "canvas_item_editor_plugin.h"
+#include "editor/editor_file_system.h"
+#include "editor/editor_inspector.h"
+#include "editor/editor_plugin.h"
+#include "scene/gui/color_picker.h"
+#include "scene/gui/color_rect.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/popup_menu.h"
+
+/*************************************************************************/
+
+class TextControlEditor : public HBoxContainer {
+ GDCLASS(TextControlEditor, HBoxContainer);
+
+ enum FontInfoID {
+ FONT_INFO_THEME_DEFAULT = 0,
+ FONT_INFO_USER_CUSTOM = 1,
+ FONT_INFO_ID = 100,
+ };
+
+ Map<String, Map<String, String>> fonts;
+
+ OptionButton *font_list = nullptr;
+ SpinBox *font_size_list = nullptr;
+ OptionButton *font_style_list = nullptr;
+ ColorPickerButton *font_color_picker = nullptr;
+ SpinBox *outline_size_list = nullptr;
+ ColorPickerButton *outline_color_picker = nullptr;
+ Button *clear_formatting = nullptr;
+
+ Vector<Control *> edited_controls;
+ Ref<Font> custom_font;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+ void _find_resources(EditorFileSystemDirectory *p_dir);
+ void _reload_fonts(const String &p_path);
+
+ void _update_fonts_menu();
+ void _update_styles_menu();
+ void _update_control();
+
+ void _font_selected(int p_id);
+ void _font_style_selected(int p_id);
+ void _set_font();
+
+ void _font_size_selected(double p_size);
+ void _outline_size_selected(double p_size);
+
+ void _font_color_changed(const Color &p_color);
+ void _outline_color_changed(const Color &p_color);
+
+ void _clear_formatting();
+
+public:
+ void edit(Object *p_object);
+ bool handles(Object *p_object) const;
+
+ TextControlEditor();
+};
+
+/*************************************************************************/
+
+class TextControlEditorPlugin : public EditorPlugin {
+ GDCLASS(TextControlEditorPlugin, EditorPlugin);
+
+ TextControlEditor *text_ctl_editor = nullptr;
+
+public:
+ virtual String get_name() const override { return "TextControlFontEditor"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ TextControlEditorPlugin();
+};
+
+#endif // TEXT_CONTROL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 3b45f32927..97ecc234e6 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -65,18 +65,21 @@ void TextEditor::_load_theme_settings() {
String TextEditor::get_name() {
String name;
- if (!text_file->is_built_in()) {
- name = text_file->get_path().get_file();
- if (is_unsaved()) {
- if (text_file->get_path().is_empty()) {
- name = TTR("[unsaved]");
- }
- name += "(*)";
+ name = text_file->get_path().get_file();
+ if (name.is_empty()) {
+ // This appears for newly created built-in text_files before saving the scene.
+ name = TTR("[unsaved]");
+ } else if (text_file->is_built_in()) {
+ const String &text_file_name = text_file->get_name();
+ if (!text_file_name.is_empty()) {
+ // If the built-in text_file has a custom resource name defined,
+ // display the built-in text_file name as follows: `ResourceName (scene_file.tscn)`
+ name = vformat("%s (%s)", text_file_name, name.get_slice("::", 0));
}
- } else if (text_file->get_name() != "") {
- name = text_file->get_name();
- } else {
- name = text_file->get_class() + "(" + itos(text_file->get_instance_id()) + ")";
+ }
+
+ if (is_unsaved()) {
+ name += "(*)";
}
return name;
@@ -86,11 +89,11 @@ Ref<Texture2D> TextEditor::get_theme_icon() {
return EditorNode::get_singleton()->get_object_icon(text_file.ptr(), "");
}
-RES TextEditor::get_edited_resource() const {
+Ref<Resource> TextEditor::get_edited_resource() const {
return text_file;
}
-void TextEditor::set_edited_resource(const RES &p_res) {
+void TextEditor::set_edited_resource(const Ref<Resource> &p_res) {
ERR_FAIL_COND(text_file.is_valid());
ERR_FAIL_COND(p_res.is_null());
@@ -176,7 +179,7 @@ void TextEditor::_update_bookmark_list() {
}
bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\"");
- bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]);
+ bookmarks_menu->set_item_metadata(-1, bookmark_list[i]);
}
}
@@ -269,8 +272,10 @@ void TextEditor::update_settings() {
code_editor->update_editor_settings();
}
-void TextEditor::set_tooltip_request_func(String p_method, Object *p_obj) {
- code_editor->get_text_editor()->set_tooltip_request_func(p_obj, p_method, this);
+void TextEditor::set_tooltip_request_func(const Callable &p_toolip_callback) {
+ Variant args[1] = { this };
+ const Variant *argp[] = { &args[0] };
+ code_editor->get_text_editor()->set_tooltip_request_func(p_toolip_callback.bind(argp, 1));
}
Control *TextEditor::get_edit_menu() {
@@ -407,7 +412,7 @@ void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) {
code_editor->convert_case(p_case);
}
-static ScriptEditorBase *create_editor(const RES &p_resource) {
+static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
if (Object::cast_to<TextFile>(*p_resource)) {
return memnew(TextEditor);
}
@@ -422,7 +427,7 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb->get_button_index() == MouseButton::RIGHT) {
CodeEdit *tx = code_editor->get_text_editor();
Point2i pos = tx->get_line_column_at_pos(mb->get_global_position() - tx->get_global_position());
@@ -504,8 +509,8 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is
context_menu->set_item_disabled(context_menu->get_item_index(EDIT_UNDO), !tx->has_undo());
context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo());
- context_menu->set_position(get_global_transform().xform(p_position));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->set_position(get_screen_position() + p_position);
+ context_menu->reset_size();
context_menu->popup();
}
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 7404557f46..9b6d568382 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -109,8 +109,8 @@ public:
virtual String get_name() override;
virtual Ref<Texture2D> get_theme_icon() override;
- virtual RES get_edited_resource() const override;
- virtual void set_edited_resource(const RES &p_res) override;
+ virtual Ref<Resource> get_edited_resource() const override;
+ virtual void set_edited_resource(const Ref<Resource> &p_res) override;
virtual void enable_editor() override;
virtual void reload_text() override;
virtual void apply_code() override;
@@ -135,7 +135,7 @@ public:
virtual bool show_members_overview() override;
virtual bool can_lose_focus_on_node_selection() override { return true; }
virtual void set_debugger_active(bool p_active) override;
- virtual void set_tooltip_request_func(String p_method, Object *p_obj) override;
+ virtual void set_tooltip_request_func(const Callable &p_toolip_callback) override;
virtual void add_callback(const String &p_function, PackedStringArray p_args) override;
void update_toggle_scripts_button() override;
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index bd1923f4ab..0fc7079a24 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,27 +30,22 @@
#include "texture_3d_editor_plugin.h"
-#include "core/config/project_settings.h"
-#include "core/io/resource_loader.h"
-#include "editor/editor_settings.h"
-
void Texture3DEditor::_texture_rect_draw() {
texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1));
}
void Texture3DEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- //get_scene()->connect("node_removed",this,"_node_removed");
- }
- if (p_what == NOTIFICATION_RESIZED) {
- _texture_rect_update_area();
- }
+ switch (p_what) {
+ case NOTIFICATION_RESIZED: {
+ _texture_rect_update_area();
+ } break;
- if (p_what == NOTIFICATION_DRAW) {
- Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
- Size2 size = get_size();
+ case NOTIFICATION_DRAW: {
+ Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
+ Size2 size = get_size();
- draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ } break;
}
}
@@ -173,7 +168,7 @@ Texture3DEditor::Texture3DEditor() {
info->set_v_grow_direction(GROW_DIRECTION_BEGIN);
info->add_theme_color_override("font_color", Color(1, 1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5));
- info->add_theme_constant_override("shadow_as_outline", 1);
+ info->add_theme_constant_override("shadow_outline_size", 1);
info->add_theme_constant_override("shadow_offset_x", 2);
info->add_theme_constant_override("shadow_offset_y", 2);
@@ -204,7 +199,7 @@ void EditorInspectorPlugin3DTexture::parse_begin(Object *p_object) {
add_custom_control(editor);
}
-Texture3DEditorPlugin::Texture3DEditorPlugin(EditorNode *p_node) {
+Texture3DEditorPlugin::Texture3DEditorPlugin() {
Ref<EditorInspectorPlugin3DTexture> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/texture_3d_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h
index 855194e644..2f7f6f83bb 100644
--- a/editor/plugins/texture_3d_editor_plugin.h
+++ b/editor/plugins/texture_3d_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,22 +31,22 @@
#ifndef TEXTURE_3D_EDITOR_PLUGIN_H
#define TEXTURE_3D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "scene/gui/spin_box.h"
#include "scene/resources/shader.h"
#include "scene/resources/texture.h"
class Texture3DEditor : public Control {
GDCLASS(Texture3DEditor, Control);
- SpinBox *layer;
- Label *info;
+ SpinBox *layer = nullptr;
+ Label *info = nullptr;
Ref<Texture3D> texture;
Ref<Shader> shader;
Ref<ShaderMaterial> material;
- Control *texture_rect;
+ Control *texture_rect = nullptr;
void _make_shaders();
@@ -88,7 +88,7 @@ class Texture3DEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "Texture3D"; }
- Texture3DEditorPlugin(EditorNode *p_node);
+ Texture3DEditorPlugin();
};
#endif // TEXTURE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index b9ec6bf5ab..15f03fd46d 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -64,13 +64,13 @@ void TexturePreview::_update_metadata_label_text() {
String format;
if (Object::cast_to<ImageTexture>(*texture)) {
format = Image::get_format_name(Object::cast_to<ImageTexture>(*texture)->get_format());
- } else if (Object::cast_to<StreamTexture2D>(*texture)) {
- format = Image::get_format_name(Object::cast_to<StreamTexture2D>(*texture)->get_format());
+ } else if (Object::cast_to<CompressedTexture2D>(*texture)) {
+ format = Image::get_format_name(Object::cast_to<CompressedTexture2D>(*texture)->get_format());
} else {
format = texture->get_class();
}
- metadata_label->set_text(itos(texture->get_width()) + "x" + itos(texture->get_height()) + " " + format);
+ metadata_label->set_text(vformat(String::utf8("%s×%s %s"), itos(texture->get_width()), itos(texture->get_height()), format));
}
TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
@@ -84,7 +84,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
texture_display->set_texture(p_texture);
texture_display->set_anchors_preset(TextureRect::PRESET_WIDE);
texture_display->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
- texture_display->set_expand(true);
+ texture_display->set_ignore_texture_size(true);
add_child(texture_display);
if (p_show_metadata) {
@@ -101,7 +101,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
metadata_label->add_theme_color_override("font_outline_color", Color::named("black"));
metadata_label->add_theme_constant_override("outline_size", 2 * EDSCALE);
- metadata_label->add_theme_constant_override("shadow_as_outline", 1);
+ metadata_label->add_theme_constant_override("shadow_outline_size", 1);
metadata_label->set_h_size_flags(Control::SIZE_SHRINK_END);
metadata_label->set_v_size_flags(Control::SIZE_SHRINK_END);
@@ -110,7 +110,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
}
bool EditorInspectorPluginTexture::can_handle(Object *p_object) {
- return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<StreamTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr;
+ return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<CompressedTexture2D>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr;
}
void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
@@ -119,7 +119,7 @@ void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
add_custom_control(memnew(TexturePreview(texture, true)));
}
-TextureEditorPlugin::TextureEditorPlugin(EditorNode *p_node) {
+TextureEditorPlugin::TextureEditorPlugin() {
Ref<EditorInspectorPluginTexture> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/texture_editor_plugin.h b/editor/plugins/texture_editor_plugin.h
index 60349febd7..9beada556c 100644
--- a/editor/plugins/texture_editor_plugin.h
+++ b/editor/plugins/texture_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,7 +31,6 @@
#ifndef TEXTURE_EDITOR_PLUGIN_H
#define TEXTURE_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/resources/texture.h"
@@ -68,7 +67,7 @@ class TextureEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "Texture2D"; }
- TextureEditorPlugin(EditorNode *p_node);
+ TextureEditorPlugin();
};
#endif // TEXTURE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 424e018a47..cb146fd342 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,15 +30,11 @@
#include "texture_layered_editor_plugin.h"
-#include "core/config/project_settings.h"
-#include "core/io/resource_loader.h"
-#include "editor/editor_settings.h"
-
void TextureLayeredEditor::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
y_rot += -mm->get_relative().x * 0.01;
x_rot += mm->get_relative().y * 0.01;
_update_material();
@@ -50,18 +46,17 @@ void TextureLayeredEditor::_texture_rect_draw() {
}
void TextureLayeredEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- //get_scene()->connect("node_removed",this,"_node_removed");
- }
- if (p_what == NOTIFICATION_RESIZED) {
- _texture_rect_update_area();
- }
+ switch (p_what) {
+ case NOTIFICATION_RESIZED: {
+ _texture_rect_update_area();
+ } break;
- if (p_what == NOTIFICATION_DRAW) {
- Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
- Size2 size = get_size();
+ case NOTIFICATION_DRAW: {
+ Ref<Texture2D> checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
+ Size2 size = get_size();
- draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ draw_texture_rect(checkerboard, Rect2(Point2(), size), true);
+ } break;
}
}
@@ -249,7 +244,7 @@ TextureLayeredEditor::TextureLayeredEditor() {
info->set_v_grow_direction(GROW_DIRECTION_BEGIN);
info->add_theme_color_override("font_color", Color(1, 1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5));
- info->add_theme_constant_override("shadow_as_outline", 1);
+ info->add_theme_constant_override("shadow_outline_size", 1);
info->add_theme_constant_override("shadow_offset_x", 2);
info->add_theme_constant_override("shadow_offset_y", 2);
@@ -277,7 +272,7 @@ void EditorInspectorPluginLayeredTexture::parse_begin(Object *p_object) {
add_custom_control(editor);
}
-TextureLayeredEditorPlugin::TextureLayeredEditorPlugin(EditorNode *p_node) {
+TextureLayeredEditorPlugin::TextureLayeredEditorPlugin() {
Ref<EditorInspectorPluginLayeredTexture> plugin;
plugin.instantiate();
add_inspector_plugin(plugin);
diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h
index a7fe4b94e9..830916e954 100644
--- a/editor/plugins/texture_layered_editor_plugin.h
+++ b/editor/plugins/texture_layered_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,16 +31,16 @@
#ifndef TEXTURE_LAYERED_EDITOR_PLUGIN_H
#define TEXTURE_LAYERED_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "scene/gui/spin_box.h"
#include "scene/resources/shader.h"
#include "scene/resources/texture.h"
class TextureLayeredEditor : public Control {
GDCLASS(TextureLayeredEditor, Control);
- SpinBox *layer;
- Label *info;
+ SpinBox *layer = nullptr;
+ Label *info = nullptr;
Ref<TextureLayered> texture;
Ref<Shader> shaders[3];
@@ -48,7 +48,7 @@ class TextureLayeredEditor : public Control {
float x_rot = 0;
float y_rot = 0;
- Control *texture_rect;
+ Control *texture_rect = nullptr;
void _make_shaders();
@@ -90,7 +90,7 @@ class TextureLayeredEditorPlugin : public EditorPlugin {
public:
virtual String get_name() const override { return "TextureLayered"; }
- TextureLayeredEditorPlugin(EditorNode *p_node);
+ TextureLayeredEditorPlugin();
};
#endif // TEXTURE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index ce90d61616..455592aa26 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,12 +33,10 @@
#include "core/core_string_names.h"
#include "core/input/input.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/gui/check_box.h"
-
-/**
- @author Mariano Suligoy
-*/
+#include "scene/gui/view_panner.h"
void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) {
Vector2 line = (to - from).normalized() * 10;
@@ -80,15 +78,17 @@ void TextureRegionEditor::_region_draw() {
}
Transform2D mtx;
- mtx.elements[2] = -draw_ofs * draw_zoom;
+ mtx.columns[2] = -draw_ofs * draw_zoom;
mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx);
edit_draw->draw_texture(base_tex, Point2());
RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D());
+ const Color color = get_theme_color(SNAME("mono_color"), SNAME("Editor"));
+
if (snap_mode == SNAP_GRID) {
- Color grid_color = Color(1.0, 1.0, 1.0, 0.15);
+ const Color grid_color = Color(color.r, color.g, color.b, color.a * 0.15);
Size2 s = edit_draw->get_size();
int last_cell = 0;
@@ -145,7 +145,7 @@ void TextureRegionEditor::_region_draw() {
}
} else if (snap_mode == SNAP_AUTOSLICE) {
for (const Rect2 &r : autoslice_cache) {
- Vector2 endpoints[4] = {
+ const Vector2 endpoints[4] = {
mtx.basis_xform(r.position),
mtx.basis_xform(r.position + Vector2(r.size.x, 0)),
mtx.basis_xform(r.position + r.size),
@@ -174,7 +174,6 @@ void TextureRegionEditor::_region_draw() {
mtx.basis_xform(raw_endpoints[2]),
mtx.basis_xform(raw_endpoints[3])
};
- Color color = get_theme_color(SNAME("mono_color"), SNAME("Editor"));
for (int i = 0; i < 4; i++) {
int prev = (i + 3) % 4;
int next = (i + 1) % 4;
@@ -263,8 +262,12 @@ void TextureRegionEditor::_region_draw() {
}
void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
+ if (panner->gui_input(p_input)) {
+ return;
+ }
+
Transform2D mtx;
- mtx.elements[2] = -draw_ofs * draw_zoom;
+ mtx.columns[2] = -draw_ofs * draw_zoom;
mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
const real_t handle_radius = 8 * EDSCALE;
@@ -284,8 +287,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (mb->is_pressed()) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed() && !panner->is_panning()) {
if (node_ninepatch || obj_styleBox.is_valid()) {
edited_margin = -1;
float margins[4] = { 0 };
@@ -330,7 +333,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
for (const Rect2 &E : autoslice_cache) {
if (E.has_point(point)) {
rect = E;
- if (Input::get_singleton()->is_key_pressed(KEY_CTRL) && !(Input::get_singleton()->is_key_pressed(Key(KEY_SHIFT | KEY_ALT)))) {
+ if (Input::get_singleton()->is_key_pressed(Key::CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) {
Rect2 r;
if (atlas_tex.is_valid()) {
r = atlas_tex->get_region();
@@ -404,7 +407,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
}
- } else if (drag) {
+ } else if (!mb->is_pressed() && drag) {
if (edited_margin >= 0) {
undo_redo->create_action(TTR("Set Margin"));
static Side side[4] = { SIDE_TOP, SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT };
@@ -446,7 +449,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
creating = false;
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
if (drag) {
drag = false;
if (edited_margin >= 0) {
@@ -465,21 +468,13 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
drag_index = -1;
}
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
- _zoom_on_position(draw_zoom * ((0.95 + (0.05 * mb->get_factor())) / 0.95), mb->get_position());
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
- _zoom_on_position(draw_zoom * (1 - (0.05 * mb->get_factor())), mb->get_position());
}
}
Ref<InputEventMouseMotion> mm = p_input;
if (mm.is_valid()) {
- if (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
- Vector2 dragged(mm->get_relative().x / draw_zoom, mm->get_relative().y / draw_zoom);
- hscroll->set_value(hscroll->get_value() - dragged.x);
- vscroll->set_value(vscroll->get_value() - dragged.y);
- } else if (drag) {
+ if (drag) {
if (edited_margin >= 0) {
float new_margin = 0;
@@ -609,6 +604,24 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
}
+void TextureRegionEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
+ _pan_callback(-p_scroll_vec * 32);
+}
+
+void TextureRegionEditor::_pan_callback(Vector2 p_scroll_vec) {
+ p_scroll_vec /= draw_zoom;
+ hscroll->set_value(hscroll->get_value() - p_scroll_vec.x);
+ vscroll->set_value(vscroll->get_value() - p_scroll_vec.y);
+}
+
+void TextureRegionEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
+ if (p_scroll_vec.y < 0) {
+ _zoom_on_position(draw_zoom * ((0.95 + (0.05 * Math::abs(p_scroll_vec.y))) / 0.95), p_origin);
+ } else {
+ _zoom_on_position(draw_zoom * (1 - (0.05 * Math::abs(p_scroll_vec.y))), p_origin);
+ }
+}
+
void TextureRegionEditor::_scroll_changed(float) {
if (updating_scroll) {
return;
@@ -806,6 +819,10 @@ void TextureRegionEditor::_notification(int p_what) {
vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
+ [[fallthrough]];
+ }
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
@@ -965,14 +982,13 @@ Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
return p_target;
}
-TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
+TextureRegionEditor::TextureRegionEditor() {
node_sprite_2d = nullptr;
node_sprite_3d = nullptr;
node_ninepatch = nullptr;
obj_styleBox = Ref<StyleBoxTexture>(nullptr);
atlas_tex = Ref<AtlasTexture>(nullptr);
- editor = p_editor;
- undo_redo = editor->get_undo_redo();
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
snap_step = Vector2(10, 10);
snap_separation = Vector2(0, 0);
@@ -1062,11 +1078,16 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
hb_grid->hide();
+ panner.instantiate();
+ panner->set_callbacks(callable_mp(this, &TextureRegionEditor::_scroll_callback), callable_mp(this, &TextureRegionEditor::_pan_callback), callable_mp(this, &TextureRegionEditor::_zoom_callback));
+
edit_draw = memnew(Panel);
add_child(edit_draw);
edit_draw->set_v_size_flags(SIZE_EXPAND_FILL);
edit_draw->connect("draw", callable_mp(this, &TextureRegionEditor::_region_draw));
edit_draw->connect("gui_input", callable_mp(this, &TextureRegionEditor::_region_input));
+ edit_draw->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key));
+ edit_draw->set_focus_mode(FOCUS_CLICK);
draw_zoom = 1.0;
edit_draw->set_clip_contents(true);
@@ -1125,11 +1146,11 @@ void TextureRegionEditorPlugin::make_visible(bool p_visible) {
is_node_configured |= region_editor->get_sprite_2d() && region_editor->get_sprite_2d()->is_region_enabled();
is_node_configured |= region_editor->get_sprite_3d() && region_editor->get_sprite_3d()->is_region_enabled();
if ((is_node_configured && !manually_hidden) || texture_region_button->is_pressed()) {
- editor->make_bottom_panel_item_visible(region_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(region_editor);
}
} else {
if (region_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
manually_hidden = false;
}
texture_region_button->hide();
@@ -1178,15 +1199,14 @@ void TextureRegionEditorPlugin::set_state(const Dictionary &p_state) {
void TextureRegionEditorPlugin::_bind_methods() {
}
-TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) {
+TextureRegionEditorPlugin::TextureRegionEditorPlugin() {
manually_hidden = false;
- editor = p_node;
- region_editor = memnew(TextureRegionEditor(p_node));
+ region_editor = memnew(TextureRegionEditor);
region_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
region_editor->hide();
region_editor->connect("visibility_changed", callable_mp(this, &TextureRegionEditorPlugin::_editor_visiblity_changed));
- texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor);
+ texture_region_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TextureRegion"), region_editor);
texture_region_button->hide();
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index c043d6ae33..2493446303 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,7 +32,6 @@
#define TEXTURE_REGION_EDITOR_PLUGIN_H
#include "canvas_item_editor_plugin.h"
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/2d/sprite_2d.h"
#include "scene/3d/sprite_3d.h"
@@ -40,9 +39,7 @@
#include "scene/resources/style_box.h"
#include "scene/resources/texture.h"
-/**
- @author Mariano Suligoy
-*/
+class ViewPanner;
class TextureRegionEditor : public VBoxContainer {
GDCLASS(TextureRegionEditor, VBoxContainer);
@@ -55,24 +52,23 @@ class TextureRegionEditor : public VBoxContainer {
};
friend class TextureRegionEditorPlugin;
- OptionButton *snap_mode_button;
- Button *zoom_in;
- Button *zoom_reset;
- Button *zoom_out;
- HBoxContainer *hb_grid; //For showing/hiding the grid controls when changing the SnapMode
- SpinBox *sb_step_y;
- SpinBox *sb_step_x;
- SpinBox *sb_off_y;
- SpinBox *sb_off_x;
- SpinBox *sb_sep_y;
- SpinBox *sb_sep_x;
- Panel *edit_draw;
-
- VScrollBar *vscroll;
- HScrollBar *hscroll;
-
- EditorNode *editor;
- UndoRedo *undo_redo;
+ OptionButton *snap_mode_button = nullptr;
+ Button *zoom_in = nullptr;
+ Button *zoom_reset = nullptr;
+ Button *zoom_out = nullptr;
+ HBoxContainer *hb_grid = nullptr; //For showing/hiding the grid controls when changing the SnapMode
+ SpinBox *sb_step_y = nullptr;
+ SpinBox *sb_step_x = nullptr;
+ SpinBox *sb_off_y = nullptr;
+ SpinBox *sb_off_x = nullptr;
+ SpinBox *sb_sep_y = nullptr;
+ SpinBox *sb_sep_x = nullptr;
+ Panel *edit_draw = nullptr;
+
+ VScrollBar *vscroll = nullptr;
+ HScrollBar *hscroll = nullptr;
+
+ UndoRedo *undo_redo = nullptr;
Vector2 draw_ofs;
float draw_zoom;
@@ -83,25 +79,30 @@ class TextureRegionEditor : public VBoxContainer {
Vector2 snap_step;
Vector2 snap_separation;
- Sprite2D *node_sprite_2d;
- Sprite3D *node_sprite_3d;
- NinePatchRect *node_ninepatch;
+ Sprite2D *node_sprite_2d = nullptr;
+ Sprite3D *node_sprite_3d = nullptr;
+ NinePatchRect *node_ninepatch = nullptr;
Ref<StyleBoxTexture> obj_styleBox;
Ref<AtlasTexture> atlas_tex;
Rect2 rect;
Rect2 rect_prev;
- float prev_margin;
+ float prev_margin = 0.0f;
int edited_margin;
Map<RID, List<Rect2>> cache_map;
List<Rect2> autoslice_cache;
bool autoslice_is_dirty;
bool drag;
- bool creating;
+ bool creating = false;
Vector2 drag_from;
int drag_index;
+ Ref<ViewPanner> panner;
+ void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
+ void _pan_callback(Vector2 p_scroll_vec);
+ void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+
void _set_snap_mode(int p_mode);
void _set_snap_off_x(float p_val);
void _set_snap_off_y(float p_val);
@@ -138,16 +139,15 @@ public:
Sprite3D *get_sprite_3d();
void edit(Object *p_obj);
- TextureRegionEditor(EditorNode *p_editor);
+ TextureRegionEditor();
};
class TextureRegionEditorPlugin : public EditorPlugin {
GDCLASS(TextureRegionEditorPlugin, EditorPlugin);
bool manually_hidden;
- Button *texture_region_button;
- TextureRegionEditor *region_editor;
- EditorNode *editor;
+ Button *texture_region_button = nullptr;
+ TextureRegionEditor *region_editor = nullptr;
protected:
static void _bind_methods();
@@ -163,7 +163,7 @@ public:
void set_state(const Dictionary &p_state) override;
Dictionary get_state() const override;
- TextureRegionEditorPlugin(EditorNode *p_node);
+ TextureRegionEditorPlugin();
};
#endif // TEXTURE_REGION_EDITOR_PLUGIN_H
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index b1ef85b4f4..87f8c4b165 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,6 +31,8 @@
#include "theme_editor_plugin.h"
#include "core/os/keyboard.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_resource_picker.h"
#include "editor/editor_scale.h"
#include "editor/progress_dialog.h"
@@ -81,8 +83,6 @@ void ThemeItemImportTree::_update_items_tree() {
bool is_matching_filter = (filter_text.is_empty() || type_name.findn(filter_text) > -1);
bool has_filtered_items = false;
- bool any_checked = false;
- bool any_checked_with_data = false;
for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
Theme::DataType dt = (Theme::DataType)i;
@@ -178,9 +178,6 @@ void ThemeItemImportTree::_update_items_tree() {
break; // Can't happen, but silences warning.
}
- bool data_type_any_checked = false;
- bool data_type_any_checked_with_data = false;
-
filtered_names.sort_custom<StringName::AlphCompare>();
for (const StringName &F : filtered_names) {
TreeItem *item_node = import_items_tree->create_item(data_type_node);
@@ -194,20 +191,11 @@ void ThemeItemImportTree::_update_items_tree() {
item_node->set_editable(IMPORT_ITEM_DATA, true);
_restore_selected_item(item_node);
- if (item_node->is_checked(IMPORT_ITEM)) {
- data_type_any_checked = true;
- any_checked = true;
- }
- if (item_node->is_checked(IMPORT_ITEM_DATA)) {
- data_type_any_checked_with_data = true;
- any_checked_with_data = true;
- }
+ item_node->propagate_check(IMPORT_ITEM, false);
+ item_node->propagate_check(IMPORT_ITEM_DATA, false);
item_list->push_back(item_node);
}
-
- data_type_node->set_checked(IMPORT_ITEM, data_type_any_checked);
- data_type_node->set_checked(IMPORT_ITEM_DATA, data_type_any_checked && data_type_any_checked_with_data);
}
// Remove the item if it doesn't match the filter in any way.
@@ -221,9 +209,6 @@ void ThemeItemImportTree::_update_items_tree() {
if (!filter_text.is_empty() && has_filtered_items) {
type_node->set_collapsed(false);
}
-
- type_node->set_checked(IMPORT_ITEM, any_checked);
- type_node->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data);
}
if (color_amount > 0) {
@@ -471,23 +456,26 @@ void ThemeItemImportTree::_tree_item_edited() {
if (is_checked) {
if (edited_column == IMPORT_ITEM_DATA) {
edited_item->set_checked(IMPORT_ITEM, true);
+ edited_item->propagate_check(IMPORT_ITEM);
}
-
- _select_all_subitems(edited_item, (edited_column == IMPORT_ITEM_DATA));
} else {
if (edited_column == IMPORT_ITEM) {
edited_item->set_checked(IMPORT_ITEM_DATA, false);
+ edited_item->propagate_check(IMPORT_ITEM_DATA);
}
-
- _deselect_all_subitems(edited_item, (edited_column == IMPORT_ITEM));
}
-
- _update_parent_items(edited_item);
- _store_selected_item(edited_item);
-
+ edited_item->propagate_check(edited_column);
updating_tree = false;
}
+void ThemeItemImportTree::_check_propagated_to_tree_item(Object *p_obj, int p_column) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_obj);
+ // Skip "category" tree items by checking for children.
+ if (item && !item->get_first_child()) {
+ _store_selected_item(item);
+ }
+}
+
void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) {
TreeItem *child_item = p_root_item->get_first_child();
while (child_item) {
@@ -516,32 +504,6 @@ void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_d
}
}
-void ThemeItemImportTree::_update_parent_items(TreeItem *p_root_item) {
- TreeItem *parent_item = p_root_item->get_parent();
- if (!parent_item) {
- return;
- }
-
- bool any_checked = false;
- bool any_checked_with_data = false;
-
- TreeItem *child_item = parent_item->get_first_child();
- while (child_item) {
- if (child_item->is_checked(IMPORT_ITEM)) {
- any_checked = true;
- }
- if (child_item->is_checked(IMPORT_ITEM_DATA)) {
- any_checked_with_data = true;
- }
-
- child_item = child_item->get_next();
- }
-
- parent_item->set_checked(IMPORT_ITEM, any_checked);
- parent_item->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data);
- _update_parent_items(parent_item);
-}
-
void ThemeItemImportTree::_select_all_items_pressed() {
if (updating_tree) {
return;
@@ -629,7 +591,7 @@ void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {
}
child_item->set_checked(IMPORT_ITEM, true);
- _update_parent_items(child_item);
+ child_item->propagate_check(IMPORT_ITEM, false);
_store_selected_item(child_item);
}
@@ -685,7 +647,8 @@ void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {
child_item->set_checked(IMPORT_ITEM, true);
child_item->set_checked(IMPORT_ITEM_DATA, true);
- _update_parent_items(child_item);
+ child_item->propagate_check(IMPORT_ITEM, false);
+ child_item->propagate_check(IMPORT_ITEM_DATA, false);
_store_selected_item(child_item);
}
@@ -741,7 +704,8 @@ void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {
child_item->set_checked(IMPORT_ITEM, false);
child_item->set_checked(IMPORT_ITEM_DATA, false);
- _update_parent_items(child_item);
+ child_item->propagate_check(IMPORT_ITEM, false);
+ child_item->propagate_check(IMPORT_ITEM_DATA, false);
_store_selected_item(child_item);
}
@@ -754,8 +718,9 @@ void ThemeItemImportTree::_import_selected() {
return;
}
- // Prevent changes from immediately being reported while the operation is still ongoing.
- edited_theme->_freeze_change_propagation();
+ Ref<Theme> old_snapshot = edited_theme->duplicate();
+ Ref<Theme> new_snapshot = edited_theme->duplicate();
+
ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size() + 2);
int idx = 0;
@@ -808,7 +773,7 @@ void ThemeItemImportTree::_import_selected() {
}
}
- edited_theme->set_theme_item(ti.data_type, ti.item_name, ti.type_name, item_value);
+ new_snapshot->set_theme_item(ti.data_type, ti.item_name, ti.type_name, item_value);
}
idx++;
@@ -816,12 +781,24 @@ void ThemeItemImportTree::_import_selected() {
// Allow changes to be reported now that the operation is finished.
ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Updating the editor"), idx++);
- edited_theme->_unfreeze_and_propagate_changes();
+
// Make sure the task is not ended before the editor freezes to update the Inspector.
ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Finalizing"), idx++);
ProgressDialog::get_singleton()->end_task("import_theme_items");
- emit_signal(SNAME("items_imported"));
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Import Theme Items"));
+
+ ur->add_do_method(*edited_theme, "clear");
+ ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
+ ur->add_undo_method(*edited_theme, "clear");
+ ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
+
+ ur->add_do_method(this, "emit_signal", SNAME("items_imported"));
+ ur->add_undo_method(this, "emit_signal", SNAME("items_imported"));
+
+ ur->commit_action();
}
void ThemeItemImportTree::set_edited_theme(const Ref<Theme> &p_theme) {
@@ -924,6 +901,7 @@ ThemeItemImportTree::ThemeItemImportTree() {
import_items_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);
import_main_hb->add_child(import_items_tree);
import_items_tree->connect("item_edited", callable_mp(this, &ThemeItemImportTree::_tree_item_edited));
+ import_items_tree->connect("check_propagated_to_item", callable_mp(this, &ThemeItemImportTree::_check_propagated_to_tree_item));
import_items_tree->set_columns(3);
import_items_tree->set_column_titles_visible(true);
@@ -941,7 +919,7 @@ ThemeItemImportTree::ThemeItemImportTree() {
ScrollContainer *import_bulk_sc = memnew(ScrollContainer);
import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE);
- import_bulk_sc->set_enable_h_scroll(false);
+ import_bulk_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
import_main_hb->add_child(import_bulk_sc);
VBoxContainer *import_bulk_vb = memnew(VBoxContainer);
import_bulk_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -1115,7 +1093,7 @@ ThemeItemImportTree::ThemeItemImportTree() {
label_set->add_child(select_items_label);
HBoxContainer *button_set = memnew(HBoxContainer);
- button_set->set_alignment(BoxContainer::ALIGN_END);
+ button_set->set_alignment(BoxContainer::ALIGNMENT_END);
all_set->add_child(button_set);
select_all_items_button->set_flat(true);
select_all_items_button->set_tooltip(select_all_items_tooltip);
@@ -1130,7 +1108,7 @@ ThemeItemImportTree::ThemeItemImportTree() {
button_set->add_child(deselect_all_items_button);
deselect_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed), varray(i));
- total_selected_items_label->set_align(Label::ALIGN_RIGHT);
+ total_selected_items_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
total_selected_items_label->hide();
import_bulk_vb->add_child(total_selected_items_label);
@@ -1235,7 +1213,8 @@ void ThemeItemEditorDialog::_update_edit_types() {
bool item_reselected = false;
edit_type_list->clear();
- int e_idx = 0;
+ TreeItem *list_root = edit_type_list->create_item();
+
for (const StringName &E : theme_types) {
Ref<Texture2D> item_icon;
if (E == "") {
@@ -1243,19 +1222,21 @@ void ThemeItemEditorDialog::_update_edit_types() {
} else {
item_icon = EditorNode::get_singleton()->get_class_icon(E, "NodeDisabled");
}
- edit_type_list->add_item(E, item_icon);
+ TreeItem *list_item = edit_type_list->create_item(list_root);
+ list_item->set_text(0, E);
+ list_item->set_icon(0, item_icon);
+ list_item->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TYPES_TREE_REMOVE_ITEM, false, TTR("Remove Type"));
if (E == edited_item_type) {
- edit_type_list->select(e_idx);
+ list_item->select(0);
item_reselected = true;
}
- e_idx++;
}
if (!item_reselected) {
edited_item_type = "";
- if (edit_type_list->get_item_count() > 0) {
- edit_type_list->select(0);
+ if (list_root->get_child_count() > 0) {
+ list_root->get_child(0)->select(0);
}
}
@@ -1264,9 +1245,9 @@ void ThemeItemEditorDialog::_update_edit_types() {
default_types.sort_custom<StringName::AlphCompare>();
String selected_type = "";
- Vector<int> selected_ids = edit_type_list->get_selected_items();
- if (selected_ids.size() > 0) {
- selected_type = edit_type_list->get_item_text(selected_ids[0]);
+ TreeItem *selected_item = edit_type_list->get_selected();
+ if (selected_item) {
+ selected_type = selected_item->get_text(0);
edit_items_add_color->set_disabled(false);
edit_items_add_constant->set_disabled(false);
@@ -1296,14 +1277,30 @@ void ThemeItemEditorDialog::_update_edit_types() {
edit_items_message->set_text(TTR("Select a theme type from the list to edit its items.\nYou can add a custom type or import a type with its items from another theme."));
edit_items_message->show();
}
+
_update_edit_item_tree(selected_type);
}
-void ThemeItemEditorDialog::_edited_type_selected(int p_item_idx) {
- String selected_type = edit_type_list->get_item_text(p_item_idx);
+void ThemeItemEditorDialog::_edited_type_selected() {
+ TreeItem *selected_item = edit_type_list->get_selected();
+ String selected_type = selected_item->get_text(0);
_update_edit_item_tree(selected_type);
}
+void ThemeItemEditorDialog::_edited_type_button_pressed(Object *p_item, int p_column, int p_id) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ if (!item) {
+ return;
+ }
+
+ switch (p_id) {
+ case TYPES_TREE_REMOVE_ITEM: {
+ String type_name = item->get_text(0);
+ _remove_theme_type(type_name);
+ } break;
+ }
+}
+
void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {
edited_item_type = p_item_type;
@@ -1452,8 +1449,8 @@ void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {
}
// If some type is selected, but it doesn't seem to have any items, show a guiding message.
- Vector<int> selected_ids = edit_type_list->get_selected_items();
- if (selected_ids.size() > 0) {
+ TreeItem *selected_item = edit_type_list->get_selected();
+ if (selected_item) {
if (!has_any_items) {
edit_items_message->set_text(TTR("This theme type is empty.\nAdd more items to it manually or by importing from another theme."));
edit_items_message->show();
@@ -1475,82 +1472,142 @@ void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_colu
String item_name = item->get_text(0);
int data_type = item->get_parent()->get_metadata(0);
_open_rename_theme_item_dialog((Theme::DataType)data_type, item_name);
+ _update_edit_item_tree(edited_item_type);
} break;
case ITEMS_TREE_REMOVE_ITEM: {
String item_name = item->get_text(0);
int data_type = item->get_parent()->get_metadata(0);
- edited_theme->clear_theme_item((Theme::DataType)data_type, item_name, edited_item_type);
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Remove Theme Item"));
+ ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type);
+ ur->add_undo_method(*edited_theme, "set_theme_item", (Theme::DataType)data_type, item_name, edited_item_type, edited_theme->get_theme_item((Theme::DataType)data_type, item_name, edited_item_type));
+ ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->commit_action();
} break;
case ITEMS_TREE_REMOVE_DATA_TYPE: {
int data_type = item->get_metadata(0);
_remove_data_type_items((Theme::DataType)data_type, edited_item_type);
} break;
}
-
- _update_edit_item_tree(edited_item_type);
}
void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
const String new_type = edit_add_type_value->get_text().strip_edges();
edit_add_type_value->clear();
- edited_theme->add_icon_type(new_type);
- edited_theme->add_stylebox_type(new_type);
- edited_theme->add_font_type(new_type);
- edited_theme->add_font_size_type(new_type);
- edited_theme->add_color_type(new_type);
- edited_theme->add_constant_type(new_type);
- _update_edit_types();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Add Theme Type"));
+
+ ur->add_do_method(*edited_theme, "add_type", new_type);
+ ur->add_undo_method(*edited_theme, "remove_type", new_type);
+ ur->add_do_method(this, "_update_edit_types");
+ ur->add_undo_method(this, "_update_edit_types");
- // Force emit a change so that other parts of the editor can update.
- edited_theme->emit_changed();
+ ur->commit_action();
}
void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Create Theme Item"));
+
switch (p_data_type) {
case Theme::DATA_TYPE_ICON:
- edited_theme->set_icon(p_item_name, p_item_type, Ref<Texture2D>());
+ ur->add_do_method(*edited_theme, "set_icon", p_item_name, p_item_type, Ref<Texture2D>());
+ ur->add_undo_method(*edited_theme, "clear_icon", p_item_name, p_item_type);
break;
case Theme::DATA_TYPE_STYLEBOX:
- edited_theme->set_stylebox(p_item_name, p_item_type, Ref<StyleBox>());
+ ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, p_item_type, Ref<StyleBox>());
+ ur->add_undo_method(*edited_theme, "clear_stylebox", p_item_name, p_item_type);
+
+ if (theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(p_item_name, p_item_type))) {
+ ur->add_undo_method(theme_type_editor, "_unpin_leading_stylebox");
+ }
break;
case Theme::DATA_TYPE_FONT:
- edited_theme->set_font(p_item_name, p_item_type, Ref<Font>());
+ ur->add_do_method(*edited_theme, "set_font", p_item_name, p_item_type, Ref<Font>());
+ ur->add_undo_method(*edited_theme, "clear_font", p_item_name, p_item_type);
break;
case Theme::DATA_TYPE_FONT_SIZE:
- edited_theme->set_font_size(p_item_name, p_item_type, -1);
+ ur->add_do_method(*edited_theme, "set_font_size", p_item_name, p_item_type, -1);
+ ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, p_item_type);
break;
case Theme::DATA_TYPE_COLOR:
- edited_theme->set_color(p_item_name, p_item_type, Color());
+ ur->add_do_method(*edited_theme, "set_color", p_item_name, p_item_type, Color());
+ ur->add_undo_method(*edited_theme, "clear_color", p_item_name, p_item_type);
break;
case Theme::DATA_TYPE_CONSTANT:
- edited_theme->set_constant(p_item_name, p_item_type, 0);
+ ur->add_do_method(*edited_theme, "set_constant", p_item_name, p_item_type, 0);
+ ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, p_item_type);
break;
case Theme::DATA_TYPE_MAX:
break; // Can't happen, but silences warning.
}
+
+ ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->commit_action();
+}
+
+void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) {
+ Ref<Theme> old_snapshot = edited_theme->duplicate();
+ Ref<Theme> new_snapshot = edited_theme->duplicate();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Remove Theme Type"));
+
+ new_snapshot->remove_type(p_theme_type);
+
+ ur->add_do_method(*edited_theme, "clear");
+ ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
+ // If the type was empty, it cannot be restored with merge, but thankfully we can fake it.
+ ur->add_undo_method(*edited_theme, "add_type", p_theme_type);
+ ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
+
+ ur->add_do_method(this, "_update_edit_types");
+ ur->add_undo_method(this, "_update_edit_types");
+
+ ur->commit_action();
}
void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {
List<StringName> names;
- // Prevent changes from immediately being reported while the operation is still ongoing.
- edited_theme->_freeze_change_propagation();
+ Ref<Theme> old_snapshot = edited_theme->duplicate();
+ Ref<Theme> new_snapshot = edited_theme->duplicate();
- edited_theme->get_theme_item_list(p_data_type, p_item_type, &names);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Remove Data Type Items From Theme"));
+
+ new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names);
for (const StringName &E : names) {
- edited_theme->clear_theme_item(p_data_type, E, p_item_type);
+ new_snapshot->clear_theme_item(p_data_type, E, edited_item_type);
+
+ if (p_data_type == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, p_item_type))) {
+ ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");
+ ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, p_item_type));
+ }
}
- // Allow changes to be reported now that the operation is finished.
- edited_theme->_unfreeze_and_propagate_changes();
+ ur->add_do_method(*edited_theme, "clear");
+ ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
+ ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
+
+ ur->add_do_method(theme_type_editor, "_update_edit_item_tree", edited_item_type);
+ ur->add_undo_method(theme_type_editor, "_update_edit_item_tree", edited_item_type);
+
+ ur->commit_action();
}
void ThemeItemEditorDialog::_remove_class_items() {
List<StringName> names;
- // Prevent changes from immediately being reported while the operation is still ongoing.
- edited_theme->_freeze_change_propagation();
+ Ref<Theme> old_snapshot = edited_theme->duplicate();
+ Ref<Theme> new_snapshot = edited_theme->duplicate();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Remove Class Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
Theme::DataType data_type = (Theme::DataType)dt;
@@ -1558,62 +1615,95 @@ void ThemeItemEditorDialog::_remove_class_items() {
names.clear();
Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names);
for (const StringName &E : names) {
- if (edited_theme->has_theme_item_nocheck(data_type, E, edited_item_type)) {
- edited_theme->clear_theme_item(data_type, E, edited_item_type);
+ if (new_snapshot->has_theme_item_nocheck(data_type, E, edited_item_type)) {
+ new_snapshot->clear_theme_item(data_type, E, edited_item_type);
+
+ if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {
+ ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");
+ ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));
+ }
}
}
}
- // Allow changes to be reported now that the operation is finished.
- edited_theme->_unfreeze_and_propagate_changes();
+ ur->add_do_method(*edited_theme, "clear");
+ ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
+ ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
+
+ ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);
- _update_edit_item_tree(edited_item_type);
+ ur->commit_action();
}
void ThemeItemEditorDialog::_remove_custom_items() {
List<StringName> names;
- // Prevent changes from immediately being reported while the operation is still ongoing.
- edited_theme->_freeze_change_propagation();
+ Ref<Theme> old_snapshot = edited_theme->duplicate();
+ Ref<Theme> new_snapshot = edited_theme->duplicate();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Remove Custom Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
Theme::DataType data_type = (Theme::DataType)dt;
names.clear();
- edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);
for (const StringName &E : names) {
if (!Theme::get_default()->has_theme_item_nocheck(data_type, E, edited_item_type)) {
- edited_theme->clear_theme_item(data_type, E, edited_item_type);
+ new_snapshot->clear_theme_item(data_type, E, edited_item_type);
+
+ if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {
+ ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");
+ ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));
+ }
}
}
}
- // Allow changes to be reported now that the operation is finished.
- edited_theme->_unfreeze_and_propagate_changes();
+ ur->add_do_method(*edited_theme, "clear");
+ ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
+ ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
+
+ ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);
- _update_edit_item_tree(edited_item_type);
+ ur->commit_action();
}
void ThemeItemEditorDialog::_remove_all_items() {
List<StringName> names;
- // Prevent changes from immediately being reported while the operation is still ongoing.
- edited_theme->_freeze_change_propagation();
+ Ref<Theme> old_snapshot = edited_theme->duplicate();
+ Ref<Theme> new_snapshot = edited_theme->duplicate();
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Remove All Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
Theme::DataType data_type = (Theme::DataType)dt;
names.clear();
- edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);
for (const StringName &E : names) {
- edited_theme->clear_theme_item(data_type, E, edited_item_type);
+ new_snapshot->clear_theme_item(data_type, E, edited_item_type);
+
+ if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {
+ ur->add_do_method(theme_type_editor, "_unpin_leading_stylebox");
+ ur->add_undo_method(theme_type_editor, "_pin_leading_stylebox", E, edited_theme->get_stylebox(E, edited_item_type));
+ }
}
}
- // Allow changes to be reported now that the operation is finished.
- edited_theme->_unfreeze_and_propagate_changes();
+ ur->add_do_method(*edited_theme, "clear");
+ ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
+ ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
- _update_edit_item_tree(edited_item_type);
+ ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);
+
+ ur->commit_action();
}
void ThemeItemEditorDialog::_open_add_theme_item_dialog(int p_data_type) {
@@ -1692,14 +1782,21 @@ void ThemeItemEditorDialog::_confirm_edit_theme_item() {
if (item_popup_mode == CREATE_THEME_ITEM) {
_add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type);
} else if (item_popup_mode == RENAME_THEME_ITEM) {
- edited_theme->rename_theme_item(edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Rename Theme Item"));
+
+ ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
+ ur->add_undo_method(*edited_theme, "rename_theme_item", edit_item_data_type, theme_item_name->get_text(), edit_item_old_name, edited_item_type);
+
+ ur->add_do_method(this, "_update_edit_item_tree", edited_item_type);
+ ur->add_undo_method(this, "_update_edit_item_tree", edited_item_type);
+
+ ur->commit_action();
}
item_popup_mode = ITEM_POPUP_MODE_MAX;
edit_item_data_type = Theme::DATA_TYPE_MAX;
edit_item_old_name = "";
-
- _update_edit_item_tree(edited_item_type);
}
void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_event) {
@@ -1711,13 +1808,13 @@ void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_
}
switch (k->get_keycode()) {
- case KEY_KP_ENTER:
- case KEY_ENTER: {
+ case Key::KP_ENTER:
+ case Key::ENTER: {
_confirm_edit_theme_item();
edit_theme_item_dialog->hide();
edit_theme_item_dialog->set_input_as_handled();
} break;
- case KEY_ESCAPE: {
+ case Key::ESCAPE: {
edit_theme_item_dialog->hide();
edit_theme_item_dialog->set_input_as_handled();
} break;
@@ -1773,17 +1870,23 @@ void ThemeItemEditorDialog::_notification(int p_what) {
}
}
+void ThemeItemEditorDialog::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_edit_types"), &ThemeItemEditorDialog::_update_edit_types);
+ ClassDB::bind_method(D_METHOD("_update_edit_item_tree"), &ThemeItemEditorDialog::_update_edit_item_tree);
+}
+
void ThemeItemEditorDialog::set_edited_theme(const Ref<Theme> &p_theme) {
edited_theme = p_theme;
}
-ThemeItemEditorDialog::ThemeItemEditorDialog() {
+ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_editor) {
set_title(TTR("Manage Theme Items"));
get_ok_button()->set_text(TTR("Close"));
set_hide_on_ok(false); // Closing may require a confirmation in some cases.
+ theme_type_editor = p_theme_type_editor;
+
tc = memnew(TabContainer);
- tc->set_tab_align(TabContainer::TabAlign::ALIGN_LEFT);
add_child(tc);
// Edit Items tab.
@@ -1799,10 +1902,14 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() {
edit_type_label->set_text(TTR("Types:"));
edit_dialog_side_vb->add_child(edit_type_label);
- edit_type_list = memnew(ItemList);
+ edit_type_list = memnew(Tree);
+ edit_type_list->set_hide_root(true);
+ edit_type_list->set_hide_folding(true);
+ edit_type_list->set_columns(1);
edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
edit_dialog_side_vb->add_child(edit_type_list);
edit_type_list->connect("item_selected", callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected));
+ edit_type_list->connect("button_pressed", callable_mp(this, &ThemeItemEditorDialog::_edited_type_button_pressed));
Label *edit_add_type_label = memnew(Label);
edit_add_type_label->set_text(TTR("Add Type:"));
@@ -1909,8 +2016,8 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() {
edit_items_message = memnew(Label);
edit_items_message->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
edit_items_message->set_mouse_filter(Control::MOUSE_FILTER_STOP);
- edit_items_message->set_align(Label::ALIGN_CENTER);
- edit_items_message->set_valign(Label::VALIGN_CENTER);
+ edit_items_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ edit_items_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
edit_items_message->set_autowrap_mode(Label::AUTOWRAP_WORD);
edit_items_tree->add_child(edit_items_message);
@@ -1938,6 +2045,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() {
// Import Items tab.
TabContainer *import_tc = memnew(TabContainer);
+ import_tc->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
tc->add_child(import_tc);
tc->set_tab_title(1, TTR("Import Items"));
@@ -1969,7 +2077,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() {
List<String> ext;
ResourceLoader::get_recognized_extensions_for_type("Theme", &ext);
for (const String &E : ext) {
- import_another_theme_dialog->add_filter("*." + E + "; Theme Resource");
+ import_another_theme_dialog->add_filter(vformat("*.%s; %s", E, TTR("Theme Resource")));
}
import_another_file_hb->add_child(import_another_theme_dialog);
import_another_theme_dialog->connect("file_selected", callable_mp(this, &ThemeItemEditorDialog::_select_another_theme_cbk));
@@ -1996,7 +2104,7 @@ void ThemeTypeDialog::_dialog_about_to_show() {
}
void ThemeTypeDialog::ok_pressed() {
- emit_signal(SNAME("type_selected"), add_type_filter->get_text().strip_edges());
+ _add_type_selected(add_type_filter->get_text().strip_edges());
}
void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {
@@ -2012,7 +2120,7 @@ void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {
Vector<StringName> unique_names;
for (const StringName &E : names) {
// Filter out undesired values.
- if (!p_filter.is_subsequence_ofi(String(E))) {
+ if (!p_filter.is_subsequence_ofn(String(E))) {
continue;
}
@@ -2042,12 +2150,25 @@ void ThemeTypeDialog::_add_type_options_cbk(int p_index) {
}
void ThemeTypeDialog::_add_type_dialog_entered(const String &p_value) {
- emit_signal(SNAME("type_selected"), p_value.strip_edges());
- hide();
+ _add_type_selected(p_value.strip_edges());
}
void ThemeTypeDialog::_add_type_dialog_activated(int p_index) {
- emit_signal(SNAME("type_selected"), add_type_options->get_item_text(p_index));
+ _add_type_selected(add_type_options->get_item_text(p_index));
+}
+
+void ThemeTypeDialog::_add_type_selected(const String &p_type_name) {
+ pre_submitted_value = p_type_name;
+ if (p_type_name.is_empty()) {
+ add_type_confirmation->popup_centered();
+ return;
+ }
+
+ _add_type_confirmed();
+}
+
+void ThemeTypeDialog::_add_type_confirmed() {
+ emit_signal(SNAME("type_selected"), pre_submitted_value);
hide();
}
@@ -2082,11 +2203,13 @@ void ThemeTypeDialog::set_include_own_types(bool p_enable) {
}
ThemeTypeDialog::ThemeTypeDialog() {
+ set_hide_on_ok(false);
+
VBoxContainer *add_type_vb = memnew(VBoxContainer);
add_child(add_type_vb);
Label *add_type_filter_label = memnew(Label);
- add_type_filter_label->set_text(TTR("Name:"));
+ add_type_filter_label->set_text(TTR("Filter the list of types or create a new custom type:"));
add_type_vb->add_child(add_type_filter_label);
add_type_filter = memnew(LineEdit);
@@ -2095,7 +2218,7 @@ ThemeTypeDialog::ThemeTypeDialog() {
add_type_filter->connect("text_submitted", callable_mp(this, &ThemeTypeDialog::_add_type_dialog_entered));
Label *add_type_options_label = memnew(Label);
- add_type_options_label->set_text(TTR("Node Types:"));
+ add_type_options_label->set_text(TTR("Available Node-based types:"));
add_type_vb->add_child(add_type_options_label);
add_type_options = memnew(ItemList);
@@ -2103,6 +2226,12 @@ ThemeTypeDialog::ThemeTypeDialog() {
add_type_vb->add_child(add_type_options);
add_type_options->connect("item_selected", callable_mp(this, &ThemeTypeDialog::_add_type_options_cbk));
add_type_options->connect("item_activated", callable_mp(this, &ThemeTypeDialog::_add_type_dialog_activated));
+
+ add_type_confirmation = memnew(ConfirmationDialog);
+ add_type_confirmation->set_title(TTR("Type name is empty!"));
+ add_type_confirmation->set_text(TTR("Are you sure you want to create an empty type?"));
+ add_type_confirmation->connect("confirmed", callable_mp(this, &ThemeTypeDialog::_add_type_confirmed));
+ add_child(add_type_confirmation);
}
VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {
@@ -2113,7 +2242,7 @@ VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {
ScrollContainer *items_sc = memnew(ScrollContainer);
items_sc->set_v_size_flags(SIZE_EXPAND_FILL);
- items_sc->set_enable_h_scroll(false);
+ items_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
items_tab->add_child(items_sc);
VBoxContainer *items_list = memnew(VBoxContainer);
items_list->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -2141,7 +2270,7 @@ void ThemeTypeEditor::_update_type_list() {
}
updating = true;
- Control *focused = get_focus_owner();
+ Control *focused = get_viewport()->gui_get_focus_owner();
if (focused) {
if (focusables.has(focused)) {
// If focus is currently on one of the internal property editors, don't update.
@@ -2408,7 +2537,7 @@ void ThemeTypeEditor::_update_type_items() {
if (edited_theme->has_font(E.key(), edited_type)) {
item_editor->set_edited_resource(edited_theme->get_font(E.key(), edited_type));
} else {
- item_editor->set_edited_resource(RES());
+ item_editor->set_edited_resource(Ref<Resource>());
}
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed), varray(E.key()));
@@ -2416,7 +2545,7 @@ void ThemeTypeEditor::_update_type_items() {
if (Theme::get_default()->has_font(E.key(), edited_type)) {
item_editor->set_edited_resource(Theme::get_default()->get_font(E.key(), edited_type));
} else {
- item_editor->set_edited_resource(RES());
+ item_editor->set_edited_resource(Ref<Resource>());
}
item_editor->set_editable(false);
}
@@ -2479,7 +2608,7 @@ void ThemeTypeEditor::_update_type_items() {
if (edited_theme->has_icon(E.key(), edited_type)) {
item_editor->set_edited_resource(edited_theme->get_icon(E.key(), edited_type));
} else {
- item_editor->set_edited_resource(RES());
+ item_editor->set_edited_resource(Ref<Resource>());
}
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed), varray(E.key()));
@@ -2487,7 +2616,7 @@ void ThemeTypeEditor::_update_type_items() {
if (Theme::get_default()->has_icon(E.key(), edited_type)) {
item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key(), edited_type));
} else {
- item_editor->set_edited_resource(RES());
+ item_editor->set_edited_resource(Ref<Resource>());
}
item_editor->set_editable(false);
}
@@ -2519,14 +2648,14 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")));
pin_leader_button->set_tooltip(TTR("Unpin this StyleBox as a main style."));
item_control->add_child(pin_leader_button);
- pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_unpin_leading_stylebox));
+ pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_unpin_leader_button_pressed));
item_control->add_child(item_editor);
- if (leading_stylebox.stylebox.is_valid()) {
+ if (edited_theme->has_stylebox(leading_stylebox.item_name, edited_type)) {
item_editor->set_edited_resource(leading_stylebox.stylebox);
} else {
- item_editor->set_edited_resource(RES());
+ item_editor->set_edited_resource(Ref<Resource>());
}
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(leading_stylebox.item_name));
@@ -2548,12 +2677,10 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->set_base_type("StyleBox");
if (E.get()) {
- Ref<StyleBox> stylebox_value;
if (edited_theme->has_stylebox(E.key(), edited_type)) {
- stylebox_value = edited_theme->get_stylebox(E.key(), edited_type);
- item_editor->set_edited_resource(stylebox_value);
+ item_editor->set_edited_resource(edited_theme->get_stylebox(E.key(), edited_type));
} else {
- item_editor->set_edited_resource(RES());
+ item_editor->set_edited_resource(Ref<Resource>());
}
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(E.key()));
@@ -2564,12 +2691,12 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")));
pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type."));
item_control->add_child(pin_leader_button);
- pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_pin_leading_stylebox), varray(item_editor, E.key()));
+ pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed), varray(item_editor, E.key()));
} else {
if (Theme::get_default()->has_stylebox(E.key(), edited_type)) {
item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key(), edited_type));
} else {
- item_editor->set_edited_resource(RES());
+ item_editor->set_edited_resource(Ref<Resource>());
}
item_editor->set_editable(false);
}
@@ -2581,11 +2708,11 @@ void ThemeTypeEditor::_update_type_items() {
}
// Various type settings.
- if (ClassDB::class_exists(edited_type)) {
+ if (edited_type.is_empty() || ClassDB::class_exists(edited_type)) {
type_variation_edit->set_editable(false);
type_variation_edit->set_text("");
type_variation_button->hide();
- type_variation_locked->show();
+ type_variation_locked->set_visible(!edited_type.is_empty());
} else {
type_variation_edit->set_editable(true);
type_variation_edit->set_text(edited_theme->get_type_variation_base(edited_type));
@@ -2603,6 +2730,7 @@ void ThemeTypeEditor::_list_type_selected(int p_index) {
void ThemeTypeEditor::_add_type_button_cbk() {
add_type_mode = ADD_THEME_TYPE;
add_type_dialog->set_title(TTR("Add Item Type"));
+ add_type_dialog->get_ok_button()->set_text(TTR("Add Type"));
add_type_dialog->set_include_own_types(false);
add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);
}
@@ -2614,16 +2742,17 @@ void ThemeTypeEditor::_add_default_type_items() {
default_type = edited_theme->get_type_variation_base(edited_type);
}
+ Ref<Theme> old_snapshot = edited_theme->duplicate();
+ Ref<Theme> new_snapshot = edited_theme->duplicate();
+
updating = true;
- // Prevent changes from immediately being reported while the operation is still ongoing.
- edited_theme->_freeze_change_propagation();
{
names.clear();
Theme::get_default()->get_icon_list(default_type, &names);
for (const StringName &E : names) {
- if (!edited_theme->has_icon(E, edited_type)) {
- edited_theme->set_icon(E, edited_type, Ref<Texture2D>());
+ if (!new_snapshot->has_icon(E, edited_type)) {
+ new_snapshot->set_icon(E, edited_type, Theme::get_default()->get_icon(E, edited_type));
}
}
}
@@ -2631,8 +2760,8 @@ void ThemeTypeEditor::_add_default_type_items() {
names.clear();
Theme::get_default()->get_stylebox_list(default_type, &names);
for (const StringName &E : names) {
- if (!edited_theme->has_stylebox(E, edited_type)) {
- edited_theme->set_stylebox(E, edited_type, Ref<StyleBox>());
+ if (!new_snapshot->has_stylebox(E, edited_type)) {
+ new_snapshot->set_stylebox(E, edited_type, Theme::get_default()->get_stylebox(E, edited_type));
}
}
}
@@ -2640,8 +2769,8 @@ void ThemeTypeEditor::_add_default_type_items() {
names.clear();
Theme::get_default()->get_font_list(default_type, &names);
for (const StringName &E : names) {
- if (!edited_theme->has_font(E, edited_type)) {
- edited_theme->set_font(E, edited_type, Ref<Font>());
+ if (!new_snapshot->has_font(E, edited_type)) {
+ new_snapshot->set_font(E, edited_type, Theme::get_default()->get_font(E, edited_type));
}
}
}
@@ -2649,8 +2778,8 @@ void ThemeTypeEditor::_add_default_type_items() {
names.clear();
Theme::get_default()->get_font_size_list(default_type, &names);
for (const StringName &E : names) {
- if (!edited_theme->has_font_size(E, edited_type)) {
- edited_theme->set_font_size(E, edited_type, Theme::get_default()->get_font_size(E, default_type));
+ if (!new_snapshot->has_font_size(E, edited_type)) {
+ new_snapshot->set_font_size(E, edited_type, Theme::get_default()->get_font_size(E, edited_type));
}
}
}
@@ -2658,8 +2787,8 @@ void ThemeTypeEditor::_add_default_type_items() {
names.clear();
Theme::get_default()->get_color_list(default_type, &names);
for (const StringName &E : names) {
- if (!edited_theme->has_color(E, edited_type)) {
- edited_theme->set_color(E, edited_type, Theme::get_default()->get_color(E, default_type));
+ if (!new_snapshot->has_color(E, edited_type)) {
+ new_snapshot->set_color(E, edited_type, Theme::get_default()->get_color(E, edited_type));
}
}
}
@@ -2667,17 +2796,25 @@ void ThemeTypeEditor::_add_default_type_items() {
names.clear();
Theme::get_default()->get_constant_list(default_type, &names);
for (const StringName &E : names) {
- if (!edited_theme->has_constant(E, edited_type)) {
- edited_theme->set_constant(E, edited_type, Theme::get_default()->get_constant(E, default_type));
+ if (!new_snapshot->has_constant(E, edited_type)) {
+ new_snapshot->set_constant(E, edited_type, Theme::get_default()->get_constant(E, edited_type));
}
}
}
- // Allow changes to be reported now that the operation is finished.
- edited_theme->_unfreeze_and_propagate_changes();
updating = false;
- _update_type_items();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Override All Default Theme Items"));
+
+ ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
+ ur->add_undo_method(*edited_theme, "clear");
+ ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
+
+ ur->add_do_method(this, "_update_type_items");
+ ur->add_undo_method(this, "_update_type_items");
+
+ ur->commit_action();
}
void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {
@@ -2687,27 +2824,43 @@ void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {
}
String item_name = le->get_text().strip_edges();
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Add Theme Item"));
+
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR: {
- edited_theme->set_color(item_name, edited_type, Color());
+ ur->add_do_method(*edited_theme, "set_color", item_name, edited_type, Color());
+ ur->add_undo_method(*edited_theme, "clear_color", item_name, edited_type);
} break;
case Theme::DATA_TYPE_CONSTANT: {
- edited_theme->set_constant(item_name, edited_type, 0);
+ ur->add_do_method(*edited_theme, "set_constant", item_name, edited_type, 0);
+ ur->add_undo_method(*edited_theme, "clear_constant", item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT: {
- edited_theme->set_font(item_name, edited_type, Ref<Font>());
+ ur->add_do_method(*edited_theme, "set_font", item_name, edited_type, Ref<Font>());
+ ur->add_undo_method(*edited_theme, "clear_font", item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT_SIZE: {
- edited_theme->set_font_size(item_name, edited_type, -1);
+ ur->add_do_method(*edited_theme, "set_font_size", item_name, edited_type, -1);
+ ur->add_undo_method(*edited_theme, "clear_font_size", item_name, edited_type);
} break;
case Theme::DATA_TYPE_ICON: {
- edited_theme->set_icon(item_name, edited_type, Ref<Texture2D>());
+ ur->add_do_method(*edited_theme, "set_icon", item_name, edited_type, Ref<Texture2D>());
+ ur->add_undo_method(*edited_theme, "clear_icon", item_name, edited_type);
} break;
case Theme::DATA_TYPE_STYLEBOX: {
- edited_theme->set_stylebox(item_name, edited_type, Ref<StyleBox>());
+ Ref<StyleBox> sb;
+ ur->add_do_method(*edited_theme, "set_stylebox", item_name, edited_type, sb);
+ ur->add_undo_method(*edited_theme, "clear_stylebox", item_name, edited_type);
+
+ if (is_stylebox_pinned(sb)) {
+ ur->add_undo_method(this, "_unpin_leading_stylebox");
+ }
} break;
}
+ ur->commit_action();
+
le->set_text("");
}
@@ -2716,53 +2869,94 @@ void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Co
}
void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Override Theme Item"));
+
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR: {
- edited_theme->set_color(p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type));
+ ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type));
+ ur->add_undo_method(*edited_theme, "clear_color", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_CONSTANT: {
- edited_theme->set_constant(p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type));
+ ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type));
+ ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT: {
- edited_theme->set_font(p_item_name, edited_type, Ref<Font>());
+ ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());
+ ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT_SIZE: {
- edited_theme->set_font_size(p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type));
+ ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type));
+ ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_ICON: {
- edited_theme->set_icon(p_item_name, edited_type, Ref<Texture2D>());
+ ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());
+ ur->add_undo_method(*edited_theme, "clear_icon", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_STYLEBOX: {
- edited_theme->set_stylebox(p_item_name, edited_type, Ref<StyleBox>());
+ Ref<StyleBox> sb;
+ ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, sb);
+ ur->add_undo_method(*edited_theme, "clear_stylebox", p_item_name, edited_type);
+
+ if (is_stylebox_pinned(sb)) {
+ ur->add_undo_method(this, "_unpin_leading_stylebox");
+ }
} break;
}
+
+ ur->commit_action();
}
void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Remove Theme Item"));
+
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR: {
- edited_theme->clear_color(p_item_name, edited_type);
+ ur->add_do_method(*edited_theme, "clear_color", p_item_name, edited_type);
+ ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));
} break;
case Theme::DATA_TYPE_CONSTANT: {
- edited_theme->clear_constant(p_item_name, edited_type);
+ ur->add_do_method(*edited_theme, "clear_constant", p_item_name, edited_type);
+ ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));
} break;
case Theme::DATA_TYPE_FONT: {
- edited_theme->clear_font(p_item_name, edited_type);
+ ur->add_do_method(*edited_theme, "clear_font", p_item_name, edited_type);
+ if (edited_theme->has_font(p_item_name, edited_type)) {
+ ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, edited_theme->get_font(p_item_name, edited_type));
+ } else {
+ ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());
+ }
} break;
case Theme::DATA_TYPE_FONT_SIZE: {
- edited_theme->clear_font_size(p_item_name, edited_type);
+ ur->add_do_method(*edited_theme, "clear_font_size", p_item_name, edited_type);
+ ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));
} break;
case Theme::DATA_TYPE_ICON: {
- edited_theme->clear_icon(p_item_name, edited_type);
+ ur->add_do_method(*edited_theme, "clear_icon", p_item_name, edited_type);
+ if (edited_theme->has_icon(p_item_name, edited_type)) {
+ ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, edited_theme->get_icon(p_item_name, edited_type));
+ } else {
+ ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());
+ }
} break;
case Theme::DATA_TYPE_STYLEBOX: {
- edited_theme->clear_stylebox(p_item_name, edited_type);
+ Ref<StyleBox> sb = edited_theme->get_stylebox(p_item_name, edited_type);
+ ur->add_do_method(*edited_theme, "clear_stylebox", p_item_name, edited_type);
+ if (edited_theme->has_stylebox(p_item_name, edited_type)) {
+ ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, sb);
+ } else {
+ ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, Ref<StyleBox>());
+ }
- if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
- _unpin_leading_stylebox();
+ if (is_stylebox_pinned(sb)) {
+ ur->add_do_method(this, "_unpin_leading_stylebox");
+ ur->add_undo_method(this, "_pin_leading_stylebox", p_item_name, sb);
}
} break;
}
+
+ ur->commit_action();
}
void ThemeTypeEditor::_item_rename_cbk(int p_data_type, String p_item_name, Control *p_control) {
@@ -2792,30 +2986,41 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name
return;
}
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Rename Theme Item"));
+
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR: {
- edited_theme->rename_color(p_item_name, new_name, edited_type);
+ ur->add_do_method(*edited_theme, "rename_color", p_item_name, new_name, edited_type);
+ ur->add_undo_method(*edited_theme, "rename_color", new_name, p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_CONSTANT: {
- edited_theme->rename_constant(p_item_name, new_name, edited_type);
+ ur->add_do_method(*edited_theme, "rename_constant", p_item_name, new_name, edited_type);
+ ur->add_undo_method(*edited_theme, "rename_constant", new_name, p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT: {
- edited_theme->rename_font(p_item_name, new_name, edited_type);
+ ur->add_do_method(*edited_theme, "rename_font", p_item_name, new_name, edited_type);
+ ur->add_undo_method(*edited_theme, "rename_font", new_name, p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT_SIZE: {
- edited_theme->rename_font_size(p_item_name, new_name, edited_type);
+ ur->add_do_method(*edited_theme, "rename_font_size", p_item_name, new_name, edited_type);
+ ur->add_undo_method(*edited_theme, "rename_font_size", new_name, p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_ICON: {
- edited_theme->rename_icon(p_item_name, new_name, edited_type);
+ ur->add_do_method(*edited_theme, "rename_icon", p_item_name, new_name, edited_type);
+ ur->add_undo_method(*edited_theme, "rename_icon", new_name, p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_STYLEBOX: {
- edited_theme->rename_stylebox(p_item_name, new_name, edited_type);
+ ur->add_do_method(*edited_theme, "rename_stylebox", p_item_name, new_name, edited_type);
+ ur->add_undo_method(*edited_theme, "rename_stylebox", new_name, p_item_name, edited_type);
if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
leading_stylebox.item_name = new_name;
}
} break;
}
+
+ ur->commit_action();
}
void ThemeTypeEditor::_item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control) {
@@ -2837,69 +3042,151 @@ void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name,
}
void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
- edited_theme->set_color(p_item_name, edited_type, p_value);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS);
+ ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value);
+ ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));
+ ur->commit_action();
}
void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {
- edited_theme->set_constant(p_item_name, edited_type, int(p_value));
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Constant Item in Theme"));
+ ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value);
+ ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));
+ ur->commit_action();
}
void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {
- edited_theme->set_font_size(p_item_name, edited_type, int(p_value));
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Font Size Item in Theme"));
+ ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value);
+ ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));
+ ur->commit_action();
}
-void ThemeTypeEditor::_edit_resource_item(RES p_resource, bool p_edit) {
+void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit) {
EditorNode::get_singleton()->edit_resource(p_resource);
}
void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {
- edited_theme->set_font(p_item_name, edited_type, p_value);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Font Item in Theme"));
+
+ ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>());
+ if (edited_theme->has_font(p_item_name, edited_type)) {
+ ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, edited_theme->get_font(p_item_name, edited_type));
+ } else {
+ ur->add_undo_method(*edited_theme, "set_font", p_item_name, edited_type, Ref<Font>());
+ }
+
+ ur->add_do_method(this, "call_deferred", "_update_type_items");
+ ur->add_undo_method(this, "call_deferred", "_update_type_items");
+
+ ur->commit_action();
}
void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {
- edited_theme->set_icon(p_item_name, edited_type, p_value);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Icon Item in Theme"));
+
+ ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>());
+ if (edited_theme->has_icon(p_item_name, edited_type)) {
+ ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, edited_theme->get_icon(p_item_name, edited_type));
+ } else {
+ ur->add_undo_method(*edited_theme, "set_icon", p_item_name, edited_type, Ref<Texture2D>());
+ }
+
+ ur->add_do_method(this, "call_deferred", "_update_type_items");
+ ur->add_undo_method(this, "call_deferred", "_update_type_items");
+
+ ur->commit_action();
}
void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {
- edited_theme->set_stylebox(p_item_name, edited_type, p_value);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Stylebox Item in Theme"));
+
+ ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>());
+ if (edited_theme->has_stylebox(p_item_name, edited_type)) {
+ ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, edited_theme->get_stylebox(p_item_name, edited_type));
+ } else {
+ ur->add_undo_method(*edited_theme, "set_stylebox", p_item_name, edited_type, Ref<StyleBox>());
+ }
+
+ ur->add_do_method(this, "_change_pinned_stylebox");
+ ur->add_undo_method(this, "_change_pinned_stylebox");
+
+ ur->add_do_method(this, "call_deferred", "_update_type_items");
+ ur->add_undo_method(this, "call_deferred", "_update_type_items");
- if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
+ ur->commit_action();
+}
+
+void ThemeTypeEditor::_change_pinned_stylebox() {
+ if (leading_stylebox.pinned) {
if (leading_stylebox.stylebox.is_valid()) {
leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
- leading_stylebox.stylebox = p_value;
- leading_stylebox.ref_stylebox = (p_value.is_valid() ? p_value->duplicate() : RES());
- if (p_value.is_valid()) {
- leading_stylebox.stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
- }
- }
-}
+ Ref<StyleBox> new_stylebox = edited_theme->get_stylebox(leading_stylebox.item_name, edited_type);
+ leading_stylebox.stylebox = new_stylebox;
+ leading_stylebox.ref_stylebox = (new_stylebox.is_valid() ? new_stylebox->duplicate() : Ref<Resource>());
-void ThemeTypeEditor::_pin_leading_stylebox(Control *p_editor, String p_item_name) {
- if (leading_stylebox.stylebox.is_valid()) {
+ if (leading_stylebox.stylebox.is_valid()) {
+ new_stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ }
+ } else if (leading_stylebox.stylebox.is_valid()) {
leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
+}
+void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_item_name) {
Ref<StyleBox> stylebox;
if (Object::cast_to<EditorResourcePicker>(p_editor)) {
stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();
}
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Pin Stylebox"));
+ ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox);
+
+ if (leading_stylebox.pinned) {
+ ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);
+ } else {
+ ur->add_undo_method(this, "_unpin_leading_stylebox");
+ }
+
+ ur->commit_action();
+}
+
+void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_stylebox) {
+ if (leading_stylebox.stylebox.is_valid()) {
+ leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ }
+
LeadingStylebox leader;
leader.pinned = true;
leader.item_name = p_item_name;
- leader.stylebox = stylebox;
- leader.ref_stylebox = (stylebox.is_valid() ? stylebox->duplicate() : RES());
+ leader.stylebox = p_stylebox;
+ leader.ref_stylebox = (p_stylebox.is_valid() ? p_stylebox->duplicate() : Ref<Resource>());
leading_stylebox = leader;
- if (leading_stylebox.stylebox.is_valid()) {
- leading_stylebox.stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
+ if (p_stylebox.is_valid()) {
+ p_stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
}
_update_type_items();
}
+void ThemeTypeEditor::_on_unpin_leader_button_pressed() {
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Unpin Stylebox"));
+ ur->add_do_method(this, "_unpin_leading_stylebox");
+ ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);
+ ur->commit_action();
+}
+
void ThemeTypeEditor::_unpin_leading_stylebox() {
if (leading_stylebox.stylebox.is_valid()) {
leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading));
@@ -2960,16 +3247,28 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
}
void ThemeTypeEditor::_type_variation_changed(const String p_value) {
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Set Theme Type Variation"));
+
if (p_value.is_empty()) {
- edited_theme->clear_type_variation(edited_type);
+ ur->add_do_method(*edited_theme, "clear_type_variation", edited_type);
} else {
- edited_theme->set_type_variation(edited_type, StringName(p_value));
+ ur->add_do_method(*edited_theme, "set_type_variation", edited_type, StringName(p_value));
}
+
+ if (edited_theme->get_type_variation_base(edited_type) == "") {
+ ur->add_undo_method(*edited_theme, "clear_type_variation", edited_type);
+ } else {
+ ur->add_undo_method(*edited_theme, "set_type_variation", edited_type, edited_theme->get_type_variation_base(edited_type));
+ }
+
+ ur->commit_action();
}
void ThemeTypeEditor::_add_type_variation_cbk() {
add_type_mode = ADD_VARIATION_BASE;
- add_type_dialog->set_title(TTR("Add Variation Base Type"));
+ add_type_dialog->set_title(TTR("Set Variation Base Type"));
+ add_type_dialog->get_ok_button()->set_text(TTR("Set Base Type"));
add_type_dialog->set_include_own_types(true);
add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);
}
@@ -2979,7 +3278,6 @@ void ThemeTypeEditor::_add_type_dialog_selected(const String p_type_name) {
select_type(p_type_name);
} else if (add_type_mode == ADD_VARIATION_BASE) {
_type_variation_changed(p_type_name);
- _update_type_items();
}
}
@@ -3005,6 +3303,13 @@ void ThemeTypeEditor::_notification(int p_what) {
}
}
+void ThemeTypeEditor::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_type_items"), &ThemeTypeEditor::_update_type_items);
+ ClassDB::bind_method(D_METHOD("_pin_leading_stylebox"), &ThemeTypeEditor::_pin_leading_stylebox);
+ ClassDB::bind_method(D_METHOD("_unpin_leading_stylebox"), &ThemeTypeEditor::_unpin_leading_stylebox);
+ ClassDB::bind_method(D_METHOD("_change_pinned_stylebox"), &ThemeTypeEditor::_change_pinned_stylebox);
+}
+
void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
if (edited_theme.is_valid()) {
edited_theme->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
@@ -3044,6 +3349,10 @@ void ThemeTypeEditor::select_type(String p_type_name) {
}
}
+bool ThemeTypeEditor::is_stylebox_pinned(Ref<StyleBox> p_stylebox) {
+ return leading_stylebox.pinned && leading_stylebox.stylebox == p_stylebox;
+}
+
ThemeTypeEditor::ThemeTypeEditor() {
VBoxContainer *main_vb = memnew(VBoxContainer);
add_child(main_vb);
@@ -3084,6 +3393,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
add_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_default_type_items));
data_type_tabs = memnew(TabContainer);
+ data_type_tabs->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
main_vb->add_child(data_type_tabs);
data_type_tabs->set_v_size_flags(SIZE_EXPAND_FILL);
data_type_tabs->set_use_hidden_tabs_for_min_size(true);
@@ -3102,7 +3412,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
ScrollContainer *type_settings_sc = memnew(ScrollContainer);
type_settings_sc->set_v_size_flags(SIZE_EXPAND_FILL);
- type_settings_sc->set_enable_h_scroll(false);
+ type_settings_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
type_settings_tab->add_child(type_settings_sc);
VBoxContainer *type_settings_list = memnew(VBoxContainer);
type_settings_list->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -3129,7 +3439,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
type_variation_locked = memnew(Label);
type_variation_vb->add_child(type_variation_locked);
- type_variation_locked->set_align(Label::ALIGN_CENTER);
+ type_variation_locked->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
type_variation_locked->set_autowrap_mode(Label::AUTOWRAP_WORD);
type_variation_locked->set_text(TTR("A type associated with a built-in class cannot be marked as a variation of another type."));
type_variation_locked->hide();
@@ -3204,7 +3514,7 @@ void ThemeEditor::_add_preview_tab(ThemeEditorPreview *p_preview_tab, const Stri
preview_tabs->add_tab(p_preview_name, p_icon);
preview_tabs_content->add_child(p_preview_tab);
- preview_tabs->set_tab_right_button(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("close"), SNAME("TabBar")));
+ preview_tabs->set_tab_button_icon(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("close"), SNAME("TabBar")));
p_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));
preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);
@@ -3308,7 +3618,9 @@ ThemeEditor::ThemeEditor() {
theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));
top_menu->add_child(theme_edit_button);
- theme_edit_dialog = memnew(ThemeItemEditorDialog);
+ theme_type_editor = memnew(ThemeTypeEditor);
+
+ theme_edit_dialog = memnew(ThemeItemEditorDialog(theme_type_editor));
theme_edit_dialog->hide();
top_menu->add_child(theme_edit_dialog);
@@ -3329,11 +3641,10 @@ ThemeEditor::ThemeEditor() {
preview_tabs_vb->add_child(preview_tabs_content);
preview_tabs = memnew(TabBar);
- preview_tabs->set_tab_align(TabBar::ALIGN_LEFT);
preview_tabs->set_h_size_flags(SIZE_EXPAND_FILL);
preview_tabbar_hb->add_child(preview_tabs);
preview_tabs->connect("tab_changed", callable_mp(this, &ThemeEditor::_change_preview_tab));
- preview_tabs->connect("tab_rmb_clicked", callable_mp(this, &ThemeEditor::_remove_preview_tab));
+ preview_tabs->connect("tab_button_pressed", callable_mp(this, &ThemeEditor::_remove_preview_tab));
HBoxContainer *add_preview_button_hb = memnew(HBoxContainer);
preview_tabbar_hb->add_child(add_preview_button_hb);
@@ -3353,12 +3664,11 @@ ThemeEditor::ThemeEditor() {
List<String> ext;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &ext);
for (const String &E : ext) {
- preview_scene_dialog->add_filter("*." + E + "; Scene");
+ preview_scene_dialog->add_filter(vformat("*.%s; %s", E, TTR("Scene")));
}
main_hs->add_child(preview_scene_dialog);
preview_scene_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_preview_scene_dialog_cbk));
- theme_type_editor = memnew(ThemeTypeEditor);
main_hs->add_child(theme_type_editor);
theme_type_editor->set_custom_minimum_size(Size2(280, 0) * EDSCALE);
}
@@ -3447,21 +3757,20 @@ bool ThemeEditorPlugin::handles(Object *p_node) const {
void ThemeEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
button->show();
- editor->make_bottom_panel_item_visible(theme_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(theme_editor);
} else {
if (theme_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
button->hide();
}
}
-ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+ThemeEditorPlugin::ThemeEditorPlugin() {
theme_editor = memnew(ThemeEditor);
theme_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
- button = editor->add_bottom_panel_item(TTR("Theme"), theme_editor);
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Theme"), theme_editor);
button->hide();
}
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index f5ad577aff..3894ca31e5 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,15 +31,20 @@
#ifndef THEME_EDITOR_PLUGIN_H
#define THEME_EDITOR_PLUGIN_H
+#include "editor/editor_plugin.h"
+#include "editor/plugins/theme_editor_preview.h"
+#include "scene/gui/check_button.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/item_list.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/tab_bar.h"
#include "scene/gui/texture_rect.h"
+#include "scene/gui/tree.h"
#include "scene/resources/theme.h"
-#include "theme_editor_preview.h"
-#include "editor/editor_node.h"
+class EditorFileDialog;
class ThemeItemImportTree : public VBoxContainer {
GDCLASS(ThemeItemImportTree, VBoxContainer);
@@ -70,9 +75,9 @@ class ThemeItemImportTree : public VBoxContainer {
Map<ThemeItem, ItemCheckedState> selected_items;
- LineEdit *import_items_filter;
+ LineEdit *import_items_filter = nullptr;
- Tree *import_items_tree;
+ Tree *import_items_tree = nullptr;
List<TreeItem *> tree_color_items;
List<TreeItem *> tree_constant_items;
List<TreeItem *> tree_font_items;
@@ -87,57 +92,57 @@ class ThemeItemImportTree : public VBoxContainer {
IMPORT_ITEM_DATA = 2,
};
- TextureRect *select_colors_icon;
- Label *select_colors_label;
- Button *select_all_colors_button;
- Button *select_full_colors_button;
- Button *deselect_all_colors_button;
- Label *total_selected_colors_label;
-
- TextureRect *select_constants_icon;
- Label *select_constants_label;
- Button *select_all_constants_button;
- Button *select_full_constants_button;
- Button *deselect_all_constants_button;
- Label *total_selected_constants_label;
-
- TextureRect *select_fonts_icon;
- Label *select_fonts_label;
- Button *select_all_fonts_button;
- Button *select_full_fonts_button;
- Button *deselect_all_fonts_button;
- Label *total_selected_fonts_label;
-
- TextureRect *select_font_sizes_icon;
- Label *select_font_sizes_label;
- Button *select_all_font_sizes_button;
- Button *select_full_font_sizes_button;
- Button *deselect_all_font_sizes_button;
- Label *total_selected_font_sizes_label;
-
- TextureRect *select_icons_icon;
- Label *select_icons_label;
- Button *select_all_icons_button;
- Button *select_full_icons_button;
- Button *deselect_all_icons_button;
- Label *total_selected_icons_label;
-
- TextureRect *select_styleboxes_icon;
- Label *select_styleboxes_label;
- Button *select_all_styleboxes_button;
- Button *select_full_styleboxes_button;
- Button *deselect_all_styleboxes_button;
- Label *total_selected_styleboxes_label;
-
- HBoxContainer *select_icons_warning_hb;
- TextureRect *select_icons_warning_icon;
- Label *select_icons_warning;
-
- Button *import_collapse_types_button;
- Button *import_expand_types_button;
- Button *import_select_all_button;
- Button *import_select_full_button;
- Button *import_deselect_all_button;
+ TextureRect *select_colors_icon = nullptr;
+ Label *select_colors_label = nullptr;
+ Button *select_all_colors_button = nullptr;
+ Button *select_full_colors_button = nullptr;
+ Button *deselect_all_colors_button = nullptr;
+ Label *total_selected_colors_label = nullptr;
+
+ TextureRect *select_constants_icon = nullptr;
+ Label *select_constants_label = nullptr;
+ Button *select_all_constants_button = nullptr;
+ Button *select_full_constants_button = nullptr;
+ Button *deselect_all_constants_button = nullptr;
+ Label *total_selected_constants_label = nullptr;
+
+ TextureRect *select_fonts_icon = nullptr;
+ Label *select_fonts_label = nullptr;
+ Button *select_all_fonts_button = nullptr;
+ Button *select_full_fonts_button = nullptr;
+ Button *deselect_all_fonts_button = nullptr;
+ Label *total_selected_fonts_label = nullptr;
+
+ TextureRect *select_font_sizes_icon = nullptr;
+ Label *select_font_sizes_label = nullptr;
+ Button *select_all_font_sizes_button = nullptr;
+ Button *select_full_font_sizes_button = nullptr;
+ Button *deselect_all_font_sizes_button = nullptr;
+ Label *total_selected_font_sizes_label = nullptr;
+
+ TextureRect *select_icons_icon = nullptr;
+ Label *select_icons_label = nullptr;
+ Button *select_all_icons_button = nullptr;
+ Button *select_full_icons_button = nullptr;
+ Button *deselect_all_icons_button = nullptr;
+ Label *total_selected_icons_label = nullptr;
+
+ TextureRect *select_styleboxes_icon = nullptr;
+ Label *select_styleboxes_label = nullptr;
+ Button *select_all_styleboxes_button = nullptr;
+ Button *select_full_styleboxes_button = nullptr;
+ Button *deselect_all_styleboxes_button = nullptr;
+ Label *total_selected_styleboxes_label = nullptr;
+
+ HBoxContainer *select_icons_warning_hb = nullptr;
+ TextureRect *select_icons_warning_icon = nullptr;
+ Label *select_icons_warning = nullptr;
+
+ Button *import_collapse_types_button = nullptr;
+ Button *import_expand_types_button = nullptr;
+ Button *import_select_all_button = nullptr;
+ Button *import_select_full_button = nullptr;
+ Button *import_deselect_all_button = nullptr;
void _update_items_tree();
void _toggle_type_items(bool p_collapse);
@@ -148,9 +153,9 @@ class ThemeItemImportTree : public VBoxContainer {
void _update_total_selected(Theme::DataType p_data_type);
void _tree_item_edited();
+ void _check_propagated_to_tree_item(Object *p_obj, int p_column);
void _select_all_subitems(TreeItem *p_root_item, bool p_select_with_data);
void _deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely);
- void _update_parent_items(TreeItem *p_root_item);
void _select_all_items_pressed();
void _select_full_items_pressed();
@@ -176,28 +181,36 @@ public:
ThemeItemImportTree();
};
+class ThemeTypeEditor;
+
class ThemeItemEditorDialog : public AcceptDialog {
GDCLASS(ThemeItemEditorDialog, AcceptDialog);
+ ThemeTypeEditor *theme_type_editor = nullptr;
+
Ref<Theme> edited_theme;
- TabContainer *tc;
+ TabContainer *tc = nullptr;
+
+ enum TypesTreeAction {
+ TYPES_TREE_REMOVE_ITEM,
+ };
- ItemList *edit_type_list;
- LineEdit *edit_add_type_value;
+ Tree *edit_type_list = nullptr;
+ LineEdit *edit_add_type_value = nullptr;
String edited_item_type;
- Button *edit_items_add_color;
- Button *edit_items_add_constant;
- Button *edit_items_add_font;
- Button *edit_items_add_font_size;
- Button *edit_items_add_icon;
- Button *edit_items_add_stylebox;
- Button *edit_items_remove_class;
- Button *edit_items_remove_custom;
- Button *edit_items_remove_all;
- Tree *edit_items_tree;
- Label *edit_items_message;
+ Button *edit_items_add_color = nullptr;
+ Button *edit_items_add_constant = nullptr;
+ Button *edit_items_add_font = nullptr;
+ Button *edit_items_add_font_size = nullptr;
+ Button *edit_items_add_icon = nullptr;
+ Button *edit_items_add_stylebox = nullptr;
+ Button *edit_items_remove_class = nullptr;
+ Button *edit_items_remove_custom = nullptr;
+ Button *edit_items_remove_all = nullptr;
+ Tree *edit_items_tree = nullptr;
+ Label *edit_items_message = nullptr;
enum ItemsTreeAction {
ITEMS_TREE_RENAME_ITEM,
@@ -205,10 +218,10 @@ class ThemeItemEditorDialog : public AcceptDialog {
ITEMS_TREE_REMOVE_DATA_TYPE,
};
- ConfirmationDialog *edit_theme_item_dialog;
- VBoxContainer *edit_theme_item_old_vb;
- Label *theme_item_old_name;
- LineEdit *theme_item_name;
+ ConfirmationDialog *edit_theme_item_dialog = nullptr;
+ VBoxContainer *edit_theme_item_old_vb = nullptr;
+ Label *theme_item_old_name = nullptr;
+ LineEdit *theme_item_name = nullptr;
enum ItemPopupMode {
CREATE_THEME_ITEM,
@@ -220,28 +233,30 @@ class ThemeItemEditorDialog : public AcceptDialog {
String edit_item_old_name;
Theme::DataType edit_item_data_type = Theme::DATA_TYPE_MAX;
- ThemeItemImportTree *import_default_theme_items;
- ThemeItemImportTree *import_editor_theme_items;
- ThemeItemImportTree *import_other_theme_items;
+ ThemeItemImportTree *import_default_theme_items = nullptr;
+ ThemeItemImportTree *import_editor_theme_items = nullptr;
+ ThemeItemImportTree *import_other_theme_items = nullptr;
- LineEdit *import_another_theme_value;
- Button *import_another_theme_button;
- EditorFileDialog *import_another_theme_dialog;
+ LineEdit *import_another_theme_value = nullptr;
+ Button *import_another_theme_button = nullptr;
+ EditorFileDialog *import_another_theme_dialog = nullptr;
- ConfirmationDialog *confirm_closing_dialog;
+ ConfirmationDialog *confirm_closing_dialog = nullptr;
void ok_pressed() override;
void _close_dialog();
void _dialog_about_to_show();
void _update_edit_types();
- void _edited_type_selected(int p_item_idx);
+ void _edited_type_selected();
+ void _edited_type_button_pressed(Object *p_item, int p_column, int p_id);
void _update_edit_item_tree(String p_item_type);
void _item_tree_button_pressed(Object *p_item, int p_column, int p_id);
void _add_theme_type(const String &p_new_text);
void _add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type);
+ void _remove_theme_type(const String &p_theme_type);
void _remove_data_type_items(Theme::DataType p_data_type, String p_item_type);
void _remove_class_items();
void _remove_custom_items();
@@ -257,11 +272,12 @@ class ThemeItemEditorDialog : public AcceptDialog {
protected:
void _notification(int p_what);
+ static void _bind_methods();
public:
void set_edited_theme(const Ref<Theme> &p_theme);
- ThemeItemEditorDialog();
+ ThemeItemEditorDialog(ThemeTypeEditor *p_theme_editor);
};
class ThemeTypeDialog : public ConfirmationDialog {
@@ -270,8 +286,11 @@ class ThemeTypeDialog : public ConfirmationDialog {
Ref<Theme> edited_theme;
bool include_own_types = false;
- LineEdit *add_type_filter;
- ItemList *add_type_options;
+ String pre_submitted_value;
+
+ LineEdit *add_type_filter = nullptr;
+ ItemList *add_type_options = nullptr;
+ ConfirmationDialog *add_type_confirmation = nullptr;
void _dialog_about_to_show();
void ok_pressed() override;
@@ -283,6 +302,9 @@ class ThemeTypeDialog : public ConfirmationDialog {
void _add_type_dialog_entered(const String &p_value);
void _add_type_dialog_activated(int p_index);
+ void _add_type_selected(const String &p_type_name);
+ void _add_type_confirmed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -310,22 +332,22 @@ class ThemeTypeEditor : public MarginContainer {
LeadingStylebox leading_stylebox;
- OptionButton *theme_type_list;
- Button *add_type_button;
+ OptionButton *theme_type_list = nullptr;
+ Button *add_type_button = nullptr;
- CheckButton *show_default_items_button;
+ CheckButton *show_default_items_button = nullptr;
- TabContainer *data_type_tabs;
- VBoxContainer *color_items_list;
- VBoxContainer *constant_items_list;
- VBoxContainer *font_items_list;
- VBoxContainer *font_size_items_list;
- VBoxContainer *icon_items_list;
- VBoxContainer *stylebox_items_list;
+ TabContainer *data_type_tabs = nullptr;
+ VBoxContainer *color_items_list = nullptr;
+ VBoxContainer *constant_items_list = nullptr;
+ VBoxContainer *font_items_list = nullptr;
+ VBoxContainer *font_size_items_list = nullptr;
+ VBoxContainer *icon_items_list = nullptr;
+ VBoxContainer *stylebox_items_list = nullptr;
- LineEdit *type_variation_edit;
- Button *type_variation_button;
- Label *type_variation_locked;
+ LineEdit *type_variation_edit = nullptr;
+ Button *type_variation_button = nullptr;
+ Label *type_variation_locked = nullptr;
enum TypeDialogMode {
ADD_THEME_TYPE,
@@ -333,10 +355,10 @@ class ThemeTypeEditor : public MarginContainer {
};
TypeDialogMode add_type_mode = ADD_THEME_TYPE;
- ThemeTypeDialog *add_type_dialog;
+ ThemeTypeDialog *add_type_dialog = nullptr;
Vector<Control *> focusables;
- Timer *update_debounce_timer;
+ Timer *update_debounce_timer = nullptr;
VBoxContainer *_create_item_list(Theme::DataType p_data_type);
void _update_type_list();
@@ -362,11 +384,14 @@ class ThemeTypeEditor : public MarginContainer {
void _color_item_changed(Color p_value, String p_item_name);
void _constant_item_changed(float p_value, String p_item_name);
void _font_size_item_changed(float p_value, String p_item_name);
- void _edit_resource_item(RES p_resource, bool p_edit);
+ void _edit_resource_item(Ref<Resource> p_resource, bool p_edit);
void _font_item_changed(Ref<Font> p_value, String p_item_name);
void _icon_item_changed(Ref<Texture2D> p_value, String p_item_name);
void _stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name);
- void _pin_leading_stylebox(Control *p_editor, String p_item_name);
+ void _change_pinned_stylebox();
+ void _on_pin_leader_button_pressed(Control *p_editor, String p_item_name);
+ void _pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_stylebox);
+ void _on_unpin_leader_button_pressed();
void _unpin_leading_stylebox();
void _update_stylebox_from_leading();
@@ -377,10 +402,12 @@ class ThemeTypeEditor : public MarginContainer {
protected:
void _notification(int p_what);
+ static void _bind_methods();
public:
void set_edited_theme(const Ref<Theme> &p_theme);
void select_type(String p_type_name);
+ bool is_stylebox_pinned(Ref<StyleBox> p_stylebox);
ThemeTypeEditor();
};
@@ -390,15 +417,15 @@ class ThemeEditor : public VBoxContainer {
Ref<Theme> theme;
- TabBar *preview_tabs;
- PanelContainer *preview_tabs_content;
- Button *add_preview_button;
- EditorFileDialog *preview_scene_dialog;
+ TabBar *preview_tabs = nullptr;
+ PanelContainer *preview_tabs_content = nullptr;
+ Button *add_preview_button = nullptr;
+ EditorFileDialog *preview_scene_dialog = nullptr;
- ThemeTypeEditor *theme_type_editor;
+ ThemeTypeEditor *theme_type_editor = nullptr;
- Label *theme_name;
- ThemeItemEditorDialog *theme_edit_dialog;
+ Label *theme_name = nullptr;
+ ThemeItemEditorDialog *theme_edit_dialog = nullptr;
void _theme_save_button_cbk(bool p_save_as);
void _theme_edit_button_cbk();
@@ -425,9 +452,8 @@ public:
class ThemeEditorPlugin : public EditorPlugin {
GDCLASS(ThemeEditorPlugin, EditorPlugin);
- ThemeEditor *theme_editor;
- EditorNode *editor;
- Button *button;
+ ThemeEditor *theme_editor = nullptr;
+ Button *button = nullptr;
public:
virtual String get_name() const override { return "Theme"; }
@@ -436,7 +462,7 @@ public:
virtual bool handles(Object *p_node) const override;
virtual void make_visible(bool p_visible) override;
- ThemeEditorPlugin(EditorNode *p_node);
+ ThemeEditorPlugin();
};
#endif // THEME_EDITOR_PLUGIN_H
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index e13a10fe3f..252a19a7db 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,11 +30,17 @@
#include "theme_editor_preview.h"
+#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/math/math_funcs.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "scene/gui/button.h"
+#include "scene/gui/color_picker.h"
+#include "scene/gui/progress_bar.h"
#include "scene/resources/packed_scene.h"
-#include "editor/editor_scale.h"
+constexpr double REFRESH_TIMER = 1.5;
void ThemeEditorPreview::set_preview_theme(const Ref<Theme> &p_theme) {
preview_content->set_theme(p_theme);
@@ -47,7 +53,7 @@ void ThemeEditorPreview::add_preview_overlay(Control *p_overlay) {
void ThemeEditorPreview::_propagate_redraw(Control *p_at) {
p_at->notification(NOTIFICATION_THEME_CHANGED);
- p_at->minimum_size_changed();
+ p_at->update_minimum_size();
p_at->update();
for (int i = 0; i < p_at->get_child_count(); i++) {
Control *a = Object::cast_to<Control>(p_at->get_child(i));
@@ -66,11 +72,14 @@ void ThemeEditorPreview::_refresh_interval() {
}
void ThemeEditorPreview::_preview_visibility_changed() {
- set_process(is_visible());
+ set_process(is_visible_in_tree());
}
void ThemeEditorPreview::_picker_button_cbk() {
picker_overlay->set_visible(picker_button->is_pressed());
+ if (picker_button->is_pressed()) {
+ _reset_picker_overlay();
+ }
}
Control *ThemeEditorPreview::_find_hovered_control(Control *p_parent, Vector2 p_mouse_position) {
@@ -133,7 +142,7 @@ void ThemeEditorPreview::_draw_picker_overlay() {
Point2 label_pos = highlight_label_rect.position;
label_pos.y += highlight_label_rect.size.y - margin_bottom;
label_pos.x += margin_left;
- picker_overlay->draw_string(theme_cache.preview_picker_font, label_pos, highlight_name, HALIGN_LEFT, -1, theme_cache.font_size);
+ picker_overlay->draw_string(theme_cache.preview_picker_font, label_pos, highlight_name, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size);
}
}
@@ -144,7 +153,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
if (hovered_control) {
StringName theme_type = hovered_control->get_theme_type_variation();
if (theme_type == StringName()) {
@@ -154,6 +163,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
emit_signal(SNAME("control_picked"), theme_type);
picker_button->set_pressed(false);
picker_overlay->set_visible(false);
+ return;
}
}
@@ -164,6 +174,9 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
hovered_control = _find_hovered_control(preview_content, mp);
picker_overlay->update();
}
+
+ // Forward input to the scroll container underneath to allow scrolling.
+ preview_container->gui_input(p_event);
}
void ThemeEditorPreview::_reset_picker_overlay() {
@@ -190,10 +203,11 @@ void ThemeEditorPreview::_notification(int p_what) {
theme_cache.preview_picker_font = get_theme_font(SNAME("status_source"), SNAME("EditorFonts"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"), SNAME("EditorFonts"));
} break;
+
case NOTIFICATION_PROCESS: {
time_left -= get_process_delta_time();
if (time_left < 0) {
- time_left = 1.5;
+ time_left = REFRESH_TIMER;
_refresh_interval();
}
} break;
@@ -220,9 +234,7 @@ ThemeEditorPreview::ThemeEditorPreview() {
preview_body->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(preview_body);
- ScrollContainer *preview_container = memnew(ScrollContainer);
- preview_container->set_enable_v_scroll(true);
- preview_container->set_enable_h_scroll(true);
+ preview_container = memnew(ScrollContainer);
preview_body->add_child(preview_container);
MarginContainer *preview_root = memnew(MarginContainer);
@@ -360,7 +372,7 @@ DefaultThemeEditorPreview::DefaultThemeEditorPreview() {
vhb->add_child(memnew(VSeparator));
VBoxContainer *hvb = memnew(VBoxContainer);
vhb->add_child(hvb);
- hvb->set_alignment(BoxContainer::ALIGN_CENTER);
+ hvb->set_alignment(BoxContainer::ALIGNMENT_CENTER);
hvb->set_h_size_flags(SIZE_EXPAND_FILL);
hvb->add_child(memnew(HSlider));
HScrollBar *hsb = memnew(HScrollBar);
diff --git a/editor/plugins/theme_editor_preview.h b/editor/plugins/theme_editor_preview.h
index f973119257..d05916afae 100644
--- a/editor/plugins/theme_editor_preview.h
+++ b/editor/plugins/theme_editor_preview.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,32 +32,19 @@
#define THEME_EDITOR_PREVIEW_H
#include "scene/gui/box_container.h"
-#include "scene/gui/check_box.h"
-#include "scene/gui/check_button.h"
-#include "scene/gui/color_picker.h"
+#include "scene/gui/button.h"
#include "scene/gui/color_rect.h"
-#include "scene/gui/label.h"
#include "scene/gui/margin_container.h"
-#include "scene/gui/menu_button.h"
-#include "scene/gui/option_button.h"
-#include "scene/gui/panel.h"
-#include "scene/gui/progress_bar.h"
#include "scene/gui/scroll_container.h"
-#include "scene/gui/separator.h"
-#include "scene/gui/spin_box.h"
-#include "scene/gui/tab_container.h"
-#include "scene/gui/text_edit.h"
-#include "scene/gui/tree.h"
#include "scene/resources/theme.h"
-#include "editor/editor_node.h"
-
class ThemeEditorPreview : public VBoxContainer {
GDCLASS(ThemeEditorPreview, VBoxContainer);
- ColorRect *preview_bg;
- MarginContainer *preview_overlay;
- Control *picker_overlay;
+ ScrollContainer *preview_container = nullptr;
+ ColorRect *preview_bg = nullptr;
+ MarginContainer *preview_overlay = nullptr;
+ Control *picker_overlay = nullptr;
Control *hovered_control = nullptr;
struct ThemeCache {
@@ -82,9 +69,9 @@ class ThemeEditorPreview : public VBoxContainer {
void _reset_picker_overlay();
protected:
- HBoxContainer *preview_toolbar;
- MarginContainer *preview_content;
- Button *picker_button;
+ HBoxContainer *preview_toolbar = nullptr;
+ MarginContainer *preview_content = nullptr;
+ Button *picker_button = nullptr;
void add_preview_overlay(Control *p_overlay);
@@ -109,7 +96,7 @@ class SceneThemeEditorPreview : public ThemeEditorPreview {
Ref<PackedScene> loaded_scene;
- Button *reload_scene_button;
+ Button *reload_scene_button = nullptr;
void _reload_scene();
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index efccac7b74..086588f5a5 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,8 @@
#include "atlas_merging_dialog.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/gui/control.h"
@@ -81,7 +83,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
}
// Copy the properties.
- TileData *original_tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_id, alternative_id));
+ TileData *original_tile_data = atlas_source->get_tile_data(tile_id, alternative_id);
List<PropertyInfo> properties;
original_tile_data->get_property_list(&properties);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
@@ -239,7 +241,7 @@ void AtlasMergingDialog::update_tile_set(Ref<TileSet> p_tile_set) {
if (texture.is_valid()) {
String item_text = vformat("%s (id:%d)", texture->get_path().get_file(), source_id);
atlas_merging_atlases_list->add_item(item_text, texture);
- atlas_merging_atlases_list->set_item_metadata(atlas_merging_atlases_list->get_item_count() - 1, source_id);
+ atlas_merging_atlases_list->set_item_metadata(-1, source_id);
}
}
}
@@ -251,6 +253,8 @@ void AtlasMergingDialog::update_tile_set(Ref<TileSet> p_tile_set) {
}
AtlasMergingDialog::AtlasMergingDialog() {
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
// Atlas merging window.
set_title(TTR("Atlas Merging"));
set_hide_on_ok(false);
@@ -301,7 +305,7 @@ AtlasMergingDialog::AtlasMergingDialog() {
preview = memnew(TextureRect);
preview->set_h_size_flags(Control::SIZE_EXPAND_FILL);
preview->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- preview->set_expand(true);
+ preview->set_ignore_texture_size(true);
preview->hide();
preview->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
atlas_merging_right_panel->add_child(preview);
@@ -309,8 +313,8 @@ AtlasMergingDialog::AtlasMergingDialog() {
select_2_atlases_label = memnew(Label);
select_2_atlases_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
select_2_atlases_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- select_2_atlases_label->set_align(Label::ALIGN_CENTER);
- select_2_atlases_label->set_valign(Label::VALIGN_CENTER);
+ select_2_atlases_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ select_2_atlases_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
select_2_atlases_label->set_text(TTR("Please select two atlases or more."));
atlas_merging_right_panel->add_child(select_2_atlases_label);
diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h
index 7cb54bc17e..9502d93f6b 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.h
+++ b/editor/plugins/tiles/atlas_merging_dialog.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,14 +31,14 @@
#ifndef ATLAS_MERGING_DIALOG_H
#define ATLAS_MERGING_DIALOG_H
-#include "editor/editor_node.h"
#include "editor/editor_properties.h"
-
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
#include "scene/gui/texture_rect.h"
#include "scene/resources/tile_set.h"
+class EditorFileDialog;
+
class AtlasMergingDialog : public ConfirmationDialog {
GDCLASS(AtlasMergingDialog, ConfirmationDialog);
@@ -49,19 +49,19 @@ private:
LocalVector<Map<Vector2i, Vector2i>> merged_mapping;
Ref<TileSet> tile_set;
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
// Settings.
int next_line_after_column = 30;
// GUI.
- ItemList *atlas_merging_atlases_list;
- EditorPropertyVector2i *texture_region_size_editor_property;
- EditorPropertyInteger *columns_editor_property;
- TextureRect *preview;
- Label *select_2_atlases_label;
- EditorFileDialog *editor_file_dialog;
- Button *merge_button;
+ ItemList *atlas_merging_atlases_list = nullptr;
+ EditorPropertyVector2i *texture_region_size_editor_property = nullptr;
+ EditorPropertyInteger *columns_editor_property = nullptr;
+ TextureRect *preview = nullptr;
+ Label *select_2_atlases_label = nullptr;
+ EditorFileDialog *editor_file_dialog = nullptr;
+ Button *merge_button = nullptr;
void _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index c064073b77..4de2f42fe0 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -36,58 +36,31 @@
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/panel.h"
-#include "scene/gui/texture_rect.h"
+#include "scene/gui/view_panner.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
void TileAtlasView::gui_input(const Ref<InputEvent> &p_event) {
- Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid()) {
- drag_type = DRAG_TYPE_NONE;
-
- Vector2i scroll_vec = Vector2((mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT) - (mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT), (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) - (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN));
- if (scroll_vec != Vector2()) {
- if (mb->is_ctrl_pressed()) {
- if (mb->is_shift_pressed()) {
- panning.x += 32 * mb->get_factor() * scroll_vec.y;
- panning.y += 32 * mb->get_factor() * scroll_vec.x;
- } else {
- panning.y += 32 * mb->get_factor() * scroll_vec.y;
- panning.x += 32 * mb->get_factor() * scroll_vec.x;
- }
-
- emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
- _update_zoom_and_panning(true);
- accept_event();
+ if (panner->gui_input(p_event)) {
+ accept_event();
+ }
+}
- } else if (!mb->is_shift_pressed()) {
- zoom_widget->set_zoom_by_increments(scroll_vec.y * 2);
- emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
- _update_zoom_and_panning(true);
- accept_event();
- }
- }
+void TileAtlasView::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
+ _pan_callback(-p_scroll_vec * 32);
+}
- if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- if (mb->is_pressed()) {
- drag_type = DRAG_TYPE_PAN;
- } else {
- drag_type = DRAG_TYPE_NONE;
- }
- accept_event();
- }
- }
+void TileAtlasView::_pan_callback(Vector2 p_scroll_vec) {
+ panning += p_scroll_vec;
+ emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
+ _update_zoom_and_panning(true);
+}
- Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid()) {
- if (drag_type == DRAG_TYPE_PAN) {
- panning += mm->get_relative();
- _update_zoom_and_panning();
- emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
- accept_event();
- }
- }
+void TileAtlasView::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
+ zoom_widget->set_zoom_by_increments(-p_scroll_vec.y * 2);
+ emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
+ _update_zoom_and_panning(true);
}
Size2i TileAtlasView::_compute_base_tiles_control_size() {
@@ -109,7 +82,7 @@ Size2i TileAtlasView::_compute_alternative_tiles_control_size() {
Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(tile_id).size;
for (int j = 1; j < alternatives_count; j++) {
int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
- bool transposed = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(tile_id, alternative_id))->get_transpose();
+ bool transposed = tile_set_atlas_source->get_tile_data(tile_id, alternative_id)->get_transpose();
line_size.x += transposed ? texture_region_size.y : texture_region_size.x;
line_size.y = MAX(line_size.y, transposed ? texture_region_size.x : texture_region_size.y);
}
@@ -121,6 +94,8 @@ Size2i TileAtlasView::_compute_alternative_tiles_control_size() {
}
void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
+ // Don't allow zoom to go below 1% or above 10000%
+ zoom_widget->set_zoom(CLAMP(zoom_widget->get_zoom(), 0.01f, 100.f));
float zoom = zoom_widget->get_zoom();
// Compute the minimum sizes.
@@ -371,11 +346,11 @@ void TileAtlasView::_draw_alternatives() {
int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(atlas_coords);
for (int j = 1; j < alternatives_count; j++) {
int alternative_id = tile_set_atlas_source->get_alternative_tile_id(atlas_coords, j);
- TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(atlas_coords, alternative_id));
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(atlas_coords, alternative_id);
bool transposed = tile_data->get_transpose();
// Update the y to max value.
- Vector2i offset_pos = current_pos;
+ Vector2i offset_pos;
if (transposed) {
offset_pos = (current_pos + Vector2(texture_region_size.y, texture_region_size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
y_increment = MAX(y_increment, texture_region_size.x);
@@ -499,7 +474,7 @@ void TileAtlasView::_update_alternative_tiles_rect_cache() {
int line_height = 0;
for (int j = 1; j < alternatives_count; j++) {
int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
- TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(tile_id, alternative_id));
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(tile_id, alternative_id);
bool transposed = tile_data->get_transpose();
current.size = transposed ? Vector2i(texture_region_size.y, texture_region_size.x) : texture_region_size;
@@ -548,9 +523,14 @@ void TileAtlasView::update() {
void TileAtlasView::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY:
+ case NOTIFICATION_ENTER_TREE:
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ } break;
+
+ case NOTIFICATION_READY: {
button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons")));
- break;
+ } break;
}
}
@@ -584,10 +564,16 @@ TileAtlasView::TileAtlasView() {
button_center_view->set_tooltip(TTR("Center View"));
add_child(button_center_view);
+ panner.instantiate();
+ panner->set_callbacks(callable_mp(this, &TileAtlasView::_scroll_callback), callable_mp(this, &TileAtlasView::_pan_callback), callable_mp(this, &TileAtlasView::_zoom_callback));
+ panner->set_enable_rmb(true);
+
center_container = memnew(CenterContainer);
center_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
center_container->set_anchors_preset(Control::PRESET_CENTER);
center_container->connect("gui_input", callable_mp(this, &TileAtlasView::gui_input));
+ center_container->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key));
+ center_container->set_focus_mode(FOCUS_CLICK);
panel->add_child(center_container);
missing_source_label = memnew(Label);
@@ -616,7 +602,7 @@ TileAtlasView::TileAtlasView() {
Label *base_tile_label = memnew(Label);
base_tile_label->set_mouse_filter(Control::MOUSE_FILTER_PASS);
base_tile_label->set_text(TTR("Base Tiles"));
- base_tile_label->set_align(Label::ALIGN_CENTER);
+ base_tile_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
left_vbox->add_child(base_tile_label);
base_tiles_root_control = memnew(Control);
@@ -660,7 +646,7 @@ TileAtlasView::TileAtlasView() {
Label *alternative_tiles_label = memnew(Label);
alternative_tiles_label->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
alternative_tiles_label->set_text(TTR("Alternative Tiles"));
- alternative_tiles_label->set_align(Label::ALIGN_CENTER);
+ alternative_tiles_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
right_vbox->add_child(alternative_tiles_label);
alternative_tiles_root_control = memnew(Control);
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index e1ca3eebee..6e74858b08 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,16 +37,16 @@
#include "scene/gui/center_container.h"
#include "scene/gui/label.h"
#include "scene/gui/margin_container.h"
-#include "scene/gui/scroll_container.h"
-#include "scene/gui/texture_rect.h"
#include "scene/resources/tile_set.h"
+class ViewPanner;
+
class TileAtlasView : public Control {
GDCLASS(TileAtlasView, Control);
private:
- TileSet *tile_set;
- TileSetAtlasSource *tile_set_atlas_source;
+ TileSet *tile_set = nullptr;
+ TileSetAtlasSource *tile_set_atlas_source = nullptr;
int source_id = TileSet::INVALID_SOURCE;
enum DragType {
@@ -55,53 +55,58 @@ private:
};
DragType drag_type = DRAG_TYPE_NONE;
float previous_zoom = 1.0;
- EditorZoomWidget *zoom_widget;
- Button *button_center_view;
- CenterContainer *center_container;
+ EditorZoomWidget *zoom_widget = nullptr;
+ Button *button_center_view = nullptr;
+ CenterContainer *center_container = nullptr;
Vector2 panning;
void _update_zoom_and_panning(bool p_zoom_on_mouse_pos = false);
void _zoom_widget_changed();
void _center_view();
virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ Ref<ViewPanner> panner;
+ void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
+ void _pan_callback(Vector2 p_scroll_vec);
+ void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+
Map<Vector2, Map<int, Rect2i>> alternative_tiles_rect_cache;
void _update_alternative_tiles_rect_cache();
- MarginContainer *margin_container;
+ MarginContainer *margin_container = nullptr;
int margin_container_paddings[4] = { 0, 0, 0, 0 };
- HBoxContainer *hbox;
- Label *missing_source_label;
+ HBoxContainer *hbox = nullptr;
+ Label *missing_source_label = nullptr;
// Background
- Control *background_left;
+ Control *background_left = nullptr;
void _draw_background_left();
- Control *background_right;
+ Control *background_right = nullptr;
void _draw_background_right();
// Left side.
- Control *base_tiles_root_control;
+ Control *base_tiles_root_control = nullptr;
void _base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event);
- Control *base_tiles_drawing_root;
+ Control *base_tiles_drawing_root = nullptr;
- Control *base_tiles_draw;
+ Control *base_tiles_draw = nullptr;
void _draw_base_tiles();
- Control *base_tiles_texture_grid;
+ Control *base_tiles_texture_grid = nullptr;
void _draw_base_tiles_texture_grid();
- Control *base_tiles_shape_grid;
+ Control *base_tiles_shape_grid = nullptr;
void _draw_base_tiles_shape_grid();
Size2i _compute_base_tiles_control_size();
// Right side.
- Control *alternative_tiles_root_control;
+ Control *alternative_tiles_root_control = nullptr;
void _alternative_tiles_root_control_gui_input(const Ref<InputEvent> &p_event);
- Control *alternative_tiles_drawing_root;
+ Control *alternative_tiles_drawing_root = nullptr;
- Control *alternatives_draw;
+ Control *alternatives_draw = nullptr;
void _draw_alternatives();
Size2i _compute_alternative_tiles_control_size();
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index e9d80bb4b8..70bcd7e39a 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -35,12 +35,13 @@
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
void TileDataEditor::_tile_set_changed_plan_update() {
_tile_set_changed_update_needed = true;
- call_deferred("_tile_set_changed_deferred_update");
+ call_deferred(SNAME("_tile_set_changed_deferred_update"));
}
void TileDataEditor::_tile_set_changed_deferred_update() {
@@ -60,7 +61,7 @@ TileData *TileDataEditor::_get_tile_data(TileMapCell p_cell) {
if (atlas_source) {
ERR_FAIL_COND_V(!atlas_source->has_tile(p_cell.get_atlas_coords()), nullptr);
ERR_FAIL_COND_V(!atlas_source->has_alternative_tile(p_cell.get_atlas_coords(), p_cell.alternative_tile), nullptr);
- td = Object::cast_to<TileData>(atlas_source->get_tile_data(p_cell.get_atlas_coords(), p_cell.alternative_tile));
+ td = atlas_source->get_tile_data(p_cell.get_atlas_coords(), p_cell.alternative_tile);
}
return td;
@@ -125,7 +126,14 @@ void GenericTilePolygonEditor::_base_control_draw() {
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorPathSharpHandle"), SNAME("EditorIcons"));
const Ref<Texture2D> add_handle = get_theme_icon(SNAME("EditorHandleAdd"), SNAME("EditorIcons"));
+ const Ref<StyleBox> focus_stylebox = get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"));
+ // Draw the focus rectangle.
+ if (base_control->has_focus()) {
+ base_control->draw_style_box(focus_stylebox, Rect2(Vector2(), base_control->get_size()));
+ }
+
+ // Draw tile-related things.
Size2 tile_size = tile_set->get_tile_size();
Transform2D xform;
@@ -211,7 +219,7 @@ void GenericTilePolygonEditor::_base_control_draw() {
int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
String text = multiple_polygon_mode ? vformat("%d:%d", tinted_polygon_index, tinted_point_index) : vformat("%d", tinted_point_index);
Size2 text_size = font->get_string_size(text, font_size);
- base_control->draw_string(font, xform.xform(polygons[tinted_polygon_index][tinted_point_index]) - text_size * 0.5, text, HALIGN_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5));
+ base_control->draw_string(font, xform.xform(polygons[tinted_polygon_index][tinted_point_index]) - text_size * 0.5, text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5));
}
if (drag_type == DRAG_TYPE_CREATE_POINT) {
@@ -240,9 +248,10 @@ void GenericTilePolygonEditor::_zoom_changed() {
}
void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
+ UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo);
switch (p_item_pressed) {
case RESET_TO_DEFAULT_TILE: {
- undo_redo->create_action(TTR("Edit Polygons"));
+ undo_redo->create_action(TTR("Reset Polygons"));
undo_redo->add_do_method(this, "clear_polygons");
Vector<Vector2> polygon = tile_set->get_tile_shape_polygon();
for (int i = 0; i < polygon.size(); i++) {
@@ -260,7 +269,7 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
undo_redo->commit_action(true);
} break;
case CLEAR_TILE: {
- undo_redo->create_action(TTR("Edit Polygons"));
+ undo_redo->create_action(TTR("Clear Polygons"));
undo_redo->add_do_method(this, "clear_polygons");
undo_redo->add_do_method(base_control, "update");
undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
@@ -272,9 +281,50 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
undo_redo->commit_action(true);
} break;
+ case ROTATE_RIGHT:
+ case ROTATE_LEFT:
+ case FLIP_HORIZONTALLY:
+ case FLIP_VERTICALLY: {
+ undo_redo->create_action(TTR("Rotate Polygons Left"));
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ Vector<Point2> new_polygon;
+ for (int point_index = 0; point_index < polygons[i].size(); point_index++) {
+ Vector2 point = polygons[i][point_index];
+ switch (p_item_pressed) {
+ case ROTATE_RIGHT: {
+ point = Vector2(-point.y, point.x);
+ } break;
+ case ROTATE_LEFT: {
+ point = Vector2(point.y, -point.x);
+ } break;
+ case FLIP_HORIZONTALLY: {
+ point = Vector2(-point.x, point.y);
+ } break;
+ case FLIP_VERTICALLY: {
+ point = Vector2(point.x, -point.y);
+ } break;
+ default:
+ break;
+ }
+ new_polygon.push_back(point);
+ }
+ undo_redo->add_do_method(this, "set_polygon", i, new_polygon);
+ }
+ undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
+ for (unsigned int i = 0; i < polygons.size(); i++) {
+ undo_redo->add_undo_method(this, "set_polygon", polygons[i]);
+ }
+ undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
+ undo_redo->commit_action(true);
+ } break;
default:
break;
}
+ if (!use_undo_redo) {
+ memdelete(undo_redo);
+ }
}
void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) {
@@ -359,6 +409,7 @@ void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) {
}
void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) {
+ UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo);
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
hovered_polygon_index = -1;
@@ -399,15 +450,15 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_ctrl_pressed()) {
+ if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_ctrl_pressed()) {
editor_zoom_widget->set_zoom_by_increments(1);
_zoom_changed();
accept_event();
- } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_ctrl_pressed()) {
+ } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_ctrl_pressed()) {
editor_zoom_widget->set_zoom_by_increments(-1);
_zoom_changed();
accept_event();
- } else if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ } else if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (tools_button_group->get_pressed_button() != button_create) {
in_creation_polygon.clear();
@@ -466,7 +517,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
_grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point);
if (closest_polygon >= 0) {
PackedVector2Array old_polygon = polygons[closest_polygon];
- polygons[closest_polygon].remove(closest_point);
+ polygons[closest_polygon].remove_at(closest_point);
undo_redo->create_action(TTR("Edit Polygons"));
if (polygons[closest_polygon].size() < 3) {
remove_polygon(closest_polygon);
@@ -504,7 +555,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
drag_point_index = -1;
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed()) {
if (tools_button_group->get_pressed_button() == button_edit) {
// Remove point or pan.
@@ -513,7 +564,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
_grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point);
if (closest_polygon >= 0) {
PackedVector2Array old_polygon = polygons[closest_polygon];
- polygons[closest_polygon].remove(closest_point);
+ polygons[closest_polygon].remove_at(closest_point);
undo_redo->create_action(TTR("Edit Polygons"));
if (polygons[closest_polygon].size() < 3) {
remove_polygon(closest_polygon);
@@ -538,7 +589,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
} else {
drag_type = DRAG_TYPE_NONE;
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
+ } else if (mb->get_button_index() == MouseButton::MIDDLE) {
if (mb->is_pressed()) {
drag_type = DRAG_TYPE_PAN;
drag_last_pos = mb->get_position();
@@ -549,21 +600,47 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
}
base_control->update();
+
+ if (!use_undo_redo) {
+ memdelete(undo_redo);
+ }
+}
+
+void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
+ use_undo_redo = p_use_undo_redo;
}
void GenericTilePolygonEditor::set_tile_set(Ref<TileSet> p_tile_set) {
- if (tile_set != p_tile_set) {
- // Set the default tile shape
- clear_polygons();
- if (p_tile_set.is_valid()) {
- Vector<Vector2> polygon = p_tile_set->get_tile_shape_polygon();
- for (int i = 0; i < polygon.size(); i++) {
- polygon.write[i] = polygon[i] * p_tile_set->get_tile_size();
- }
- add_polygon(polygon);
+ ERR_FAIL_COND(!p_tile_set.is_valid());
+ if (tile_set == p_tile_set) {
+ return;
+ }
+
+ // Set the default tile shape
+ clear_polygons();
+ if (p_tile_set.is_valid()) {
+ Vector<Vector2> polygon = p_tile_set->get_tile_shape_polygon();
+ for (int i = 0; i < polygon.size(); i++) {
+ polygon.write[i] = polygon[i] * p_tile_set->get_tile_size();
}
+ add_polygon(polygon);
}
+
tile_set = p_tile_set;
+
+ // Set the default zoom value.
+ int default_control_y_size = 200 * EDSCALE;
+ Vector2 zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size();
+ while (zoomed_tile.y < default_control_y_size) {
+ editor_zoom_widget->set_zoom_by_increments(6, false);
+ zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size();
+ }
+ while (zoomed_tile.y > default_control_y_size) {
+ editor_zoom_widget->set_zoom_by_increments(-6, false);
+ zoomed_tile = editor_zoom_widget->get_zoom() * tile_set->get_tile_size();
+ }
+ editor_zoom_widget->set_zoom_by_increments(-6, false);
+ _zoom_changed();
}
void GenericTilePolygonEditor::set_background(Ref<Texture2D> p_texture, Rect2 p_region, Vector2 p_offset, bool p_flip_h, bool p_flip_v, bool p_transpose, Color p_modulate) {
@@ -600,7 +677,7 @@ int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index)
void GenericTilePolygonEditor::remove_polygon(int p_index) {
ERR_FAIL_INDEX(p_index, (int)polygons.size());
- polygons.remove(p_index);
+ polygons.remove_at(p_index);
if (polygons.size() == 0) {
button_create->set_pressed(true);
@@ -637,14 +714,21 @@ void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon
void GenericTilePolygonEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY:
- button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
- button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
- button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
- button_center_view->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons")));
- button_pixel_snap->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
- button_advanced_menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
- break;
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ button_create->set_icon(get_theme_icon(SNAME("CurveCreate"), SNAME("EditorIcons")));
+ button_edit->set_icon(get_theme_icon(SNAME("CurveEdit"), SNAME("EditorIcons")));
+ button_delete->set_icon(get_theme_icon(SNAME("CurveDelete"), SNAME("EditorIcons")));
+ button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons")));
+ button_pixel_snap->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
+ button_advanced_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+
+ PopupMenu *p = button_advanced_menu->get_popup();
+ p->set_item_icon(p->get_item_index(ROTATE_RIGHT), get_theme_icon(SNAME("RotateRight"), SNAME("EditorIcons")));
+ p->set_item_icon(p->get_item_index(ROTATE_LEFT), get_theme_icon(SNAME("RotateLeft"), SNAME("EditorIcons")));
+ p->set_item_icon(p->get_item_index(FLIP_HORIZONTALLY), get_theme_icon(SNAME("MirrorX"), SNAME("EditorIcons")));
+ p->set_item_icon(p->get_item_index(FLIP_VERTICALLY), get_theme_icon(SNAME("MirrorY"), SNAME("EditorIcons")));
+ } break;
}
}
@@ -660,6 +744,8 @@ void GenericTilePolygonEditor::_bind_methods() {
}
GenericTilePolygonEditor::GenericTilePolygonEditor() {
+ editor_undo_redo = EditorNode::get_undo_redo();
+
toolbar = memnew(HBoxContainer);
add_child(toolbar);
@@ -670,18 +756,21 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_create->set_toggle_mode(true);
button_create->set_button_group(tools_button_group);
button_create->set_pressed(true);
+ button_create->set_tooltip(TTR("Add polygon tool"));
toolbar->add_child(button_create);
button_edit = memnew(Button);
button_edit->set_flat(true);
button_edit->set_toggle_mode(true);
button_edit->set_button_group(tools_button_group);
+ button_edit->set_tooltip(TTR("Edit points tool"));
toolbar->add_child(button_edit);
button_delete = memnew(Button);
button_delete->set_flat(true);
button_delete->set_toggle_mode(true);
button_delete->set_button_group(tools_button_group);
+ button_delete->set_tooltip(TTR("Delete points tool"));
toolbar->add_child(button_delete);
button_advanced_menu = memnew(MenuButton);
@@ -689,7 +778,13 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_advanced_menu->set_toggle_mode(true);
button_advanced_menu->get_popup()->add_item(TTR("Reset to default tile shape"), RESET_TO_DEFAULT_TILE);
button_advanced_menu->get_popup()->add_item(TTR("Clear"), CLEAR_TILE);
+ button_advanced_menu->get_popup()->add_separator();
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("RotateRight"), SNAME("EditorIcons")), TTR("Rotate Right"), ROTATE_RIGHT);
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("RotateLeft"), SNAME("EditorIcons")), TTR("Rotate Left"), ROTATE_LEFT);
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("MirrorX"), SNAME("EditorIcons")), TTR("Flip Horizontally"), FLIP_HORIZONTALLY);
+ button_advanced_menu->get_popup()->add_icon_item(get_theme_icon(SNAME("MirrorY"), SNAME("EditorIcons")), TTR("Flip Vertically"), FLIP_VERTICALLY);
button_advanced_menu->get_popup()->connect("id_pressed", callable_mp(this, &GenericTilePolygonEditor::_advanced_menu_item_pressed));
+ button_advanced_menu->set_focus_mode(FOCUS_ALL);
toolbar->add_child(button_advanced_menu);
toolbar->add_child(memnew(VSeparator));
@@ -698,6 +793,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_pixel_snap->set_flat(true);
button_pixel_snap->set_toggle_mode(true);
button_pixel_snap->set_pressed(true);
+ button_pixel_snap->set_tooltip(TTR("Snap to half-pixel"));
toolbar->add_child(button_pixel_snap);
Control *root = memnew(Control);
@@ -717,6 +813,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
base_control->connect("draw", callable_mp(this, &GenericTilePolygonEditor::_base_control_draw));
base_control->connect("gui_input", callable_mp(this, &GenericTilePolygonEditor::_base_control_gui_input));
base_control->set_clip_contents(true);
+ base_control->set_focus_mode(Control::FOCUS_CLICK);
root->add_child(base_control);
editor_zoom_widget = memnew(EditorZoomWidget);
@@ -744,7 +841,7 @@ Variant TileDataDefaultEditor::_get_painted_value() {
}
void TileDataDefaultEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
Variant value = tile_data->get(property);
dummy_object->set(property, value);
@@ -754,13 +851,13 @@ void TileDataDefaultEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_at
}
void TileDataDefaultEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
tile_data->set(property, p_value);
}
Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND_V(!tile_data, Variant());
return tile_data->get(property);
}
@@ -836,7 +933,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (picker_button->is_pressed()) {
Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
@@ -927,7 +1024,7 @@ void TileDataDefaultEditor::forward_painting_alternatives_gui_input(TileAtlasVie
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (picker_button->is_pressed()) {
Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position());
@@ -1020,7 +1117,7 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2
}
Vector2 string_size = font->get_string_size(text, font_size);
- p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1));
+ p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1));
}
}
@@ -1055,6 +1152,7 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p
property_editor->set_label(p_label);
}
property_editor->connect("property_changed", callable_mp(this, &TileDataDefaultEditor::_property_value_changed).unbind(1));
+ property_editor->set_tooltip(p_property);
property_editor->update_property();
add_child(property_editor);
}
@@ -1062,17 +1160,17 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p
void TileDataDefaultEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
tile_bool_checked = get_theme_icon(SNAME("TileChecked"), SNAME("EditorIcons"));
tile_bool_unchecked = get_theme_icon(SNAME("TileUnchecked"), SNAME("EditorIcons"));
- break;
- default:
- break;
+ } break;
}
}
TileDataDefaultEditor::TileDataDefaultEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
label = memnew(Label);
label->set_text(TTR("Painting:"));
add_child(label);
@@ -1082,7 +1180,7 @@ TileDataDefaultEditor::TileDataDefaultEditor() {
picker_button = memnew(Button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P));
toolbar->add_child(picker_button);
}
@@ -1175,7 +1273,7 @@ Variant TileDataOcclusionShapeEditor::_get_painted_value() {
}
void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer);
@@ -1187,7 +1285,7 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile
}
void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
Ref<OccluderPolygon2D> occluder_polygon = p_value;
tile_data->set_occluder(occlusion_layer, occluder_polygon);
@@ -1196,7 +1294,7 @@ void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atl
}
Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND_V(!tile_data, Variant());
return tile_data->get_occluder(occlusion_layer);
}
@@ -1215,15 +1313,15 @@ void TileDataOcclusionShapeEditor::_tile_set_changed() {
void TileDataOcclusionShapeEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_ENTER_TREE: {
polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color());
- break;
- default:
- break;
+ } break;
}
}
TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
polygon_editor = memnew(GenericTilePolygonEditor);
add_child(polygon_editor);
}
@@ -1232,6 +1330,15 @@ void TileDataCollisionEditor::_property_value_changed(StringName p_property, Var
dummy_object->set(p_property, p_value);
}
+void TileDataCollisionEditor::_property_selected(StringName p_path, int p_focusable) {
+ // Deselect all other properties
+ for (KeyValue<StringName, EditorProperty *> &editor : property_editors) {
+ if (editor.key != p_path) {
+ editor.value->deselect();
+ }
+ }
+}
+
void TileDataCollisionEditor::_polygons_changed() {
// Update the dummy object properties and their editors.
for (int i = 0; i < polygon_editor->get_polygon_count(); i++) {
@@ -1253,6 +1360,8 @@ void TileDataCollisionEditor::_polygons_changed() {
one_way_property_editor->set_object_and_property(dummy_object, one_way_property);
one_way_property_editor->set_label(one_way_property);
one_way_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
+ one_way_property_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
+ one_way_property_editor->set_tooltip(one_way_property_editor->get_edited_property());
one_way_property_editor->update_property();
add_child(one_way_property_editor);
property_editors[one_way_property] = one_way_property_editor;
@@ -1263,6 +1372,8 @@ void TileDataCollisionEditor::_polygons_changed() {
one_way_margin_property_editor->set_object_and_property(dummy_object, one_way_margin_property);
one_way_margin_property_editor->set_label(one_way_margin_property);
one_way_margin_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
+ one_way_margin_property_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
+ one_way_margin_property_editor->set_tooltip(one_way_margin_property_editor->get_edited_property());
one_way_margin_property_editor->update_property();
add_child(one_way_margin_property_editor);
property_editors[one_way_margin_property] = one_way_margin_property_editor;
@@ -1305,7 +1416,7 @@ Variant TileDataCollisionEditor::_get_painted_value() {
}
void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
polygon_editor->clear_polygons();
@@ -1331,7 +1442,7 @@ void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_
}
void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
Dictionary dict = p_value;
@@ -1350,7 +1461,7 @@ void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_so
}
Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND_V(!tile_data, Variant());
Dictionary dict;
@@ -1399,15 +1510,15 @@ void TileDataCollisionEditor::_tile_set_changed() {
void TileDataCollisionEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_ENTER_TREE: {
polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color());
- break;
- default:
- break;
+ } break;
}
}
TileDataCollisionEditor::TileDataCollisionEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
polygon_editor = memnew(GenericTilePolygonEditor);
polygon_editor->set_multiple_polygon_mode(true);
polygon_editor->connect("polygons_changed", callable_mp(this, &TileDataCollisionEditor::_polygons_changed));
@@ -1422,6 +1533,8 @@ TileDataCollisionEditor::TileDataCollisionEditor() {
linear_velocity_editor->set_object_and_property(dummy_object, "linear_velocity");
linear_velocity_editor->set_label("linear_velocity");
linear_velocity_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
+ linear_velocity_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
+ linear_velocity_editor->set_tooltip(linear_velocity_editor->get_edited_property());
linear_velocity_editor->update_property();
add_child(linear_velocity_editor);
property_editors["linear_velocity"] = linear_velocity_editor;
@@ -1430,9 +1543,11 @@ TileDataCollisionEditor::TileDataCollisionEditor() {
angular_velocity_editor->set_object_and_property(dummy_object, "angular_velocity");
angular_velocity_editor->set_label("angular_velocity");
angular_velocity_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
+ angular_velocity_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
+ angular_velocity_editor->set_tooltip(angular_velocity_editor->get_edited_property());
angular_velocity_editor->update_property();
add_child(angular_velocity_editor);
- property_editors["angular_velocity"] = linear_velocity_editor;
+ property_editors["angular_velocity"] = angular_velocity_editor;
_polygons_changed();
}
@@ -1548,7 +1663,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
hovered_coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_pos);
hovered_coords = p_tile_set_atlas_source->get_tile_at_coords(hovered_coords);
if (hovered_coords != TileSetSource::INVALID_ATLAS_COORDS) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(hovered_coords, 0);
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(hovered_coords);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0);
@@ -1587,7 +1702,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
for (int i = 0; i < p_tile_set_atlas_source->get_tiles_count(); i++) {
Vector2i coords = p_tile_set_atlas_source->get_tile_id(i);
if (coords != hovered_coords) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
if (tile_data->get_terrain_set() != int(dummy_object->get("terrain_set"))) {
// Dimming
p_canvas_item->draw_set_transform_matrix(p_transform);
@@ -1607,7 +1722,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
text = "-";
}
Vector2 string_size = font->get_string_size(text, font_size);
- p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1));
+ p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1));
}
}
}
@@ -1661,7 +1776,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
Vector2i coords = Vector2i(x, y);
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
if (tile_data->get_terrain_set() == terrain_set) {
TileMapCell cell;
cell.source_id = 0;
@@ -1722,7 +1837,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
hovered_coords = Vector2i(hovered.x, hovered.y);
hovered_alternative = hovered.z;
if (hovered_coords != TileSetSource::INVALID_ATLAS_COORDS) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, hovered_alternative));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(hovered_coords, hovered_alternative);
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(hovered_coords, hovered_alternative);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative);
@@ -1763,7 +1878,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
for (int j = 1; j < p_tile_set_atlas_source->get_alternative_tiles_count(coords); j++) {
int alternative_tile = p_tile_set_atlas_source->get_alternative_tile_id(coords, j);
if (coords != hovered_coords || alternative_tile != hovered_alternative) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, alternative_tile);
if (tile_data->get_terrain_set() != int(dummy_object->get("terrain_set"))) {
// Dimming
p_canvas_item->draw_set_transform_matrix(p_transform);
@@ -1783,7 +1898,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
text = "-";
}
Vector2 string_size = font->get_string_size(text, font_size);
- p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1));
+ p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color, 1, Color(0, 0, 0, 1));
}
}
}
@@ -1807,7 +1922,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
cell.alternative_tile = 0;
// Save the old terrain_set and terrains bits.
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
if (!drag_modified.has(cell)) {
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
@@ -1837,7 +1952,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
cell.set_atlas_coords(coords);
cell.alternative_tile = 0;
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
if (tile_data->get_terrain_set() == terrain_set) {
// Save the old terrain_set and terrains bits.
if (!drag_modified.has(cell)) {
@@ -1873,13 +1988,13 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (picker_button->is_pressed()) {
Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
@@ -1903,7 +2018,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
TileData *tile_data = nullptr;
if (coords != TileSetAtlasSource::INVALID_ATLAS_COORDS) {
- tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
}
int terrain_set = int(dummy_object->get("terrain_set"));
int terrain = int(dummy_object->get("terrain"));
@@ -1942,7 +2057,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
}
drag_last_pos = mb->get_position();
}
- } else if (tile_data && tile_data->get_terrain_set() == terrain_set) {
+ } else if (tile_data->get_terrain_set() == terrain_set) {
if (mb->is_ctrl_pressed()) {
// Paint terrain set with rect.
drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS_RECT;
@@ -2020,7 +2135,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
undo_redo->create_action(TTR("Painting Terrain Set"));
for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) {
Vector2i coords = E->get().get_atlas_coords();
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->get().alternative_tile), tile_data->get_terrain_set());
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->get().alternative_tile), drag_painted_value);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
@@ -2086,7 +2201,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Vector2i coords = Vector2i(x, y);
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
if (tile_data->get_terrain_set() == terrain_set) {
TileMapCell cell;
cell.source_id = 0;
@@ -2107,7 +2222,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
undo_redo->create_action(TTR("Painting Terrain"));
for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) {
Vector2i coords = E->get().get_atlas_coords();
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
@@ -2148,7 +2263,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
cell.source_id = 0;
cell.set_atlas_coords(coords);
cell.alternative_tile = alternative_tile;
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, alternative_tile);
if (!drag_modified.has(cell)) {
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
@@ -2180,7 +2295,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
cell.alternative_tile = alternative_tile;
// Save the old terrain_set and terrains bits.
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, alternative_tile);
if (tile_data->get_terrain_set() == terrain_set) {
if (!drag_modified.has(cell)) {
Dictionary dict;
@@ -2214,7 +2329,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (picker_button->is_pressed()) {
Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position());
@@ -2222,7 +2337,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
int alternative_tile = tile.z;
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, alternative_tile);
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
@@ -2249,7 +2364,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
Vector2i coords = Vector2i(tile.x, tile.y);
int alternative_tile = tile.z;
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, alternative_tile);
if (terrain_set == -1 || !tile_data || tile_data->get_terrain_set() != terrain_set) {
drag_type = DRAG_TYPE_PAINT_TERRAIN_SET;
@@ -2272,7 +2387,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
tile_data->set_terrain_set(drag_painted_value);
}
drag_last_pos = mb->get_position();
- } else if (tile_data && tile_data->get_terrain_set() == terrain_set) {
+ } else if (tile_data->get_terrain_set() == terrain_set) {
// Paint terrain bits.
drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS;
drag_modified.clear();
@@ -2366,15 +2481,15 @@ void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform
void TileDataTerrainsEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
picker_button->set_icon(get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
- break;
- default:
- break;
+ } break;
}
}
TileDataTerrainsEditor::TileDataTerrainsEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
label = memnew(Label);
label->set_text("Painting:");
add_child(label);
@@ -2385,7 +2500,7 @@ TileDataTerrainsEditor::TileDataTerrainsEditor() {
picker_button = memnew(Button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P));
toolbar->add_child(picker_button);
// Setup
@@ -2399,6 +2514,7 @@ TileDataTerrainsEditor::TileDataTerrainsEditor() {
terrain_set_property_editor->set_object_and_property(dummy_object, "terrain_set");
terrain_set_property_editor->set_label("Terrain Set");
terrain_set_property_editor->connect("property_changed", callable_mp(this, &TileDataTerrainsEditor::_property_value_changed).unbind(1));
+ terrain_set_property_editor->set_tooltip(terrain_set_property_editor->get_edited_property());
add_child(terrain_set_property_editor);
terrain_property_editor = memnew(EditorPropertyEnum);
@@ -2427,7 +2543,7 @@ Variant TileDataNavigationEditor::_get_painted_value() {
}
void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer);
@@ -2441,7 +2557,7 @@ void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set
}
void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
Ref<NavigationPolygon> navigation_polygon = p_value;
tile_data->set_navigation_polygon(navigation_layer, navigation_polygon);
@@ -2450,7 +2566,7 @@ void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_s
}
Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
- TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile));
+ TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND_V(!tile_data, Variant());
return tile_data->get_navigation_polygon(navigation_layer);
}
@@ -2469,15 +2585,15 @@ void TileDataNavigationEditor::_tile_set_changed() {
void TileDataNavigationEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_ENTER_TREE: {
polygon_editor->set_polygons_color(get_tree()->get_debug_navigation_color());
- break;
- default:
- break;
+ } break;
}
}
TileDataNavigationEditor::TileDataNavigationEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
polygon_editor = memnew(GenericTilePolygonEditor);
polygon_editor->set_multiple_polygon_mode(true);
add_child(polygon_editor);
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index acb4c5882d..2c849637f0 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,9 +33,7 @@
#include "tile_atlas_view.h"
-#include "editor/editor_node.h"
#include "editor/editor_properties.h"
-
#include "scene/2d/tile_map.h"
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
@@ -94,7 +92,8 @@ private:
LocalVector<Vector<Point2>> polygons;
bool multiple_polygon_mode = false;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ bool use_undo_redo = true;
+ UndoRedo *editor_undo_redo = nullptr;
// UI
int hovered_polygon_index = -1;
@@ -108,34 +107,34 @@ private:
DRAG_TYPE_CREATE_POINT,
DRAG_TYPE_PAN,
};
- DragType drag_type;
- int drag_polygon_index;
- int drag_point_index;
+ DragType drag_type = DRAG_TYPE_NONE;
+ int drag_polygon_index = 0;
+ int drag_point_index = 0;
Vector2 drag_last_pos;
PackedVector2Array drag_old_polygon;
- HBoxContainer *toolbar;
+ HBoxContainer *toolbar = nullptr;
Ref<ButtonGroup> tools_button_group;
- Button *button_create;
- Button *button_edit;
- Button *button_delete;
- Button *button_pixel_snap;
- MenuButton *button_advanced_menu;
+ Button *button_create = nullptr;
+ Button *button_edit = nullptr;
+ Button *button_delete = nullptr;
+ Button *button_pixel_snap = nullptr;
+ MenuButton *button_advanced_menu = nullptr;
Vector<Point2> in_creation_polygon;
- Panel *panel;
- Control *base_control;
- EditorZoomWidget *editor_zoom_widget;
- Button *button_center_view;
+ Panel *panel = nullptr;
+ Control *base_control = nullptr;
+ EditorZoomWidget *editor_zoom_widget = nullptr;
+ Button *button_center_view = nullptr;
Vector2 panning;
Ref<Texture2D> background_texture;
Rect2 background_region;
Vector2 background_offset;
- bool background_h_flip;
- bool background_v_flip;
- bool background_transpose;
+ bool background_h_flip = false;
+ bool background_v_flip = false;
+ bool background_transpose = false;
Color background_modulate;
Color polygon_color = Color(1.0, 0.0, 0.0);
@@ -143,6 +142,10 @@ private:
enum AdvancedMenuOption {
RESET_TO_DEFAULT_TILE,
CLEAR_TILE,
+ ROTATE_RIGHT,
+ ROTATE_LEFT,
+ FLIP_HORIZONTALLY,
+ FLIP_VERTICALLY,
};
void _base_control_draw();
@@ -161,6 +164,8 @@ protected:
static void _bind_methods();
public:
+ void set_use_undo_redo(bool p_use_undo_redo);
+
void set_tile_set(Ref<TileSet> p_tile_set);
void set_background(Ref<Texture2D> p_texture, Rect2 p_region = Rect2(), Vector2 p_offset = Vector2(), bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, Color p_modulate = Color(1.0, 1.0, 1.0, 0.0));
@@ -183,12 +188,12 @@ class TileDataDefaultEditor : public TileDataEditor {
private:
// Toolbar
HBoxContainer *toolbar = memnew(HBoxContainer);
- Button *picker_button;
+ Button *picker_button = nullptr;
// UI
Ref<Texture2D> tile_bool_checked;
Ref<Texture2D> tile_bool_unchecked;
- Label *label;
+ Label *label = nullptr;
EditorProperty *property_editor = nullptr;
@@ -209,7 +214,7 @@ private:
protected:
DummyObject *dummy_object = memnew(DummyObject);
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
StringName type;
String property;
@@ -263,7 +268,7 @@ private:
int occlusion_layer = -1;
// UI
- GenericTilePolygonEditor *polygon_editor;
+ GenericTilePolygonEditor *polygon_editor = nullptr;
void _polygon_changed(PackedVector2Array p_polygon);
@@ -274,7 +279,7 @@ private:
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
virtual void _tile_set_changed() override;
@@ -294,11 +299,12 @@ class TileDataCollisionEditor : public TileDataDefaultEditor {
int physics_layer = -1;
// UI
- GenericTilePolygonEditor *polygon_editor;
+ GenericTilePolygonEditor *polygon_editor = nullptr;
DummyObject *dummy_object = memnew(DummyObject);
Map<StringName, EditorProperty *> property_editors;
void _property_value_changed(StringName p_property, Variant p_value, StringName p_field);
+ void _property_selected(StringName p_path, int p_focusable);
void _polygons_changed();
virtual Variant _get_painted_value() override;
@@ -308,7 +314,7 @@ class TileDataCollisionEditor : public TileDataDefaultEditor {
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
virtual void _tile_set_changed() override;
@@ -329,7 +335,7 @@ class TileDataTerrainsEditor : public TileDataEditor {
private:
// Toolbar
HBoxContainer *toolbar = memnew(HBoxContainer);
- Button *picker_button;
+ Button *picker_button = nullptr;
// Painting state.
enum DragType {
@@ -346,7 +352,7 @@ private:
Variant drag_painted_value;
// UI
- Label *label;
+ Label *label = nullptr;
DummyObject *dummy_object = memnew(DummyObject);
EditorPropertyEnum *terrain_set_property_editor = nullptr;
EditorPropertyEnum *terrain_property_editor = nullptr;
@@ -360,7 +366,7 @@ protected:
void _notification(int p_what);
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
public:
virtual Control *get_toolbar() override { return toolbar; };
@@ -382,7 +388,7 @@ private:
PackedVector2Array navigation_polygon;
// UI
- GenericTilePolygonEditor *polygon_editor;
+ GenericTilePolygonEditor *polygon_editor = nullptr;
void _polygon_changed(PackedVector2Array p_polygon);
@@ -393,7 +399,7 @@ private:
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
virtual void _tile_set_changed() override;
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 39fbd86f77..ba87eba9e0 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -32,6 +32,7 @@
#include "tiles_editor_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
@@ -75,7 +76,7 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
picker_button->show();
erase_button->show();
tools_settings_vsep_2->show();
- random_tile_checkbox->show();
+ random_tile_toggle->show();
scatter_label->show();
scatter_spinbox->show();
} else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
@@ -83,7 +84,7 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
picker_button->show();
erase_button->show();
tools_settings_vsep_2->show();
- random_tile_checkbox->show();
+ random_tile_toggle->show();
scatter_label->show();
scatter_spinbox->show();
} else if (tool_buttons_group->get_pressed_button() == rect_tool_button) {
@@ -91,7 +92,7 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
picker_button->show();
erase_button->show();
tools_settings_vsep_2->show();
- random_tile_checkbox->show();
+ random_tile_toggle->show();
scatter_label->show();
scatter_spinbox->show();
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
@@ -100,7 +101,7 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
erase_button->show();
tools_settings_vsep_2->show();
bucket_contiguous_checkbox->show();
- random_tile_checkbox->show();
+ random_tile_toggle->show();
scatter_label->show();
scatter_spinbox->show();
}
@@ -124,6 +125,10 @@ void TileMapEditorTilesPlugin::_tab_changed() {
void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
// Update the sources.
int old_current = sources_list->get_current();
+ int old_source = -1;
+ if (old_current > -1) {
+ old_source = sources_list->get_item_metadata(old_current);
+ }
sources_list->clear();
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
@@ -136,9 +141,12 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
return;
}
- for (int i = 0; i < tile_set->get_source_count(); i++) {
- int source_id = tile_set->get_source_id(i);
+ if (!tile_set->has_source(old_source)) {
+ old_source = -1;
+ }
+ List<int> source_ids = TilesEditorPlugin::get_singleton()->get_sorted_sources(tile_set);
+ for (const int &source_id : source_ids) {
TileSetSource *source = *tile_set->get_source(source_id);
Ref<Texture2D> texture;
@@ -157,7 +165,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
if (texture.is_valid()) {
item_text = vformat("%s (ID: %d)", texture->get_path().get_file(), source_id);
} else {
- item_text = vformat("No Texture Atlas Source (ID: %d)", source_id);
+ item_text = vformat(TTR("No Texture Atlas Source (ID: %d)"), source_id);
}
}
}
@@ -180,20 +188,25 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
}
sources_list->add_item(item_text, texture);
- sources_list->set_item_metadata(i, source_id);
+ sources_list->set_item_metadata(-1, source_id);
}
if (sources_list->get_item_count() > 0) {
- if (old_current > 0) {
- // Keep the current selected item if needed.
- sources_list->set_current(CLAMP(old_current, 0, sources_list->get_item_count() - 1));
+ if (old_source >= 0) {
+ for (int i = 0; i < sources_list->get_item_count(); i++) {
+ if ((int)sources_list->get_item_metadata(i) == old_source) {
+ sources_list->set_current(i);
+ sources_list->ensure_current_is_visible();
+ break;
+ }
+ }
} else {
sources_list->set_current(0);
}
sources_list->emit_signal(SNAME("item_selected"), sources_list->get_current());
}
- // Synchronize
+ // Synchronize the lists.
TilesEditorPlugin::get_singleton()->set_sources_lists_current(sources_list->get_current());
}
@@ -415,7 +428,7 @@ void TileMapEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_s
TileMapCell selected = TileMapCell(source_id, Vector2i(), scene_id);
// Clear the selection if shift is not pressed.
- if (!Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (!Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
tile_set_selection.clear();
}
@@ -439,6 +452,7 @@ void TileMapEditorTilesPlugin::_scenes_list_nothing_selected() {
}
void TileMapEditorTilesPlugin::_update_theme() {
+ source_sort_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Sort"), SNAME("EditorIcons")));
select_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
paint_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
line_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
@@ -447,6 +461,7 @@ void TileMapEditorTilesPlugin::_update_theme() {
picker_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
erase_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
+ random_tile_toggle->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("RandomNumberGenerator"), SNAME("EditorIcons")));
missing_atlas_texture_icon = tiles_bottom_panel->get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons"));
}
@@ -590,15 +605,18 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(mb->get_position());
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed()) {
// Pressed
- if (erase_button->is_pressed() || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (erase_button->is_pressed() || mb->get_button_index() == MouseButton::RIGHT) {
drag_erasing = true;
}
if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
- // Do nothing.
+ // Cancel tile pasting on right-click
+ if (mb->get_button_index() == MouseButton::RIGHT) {
+ drag_type = DRAG_TYPE_NONE;
+ }
} else if (tool_buttons_group->get_pressed_button() == select_tool_button) {
drag_start_mouse_pos = mpos;
if (tile_map_selection.has(tile_map->world_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) {
@@ -617,12 +635,12 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
} else {
// Check if we are picking a tile.
- if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
drag_type = DRAG_TYPE_PICK;
drag_start_mouse_pos = mpos;
} else {
// Paint otherwise.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
drag_type = DRAG_TYPE_PAINT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
@@ -638,11 +656,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
_fix_invalid_tiles_in_tile_map_selection();
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && !Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) {
drag_type = DRAG_TYPE_LINE;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) {
drag_type = DRAG_TYPE_RECT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
@@ -713,7 +731,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the selection.
if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && tool_buttons_group->get_pressed_button() == select_tool_button) {
// In select mode, we only draw the current selection if we are modifying it (pressing control or shift).
- if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
// Do nothing
} else {
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
@@ -783,7 +801,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i]));
}
- } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single pattern.
@@ -832,9 +850,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Fade out the border of the grid.
float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
- float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f);
+ float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)(pos_in_rect.x + 1)), 0.0f, 1.0f);
float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
- float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
+ float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)(pos_in_rect.y + 1)), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
@@ -853,7 +871,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Transform2D tile_xform;
tile_xform.set_origin(tile_map->map_to_world(E.key));
tile_xform.set_scale(tile_set->get_tile_size());
- if (!(drag_erasing || erase_button->is_pressed()) && random_tile_checkbox->is_pressed()) {
+ if (!(drag_erasing || erase_button->is_pressed()) && random_tile_toggle->is_pressed()) {
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} else {
if (tile_set->has_source(E.value.source_id)) {
@@ -861,7 +879,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
// Get tile data.
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E.value.get_atlas_coords(), E.value.alternative_tile));
+ TileData *tile_data = atlas_source->get_tile_data(E.value.get_atlas_coords(), E.value.alternative_tile);
// Compute the offset
Rect2i source_rect = atlas_source->get_tile_texture_region(E.value.get_atlas_coords());
@@ -933,7 +951,7 @@ TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pa
TileSetSource *source = *tile_set->get_source(source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(atlas_coords, alternative_tile));
+ TileData *tile_data = atlas_source->get_tile_data(atlas_coords, alternative_tile);
ERR_FAIL_COND_V(!tile_data, TileMapCell());
sum += tile_data->get_probability();
} else {
@@ -952,7 +970,7 @@ TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pa
TileSetSource *source = *tile_set->get_source(source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
- current += Object::cast_to<TileData>(atlas_source->get_tile_data(atlas_coords, alternative_tile))->get_probability();
+ current += atlas_source->get_tile_data(atlas_coords, alternative_tile)->get_probability();
} else {
current += 1.0;
}
@@ -984,7 +1002,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_
Map<Vector2i, TileMapCell> output;
if (!pattern->is_empty()) {
// Paint the tiles on the tile map.
- if (!p_erase && random_tile_checkbox->is_pressed()) {
+ if (!p_erase && random_tile_toggle->is_pressed()) {
// Paint a random tile.
Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(p_from_mouse_pos), tile_map->world_to_map(p_to_mouse_pos));
for (int i = 0; i < line.size(); i++) {
@@ -1044,7 +1062,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
Map<Vector2i, TileMapCell> output;
if (!pattern->is_empty()) {
- if (!p_erase && random_tile_checkbox->is_pressed()) {
+ if (!p_erase && random_tile_toggle->is_pressed()) {
// Paint a random tile.
for (int x = 0; x < rect.size.x; x++) {
for (int y = 0; y < rect.size.y; y++) {
@@ -1117,7 +1135,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
source_cell.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
source_cell.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
(source_cell.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
- if (!p_erase && random_tile_checkbox->is_pressed()) {
+ if (!p_erase && random_tile_toggle->is_pressed()) {
// Paint a random tile.
output.insert(coords, _pick_random_tile(pattern));
} else {
@@ -1163,7 +1181,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
source_cell.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
source_cell.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
(source_cell.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
- if (!p_erase && random_tile_checkbox->is_pressed()) {
+ if (!p_erase && random_tile_toggle->is_pressed()) {
// Paint a random tile.
output.insert(coords, _pick_random_tile(pattern));
} else {
@@ -1212,14 +1230,14 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->create_action(TTR("Change selection"));
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
- if (!Input::get_singleton()->is_key_pressed(KEY_SHIFT) && !Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
tile_map_selection.clear();
}
Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
for (int x = rect.position.x; x <= rect.get_end().x; x++) {
for (int y = rect.position.y; y <= rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
- if (Input::get_singleton()->is_key_pressed(KEY_CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
if (tile_map_selection.has(coords)) {
tile_map_selection.erase(coords);
}
@@ -1311,15 +1329,35 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
+ int picked_source = -1;
TypedArray<Vector2i> coords_array;
for (int x = rect.position.x; x < rect.get_end().x; x++) {
for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
- if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
+
+ int source = tile_map->get_cell_source_id(tile_map_layer, coords);
+ if (source != TileSet::INVALID_SOURCE) {
coords_array.push_back(coords);
+ if (picked_source == -1) {
+ picked_source = source;
+ } else if (picked_source != source) {
+ picked_source = -2;
+ }
}
}
}
+
+ if (picked_source >= 0) {
+ for (int i = 0; i < sources_list->get_item_count(); i++) {
+ if (int(sources_list->get_item_metadata(i)) == picked_source) {
+ sources_list->set_current(i);
+ break;
+ }
+ }
+ sources_list->ensure_current_is_visible();
+ TilesEditorPlugin::get_singleton()->set_sources_lists_current(picked_source);
+ }
+
Ref<TileMapPattern> new_selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
if (!new_selection_pattern->is_empty()) {
selection_pattern = new_selection_pattern;
@@ -1734,7 +1772,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) { // Pressed
tile_set_dragging_selection = true;
tile_set_drag_start_mouse_pos = tile_atlas_control->get_local_mouse_position();
@@ -1892,7 +1930,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) { // Pressed
// Left click pressed.
if (!mb->is_shift_pressed()) {
@@ -1947,6 +1985,14 @@ void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer
tile_map_layer = p_tile_map_layer;
}
+void TileMapEditorTilesPlugin::_set_source_sort(int p_sort) {
+ for (int i = 0; i != TilesEditorPlugin::SOURCE_SORT_MAX; i++) {
+ source_sort_button->get_popup()->set_item_checked(i, (i == (int)p_sort));
+ }
+ TilesEditorPlugin::get_singleton()->set_sorting_option(p_sort);
+ _update_tile_set_sources_list();
+}
+
void TileMapEditorTilesPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileMapEditorTilesPlugin::_scene_thumbnail_done);
ClassDB::bind_method(D_METHOD("_set_tile_map_selection", "selection"), &TileMapEditorTilesPlugin::_set_tile_map_selection);
@@ -1954,14 +2000,18 @@ void TileMapEditorTilesPlugin::_bind_methods() {
}
TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
- CanvasItemEditor::get_singleton()->get_viewport_control()->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_mouse_exited_viewport));
+ undo_redo = EditorNode::get_undo_redo();
+
+ CanvasItemEditor::get_singleton()
+ ->get_viewport_control()
+ ->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_mouse_exited_viewport));
// --- Shortcuts ---
- ED_SHORTCUT("tiles_editor/cut", TTR("Cut"), KEY_MASK_CMD | KEY_X);
- ED_SHORTCUT("tiles_editor/copy", TTR("Copy"), KEY_MASK_CMD | KEY_C);
- ED_SHORTCUT("tiles_editor/paste", TTR("Paste"), KEY_MASK_CMD | KEY_V);
- ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), KEY_ESCAPE);
- ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), KEY_DELETE);
+ ED_SHORTCUT("tiles_editor/cut", TTR("Cut"), KeyModifierMask::CMD | Key::X);
+ ED_SHORTCUT("tiles_editor/copy", TTR("Copy"), KeyModifierMask::CMD | Key::C);
+ ED_SHORTCUT("tiles_editor/paste", TTR("Paste"), KeyModifierMask::CMD | Key::V);
+ ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), Key::ESCAPE);
+ ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE);
// --- Initialize references ---
tile_map_clipboard.instantiate();
@@ -1979,7 +2029,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
select_tool_button->set_flat(true);
select_tool_button->set_toggle_mode(true);
select_tool_button->set_button_group(tool_buttons_group);
- select_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/selection_tool", "Selection", KEY_S));
+ select_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/selection_tool", "Selection", Key::S));
select_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(select_tool_button);
@@ -1987,7 +2037,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
paint_tool_button->set_flat(true);
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
- paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_D));
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", Key::D));
paint_tool_button->set_tooltip(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle."));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -1996,7 +2046,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
line_tool_button->set_flat(true);
line_tool_button->set_toggle_mode(true);
line_tool_button->set_button_group(tool_buttons_group);
- line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", KEY_L));
+ line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", Key::L));
line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(line_tool_button);
@@ -2004,7 +2054,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
rect_tool_button->set_flat(true);
rect_tool_button->set_toggle_mode(true);
rect_tool_button->set_button_group(tool_buttons_group);
- rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", KEY_R));
+ rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", Key::R));
rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(rect_tool_button);
@@ -2012,7 +2062,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
bucket_tool_button->set_flat(true);
bucket_tool_button->set_toggle_mode(true);
bucket_tool_button->set_button_group(tool_buttons_group);
- bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", KEY_B));
+ bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", Key::B));
bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
toolbar->add_child(tilemap_tiles_tools_buttons);
@@ -2028,7 +2078,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
picker_button = memnew(Button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P));
picker_button->set_tooltip(TTR("Alternatively hold Ctrl with other tools to pick tile."));
picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
@@ -2037,7 +2087,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
erase_button = memnew(Button);
erase_button->set_flat(true);
erase_button->set_toggle_mode(true);
- erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
+ erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E));
erase_button->set_tooltip(TTR("Alternatively use RMB to erase tiles."));
erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
@@ -2054,11 +2104,12 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
tools_settings->add_child(bucket_contiguous_checkbox);
// Random tile checkbox.
- random_tile_checkbox = memnew(CheckBox);
- random_tile_checkbox->set_flat(true);
- random_tile_checkbox->set_text(TTR("Place Random Tile"));
- random_tile_checkbox->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled));
- tools_settings->add_child(random_tile_checkbox);
+ random_tile_toggle = memnew(Button);
+ random_tile_toggle->set_flat(true);
+ random_tile_toggle->set_toggle_mode(true);
+ random_tile_toggle->set_tooltip(TTR("Place Random Tile"));
+ random_tile_toggle->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled));
+ tools_settings->add_child(random_tile_toggle);
// Random tile scattering.
scatter_label = memnew(Label);
@@ -2093,8 +2144,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
missing_source_label->set_text(TTR("This TileMap's TileSet has no source configured. Edit the TileSet resource to add one."));
missing_source_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
missing_source_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- missing_source_label->set_align(Label::ALIGN_CENTER);
- missing_source_label->set_valign(Label::VALIGN_CENTER);
+ missing_source_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ missing_source_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
missing_source_label->hide();
tiles_bottom_panel->add_child(missing_source_label);
@@ -2103,17 +2154,44 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
atlas_sources_split_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tiles_bottom_panel->add_child(atlas_sources_split_container);
+ VBoxContainer *split_container_left_side = memnew(VBoxContainer);
+ split_container_left_side->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ split_container_left_side->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ split_container_left_side->set_stretch_ratio(0.25);
+ split_container_left_side->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
+ atlas_sources_split_container->add_child(split_container_left_side);
+
+ HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);
+ sources_bottom_actions->set_alignment(HBoxContainer::ALIGNMENT_END);
+
+ source_sort_button = memnew(MenuButton);
+ source_sort_button->set_flat(true);
+ source_sort_button->set_tooltip(TTR("Sort sources"));
+
+ PopupMenu *p = source_sort_button->get_popup();
+ p->connect("id_pressed", callable_mp(this, &TileMapEditorTilesPlugin::_set_source_sort));
+ p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorPlugin::SOURCE_SORT_ID);
+ p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorPlugin::SOURCE_SORT_ID_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorPlugin::SOURCE_SORT_NAME);
+ p->add_radio_check_item(TTR("Sort by Name (Descending)"), TilesEditorPlugin::SOURCE_SORT_NAME_REVERSE);
+ p->set_item_checked(TilesEditorPlugin::SOURCE_SORT_ID, true);
+ sources_bottom_actions->add_child(source_sort_button);
+
sources_list = memnew(ItemList);
sources_list->set_fixed_icon_size(Size2i(60, 60) * EDSCALE);
sources_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ sources_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
sources_list->set_stretch_ratio(0.25);
sources_list->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_fix_selected_and_hovered).unbind(1));
sources_list->connect("item_selected", callable_mp(this, &TileMapEditorTilesPlugin::_update_source_display).unbind(1));
sources_list->connect("item_selected", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_sources_lists_current));
- sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list), varray(sources_list));
- atlas_sources_split_container->add_child(sources_list);
+ sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list), varray(sources_list, source_sort_button));
+ sources_list->add_user_signal(MethodInfo("sort_request"));
+ sources_list->connect("sort_request", callable_mp(this, &TileMapEditorTilesPlugin::_update_tile_set_sources_list));
+ split_container_left_side->add_child(sources_list);
+ split_container_left_side->add_child(sources_bottom_actions);
// Tile atlas source.
tile_atlas_view = memnew(TileAtlasView);
@@ -2152,8 +2230,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
invalid_source_label->set_text(TTR("Invalid source selected."));
invalid_source_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
invalid_source_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- invalid_source_label->set_align(Label::ALIGN_CENTER);
- invalid_source_label->set_valign(Label::VALIGN_CENTER);
+ invalid_source_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ invalid_source_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
invalid_source_label->hide();
atlas_sources_split_container->add_child(invalid_source_label);
@@ -2286,7 +2364,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const Map
bool to_replace_modified = true;
while (to_replace_modified) {
// Get the constraints from the removed cells.
- removed_cells_constraints_set = tile_map->get_terrain_constraints_from_removed_cells_list(tile_map_layer, to_replace, p_terrain_set);
+ removed_cells_constraints_set = tile_map->get_terrain_constraints_from_removed_cells_list(tile_map_layer, to_replace, p_terrain_set, false);
// Filter the sources to make sure they are in the potential_to_replace.
Map<TileMap::TerrainConstraint, Set<Vector2i>> per_constraint_tiles;
@@ -2424,7 +2502,7 @@ Set<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p
Ref<TileSetSource> source = tile_set->get_source(source_cell.source_id);
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(source_cell.get_atlas_coords(), source_cell.alternative_tile));
+ tile_data = atlas_source->get_tile_data(source_cell.get_atlas_coords(), source_cell.alternative_tile);
}
if (!tile_data) {
return Set<Vector2i>();
@@ -2455,7 +2533,7 @@ Set<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p
Ref<TileSetSource> source = tile_set->get_source(tile_map->get_cell_source_id(tile_map_layer, coords));
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)));
+ tile_data = atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
}
if (tile_data) {
candidate_pattern = tile_data->get_terrains_pattern();
@@ -2500,7 +2578,7 @@ Set<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p
Ref<TileSetSource> source = tile_set->get_source(tile_map->get_cell_source_id(tile_map_layer, coords));
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)));
+ tile_data = atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
}
if (tile_data) {
candidate_pattern = tile_data->get_terrains_pattern();
@@ -2566,7 +2644,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile));
+ tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
}
if (tile_data) {
@@ -2766,10 +2844,10 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(mb->get_position());
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed()) {
// Pressed
- if (erase_button->is_pressed() || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (erase_button->is_pressed() || mb->get_button_index() == MouseButton::RIGHT) {
drag_erasing = true;
}
@@ -2777,7 +2855,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_type = DRAG_TYPE_PICK;
} else {
// Paint otherwise.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
return true;
}
@@ -2792,14 +2870,14 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && !Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) {
if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
return true;
}
drag_type = DRAG_TYPE_LINE;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) {
if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
return true;
}
@@ -2884,7 +2962,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
}
- } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single tile.
@@ -2945,9 +3023,9 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
// Fade out the border of the grid.
float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
- float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f);
+ float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)(pos_in_rect.x + 1)), 0.0f, 1.0f);
float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
- float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
+ float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)(pos_in_rect.y + 1)), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
@@ -3007,7 +3085,7 @@ void TileMapEditorTerrainsPlugin::_update_terrains_cache() {
for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) {
int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index);
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_id, alternative_id));
+ TileData *tile_data = atlas_source->get_tile_data(tile_id, alternative_id);
int terrain_set = tile_data->get_terrain_set();
if (terrain_set >= 0) {
ERR_FAIL_INDEX(terrain_set, (int)per_terrain_terrains_patterns.size());
@@ -3135,7 +3213,7 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
Ref<TileSetAtlasSource> atlas_source = source;
if (atlas_source.is_valid()) {
- TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile));
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
if (tile_data->get_probability() > max_probability) {
icon = atlas_source->get_texture();
region = atlas_source->get_tile_texture_region(cell.get_atlas_coords());
@@ -3191,6 +3269,8 @@ void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_la
}
TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
+ undo_redo = EditorNode::get_undo_redo();
+
main_vbox_container = memnew(VBoxContainer);
main_vbox_container->connect("tree_entered", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
@@ -3230,7 +3310,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
paint_tool_button->set_pressed(true);
- paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_D));
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", Key::D));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -3238,7 +3318,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
line_tool_button->set_flat(true);
line_tool_button->set_toggle_mode(true);
line_tool_button->set_button_group(tool_buttons_group);
- line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", KEY_L));
+ line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", Key::L));
line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(line_tool_button);
@@ -3246,7 +3326,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
rect_tool_button->set_flat(true);
rect_tool_button->set_toggle_mode(true);
rect_tool_button->set_button_group(tool_buttons_group);
- rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", KEY_R));
+ rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", Key::R));
rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(rect_tool_button);
@@ -3254,7 +3334,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
bucket_tool_button->set_flat(true);
bucket_tool_button->set_toggle_mode(true);
bucket_tool_button->set_button_group(tool_buttons_group);
- bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", KEY_B));
+ bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", Key::B));
bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
@@ -3271,7 +3351,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
picker_button = memnew(Button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P));
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P));
picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
@@ -3279,7 +3359,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
erase_button = memnew(Button);
erase_button->set_flat(true);
erase_button->set_toggle_mode(true);
- erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
+ erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E));
erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
@@ -3301,15 +3381,16 @@ TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() {
void TileMapEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
missing_tile_texture = get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
warning_pattern_texture = get_theme_icon(SNAME("WarningPattern"), SNAME("EditorIcons"));
advanced_menu_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
toggle_grid_button->set_icon(get_theme_icon(SNAME("Grid"), SNAME("EditorIcons")));
toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
toogle_highlight_selected_layer_button->set_icon(get_theme_icon(SNAME("TileMapHighlightSelected"), SNAME("EditorIcons")));
- break;
- case NOTIFICATION_INTERNAL_PROCESS:
+ } break;
+
+ case NOTIFICATION_INTERNAL_PROCESS: {
if (is_visible_in_tree() && tileset_changed_needs_update) {
_update_bottom_panel();
_update_layers_selection();
@@ -3317,11 +3398,13 @@ void TileMapEditor::_notification(int p_what) {
CanvasItemEditor::get_singleton()->update_viewport();
tileset_changed_needs_update = false;
}
- break;
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED:
+ } break;
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
- break;
- case NOTIFICATION_VISIBILITY_CHANGED:
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (tile_map) {
if (is_visible_in_tree()) {
@@ -3330,7 +3413,7 @@ void TileMapEditor::_notification(int p_what) {
tile_map->set_selected_layer(-1);
}
}
- break;
+ } break;
}
}
@@ -3684,7 +3767,7 @@ void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_
String str = pi.name.trim_prefix(p_array_prefix);
int to_char_index = 0;
while (to_char_index < str.length()) {
- if (str[to_char_index] < '0' || str[to_char_index] > '9') {
+ if (!is_digit(str[to_char_index])) {
break;
}
to_char_index++;
@@ -3783,7 +3866,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
// Draw the warning icon.
- int min_axis = missing_tile_texture->get_size().min_axis();
+ Vector2::Axis min_axis = missing_tile_texture->get_size().min_axis_index();
Vector2 icon_size;
icon_size[min_axis] = tile_set->get_tile_size()[min_axis] / 3;
icon_size[(min_axis + 1) % 2] = (icon_size[min_axis] * missing_tile_texture->get_size()[(min_axis + 1) % 2] / missing_tile_texture->get_size()[min_axis]);
@@ -3830,9 +3913,9 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
// Fade out the border of the grid.
float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
- float right_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.x, (float)(displayed_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f);
+ float right_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.x, (float)(displayed_rect.size.x - fading), (float)(pos_in_rect.x + 1)), 0.0f, 1.0f);
float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
- float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
+ float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)(pos_in_rect.y + 1)), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
@@ -3894,11 +3977,13 @@ void TileMapEditor::edit(TileMap *p_tile_map) {
}
TileMapEditor::TileMapEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
set_process_internal(true);
// Shortcuts.
- ED_SHORTCUT("tiles_editor/select_next_layer", TTR("Select Next Tile Map Layer"), KEY_PAGEUP);
- ED_SHORTCUT("tiles_editor/select_previous_layer", TTR("Select Previous Tile Map Layer"), KEY_PAGEDOWN);
+ ED_SHORTCUT("tiles_editor/select_next_layer", TTR("Select Next Tile Map Layer"), Key::PAGEUP);
+ ED_SHORTCUT("tiles_editor/select_previous_layer", TTR("Select Previous Tile Map Layer"), Key::PAGEDOWN);
// TileMap editor plugins
tile_map_editor_plugins.push_back(memnew(TileMapEditorTilesPlugin));
@@ -3906,6 +3991,7 @@ TileMapEditor::TileMapEditor() {
// TabBar.
tabs_bar = memnew(TabBar);
+ tabs_bar->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
tabs_bar->set_clip_tabs(false);
for (int plugin_index = 0; plugin_index < tile_map_editor_plugins.size(); plugin_index++) {
Vector<TileMapEditorPlugin::TabData> tabs_vector = tile_map_editor_plugins[plugin_index]->get_tabs();
@@ -3941,7 +4027,7 @@ TileMapEditor::TileMapEditor() {
// Layer selector.
layers_selection_popup = memnew(PopupMenu);
layers_selection_popup->connect("id_pressed", callable_mp(this, &TileMapEditor::_layers_selection_id_pressed));
- layers_selection_popup->set_close_on_parent_focus(false);
+ layers_selection_popup->set_flag(Window::FLAG_POPUP, false);
layers_selection_button = memnew(Button);
layers_selection_button->set_toggle_mode(true);
@@ -3981,8 +4067,8 @@ TileMapEditor::TileMapEditor() {
missing_tileset_label->set_text(TTR("The edited TileMap node has no TileSet resource."));
missing_tileset_label->set_h_size_flags(SIZE_EXPAND_FILL);
missing_tileset_label->set_v_size_flags(SIZE_EXPAND_FILL);
- missing_tileset_label->set_align(Label::ALIGN_CENTER);
- missing_tileset_label->set_valign(Label::VALIGN_CENTER);
+ missing_tileset_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ missing_tileset_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
missing_tileset_label->hide();
add_child(missing_tileset_label);
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index f462119727..ec32c83d10 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -35,16 +35,24 @@
#include "core/os/thread.h"
#include "core/typedefs.h"
-#include "editor/editor_node.h"
#include "scene/2d/tile_map.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/item_list.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/spin_box.h"
+#include "scene/gui/split_container.h"
#include "scene/gui/tab_bar.h"
+#include "scene/gui/tree.h"
+
+class UndoRedo;
class TileMapEditorPlugin : public Object {
public:
struct TabData {
- Control *toolbar;
- Control *panel;
+ Control *toolbar = nullptr;
+ Control *panel = nullptr;
};
virtual Vector<TabData> get_tabs() const {
@@ -61,33 +69,33 @@ class TileMapEditorTilesPlugin : public TileMapEditorPlugin {
GDCLASS(TileMapEditorTilesPlugin, TileMapEditorPlugin);
private:
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
ObjectID tile_map_id;
int tile_map_layer = -1;
virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
///// Toolbar /////
- HBoxContainer *toolbar;
+ HBoxContainer *toolbar = nullptr;
Ref<ButtonGroup> tool_buttons_group;
- Button *select_tool_button;
- Button *paint_tool_button;
- Button *line_tool_button;
- Button *rect_tool_button;
- Button *bucket_tool_button;
+ Button *select_tool_button = nullptr;
+ Button *paint_tool_button = nullptr;
+ Button *line_tool_button = nullptr;
+ Button *rect_tool_button = nullptr;
+ Button *bucket_tool_button = nullptr;
- HBoxContainer *tools_settings;
+ HBoxContainer *tools_settings = nullptr;
- VSeparator *tools_settings_vsep;
- Button *picker_button;
- Button *erase_button;
+ VSeparator *tools_settings_vsep = nullptr;
+ Button *picker_button = nullptr;
+ Button *erase_button = nullptr;
- VSeparator *tools_settings_vsep_2;
- CheckBox *bucket_contiguous_checkbox;
- CheckBox *random_tile_checkbox;
+ VSeparator *tools_settings_vsep_2 = nullptr;
+ CheckBox *bucket_contiguous_checkbox = nullptr;
+ Button *random_tile_toggle = nullptr;
float scattering = 0.0;
- Label *scatter_label;
- SpinBox *scatter_spinbox;
+ Label *scatter_label = nullptr;
+ SpinBox *scatter_spinbox = nullptr;
void _on_random_tile_checkbox_toggled(bool p_pressed);
void _on_scattering_spinbox_changed(double p_value);
@@ -140,11 +148,12 @@ private:
void _tab_changed();
///// Bottom panel tiles ////
- VBoxContainer *tiles_bottom_panel;
- Label *missing_source_label;
- Label *invalid_source_label;
+ VBoxContainer *tiles_bottom_panel = nullptr;
+ Label *missing_source_label = nullptr;
+ Label *invalid_source_label = nullptr;
- ItemList *sources_list;
+ ItemList *sources_list = nullptr;
+ MenuButton *source_sort_button = nullptr;
Ref<Texture2D> missing_atlas_texture_icon;
void _update_tile_set_sources_list();
@@ -153,26 +162,27 @@ private:
// Atlas sources.
TileMapCell hovered_tile;
- TileAtlasView *tile_atlas_view;
- HSplitContainer *atlas_sources_split_container;
+ TileAtlasView *tile_atlas_view = nullptr;
+ HSplitContainer *atlas_sources_split_container = nullptr;
bool tile_set_dragging_selection = false;
Vector2i tile_set_drag_start_mouse_pos;
- Control *tile_atlas_control;
+ Control *tile_atlas_control = nullptr;
void _tile_atlas_control_mouse_exited();
void _tile_atlas_control_gui_input(const Ref<InputEvent> &p_event);
void _tile_atlas_control_draw();
- Control *alternative_tiles_control;
+ Control *alternative_tiles_control = nullptr;
void _tile_alternatives_control_draw();
void _tile_alternatives_control_mouse_exited();
void _tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event);
void _update_atlas_view();
+ void _set_source_sort(int p_sort);
// Scenes collection sources.
- ItemList *scene_tiles_list;
+ ItemList *scene_tiles_list = nullptr;
void _update_scenes_collection_view();
void _scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud);
@@ -180,9 +190,9 @@ private:
void _scenes_list_nothing_selected();
///// Bottom panel patterns ////
- VBoxContainer *patterns_bottom_panel;
- ItemList *patterns_item_list;
- Label *patterns_help_label;
+ VBoxContainer *patterns_bottom_panel = nullptr;
+ ItemList *patterns_item_list = nullptr;
+ Label *patterns_help_label = nullptr;
void _patterns_item_list_gui_input(const Ref<InputEvent> &p_event);
void _pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture);
bool select_last_pattern = false;
@@ -210,32 +220,32 @@ class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin {
GDCLASS(TileMapEditorTerrainsPlugin, TileMapEditorPlugin);
private:
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
ObjectID tile_map_id;
int tile_map_layer = -1;
virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
// Toolbar.
- HBoxContainer *toolbar;
+ HBoxContainer *toolbar = nullptr;
Ref<ButtonGroup> tool_buttons_group;
- Button *paint_tool_button;
- Button *line_tool_button;
- Button *rect_tool_button;
- Button *bucket_tool_button;
+ Button *paint_tool_button = nullptr;
+ Button *line_tool_button = nullptr;
+ Button *rect_tool_button = nullptr;
+ Button *bucket_tool_button = nullptr;
- HBoxContainer *tools_settings;
+ HBoxContainer *tools_settings = nullptr;
- VSeparator *tools_settings_vsep;
- Button *picker_button;
- Button *erase_button;
+ VSeparator *tools_settings_vsep = nullptr;
+ Button *picker_button = nullptr;
+ Button *erase_button = nullptr;
- VSeparator *tools_settings_vsep_2;
- CheckBox *bucket_contiguous_checkbox;
+ VSeparator *tools_settings_vsep_2 = nullptr;
+ CheckBox *bucket_contiguous_checkbox = nullptr;
void _update_toolbar();
// Main vbox.
- VBoxContainer *main_vbox_container;
+ VBoxContainer *main_vbox_container = nullptr;
// TileMap editing.
bool has_mouse = false;
@@ -268,8 +278,8 @@ private:
void _update_selection();
// Bottom panel.
- Tree *terrains_tree;
- ItemList *terrains_tile_list;
+ Tree *terrains_tree = nullptr;
+ ItemList *terrains_tile_list = nullptr;
// Cache.
LocalVector<LocalVector<Set<TileSet::TerrainsPattern>>> per_terrain_terrains_patterns;
@@ -296,7 +306,7 @@ class TileMapEditor : public VBoxContainer {
GDCLASS(TileMapEditor, VBoxContainer);
private:
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
bool tileset_changed_needs_update = false;
ObjectID tile_map_id;
int tile_map_layer = -1;
@@ -305,24 +315,24 @@ private:
Vector<TileMapEditorPlugin *> tile_map_editor_plugins;
// Toolbar.
- HBoxContainer *tile_map_toolbar;
+ HBoxContainer *tile_map_toolbar = nullptr;
- PopupMenu *layers_selection_popup;
- Button *layers_selection_button;
- Button *toogle_highlight_selected_layer_button;
+ PopupMenu *layers_selection_popup = nullptr;
+ Button *layers_selection_button = nullptr;
+ Button *toogle_highlight_selected_layer_button = nullptr;
void _layers_selection_button_draw();
void _layers_selection_button_pressed();
void _layers_selection_id_pressed(int p_id);
- Button *toggle_grid_button;
+ Button *toggle_grid_button = nullptr;
void _on_grid_toggled(bool p_pressed);
- MenuButton *advanced_menu_button;
+ MenuButton *advanced_menu_button = nullptr;
void _advanced_menu_button_id_pressed(int p_id);
// Bottom panel.
- Label *missing_tileset_label;
- TabBar *tabs_bar;
+ Label *missing_tileset_label = nullptr;
+ TabBar *tabs_bar = nullptr;
LocalVector<TileMapEditorPlugin::TabData> tabs_data;
LocalVector<TileMapEditorPlugin *> tabs_plugins;
void _update_bottom_panel();
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index 9e47a44b34..62f3bd6356 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,11 +30,12 @@
#include "tile_proxies_manager_dialog.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list) {
ItemList *item_list = Object::cast_to<ItemList>(p_item_list);
- popup_menu->set_size(Vector2(1, 1));
+ popup_menu->reset_size();
popup_menu->set_position(get_position() + item_list->get_global_mouse_position());
popup_menu->popup();
}
@@ -312,6 +313,8 @@ void TileProxiesManagerDialog::update_tile_set(Ref<TileSet> p_tile_set) {
}
TileProxiesManagerDialog::TileProxiesManagerDialog() {
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
// Tile proxy management window.
set_title(TTR("Tile Proxies Management"));
set_process_unhandled_key_input(true);
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h
index 6849be2cd6..00866544be 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.h
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,9 +31,7 @@
#ifndef TILE_PROXIES_MANAGER_DIALOG_H
#define TILE_PROXIES_MANAGER_DIALOG_H
-#include "editor/editor_node.h"
#include "editor/editor_properties.h"
-
#include "scene/2d/tile_map.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
@@ -45,24 +43,24 @@ private:
int commited_actions_count = 0;
Ref<TileSet> tile_set;
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
TileMapCell from;
TileMapCell to;
// GUI
- ItemList *source_level_list;
- ItemList *coords_level_list;
- ItemList *alternative_level_list;
+ ItemList *source_level_list = nullptr;
+ ItemList *coords_level_list = nullptr;
+ ItemList *alternative_level_list = nullptr;
- EditorPropertyInteger *source_from_property_editor;
- EditorPropertyVector2i *coords_from_property_editor;
- EditorPropertyInteger *alternative_from_property_editor;
- EditorPropertyInteger *source_to_property_editor;
- EditorPropertyVector2i *coords_to_property_editor;
- EditorPropertyInteger *alternative_to_property_editor;
+ EditorPropertyInteger *source_from_property_editor = nullptr;
+ EditorPropertyVector2i *coords_from_property_editor = nullptr;
+ EditorPropertyInteger *alternative_from_property_editor = nullptr;
+ EditorPropertyInteger *source_to_property_editor = nullptr;
+ EditorPropertyVector2i *coords_to_property_editor = nullptr;
+ EditorPropertyInteger *alternative_to_property_editor = nullptr;
- PopupMenu *popup_menu;
+ PopupMenu *popup_menu = nullptr;
void _right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list);
void _menu_id_pressed(int p_id);
void _delete_selected_bindings();
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index ae744f697b..44b18f48fc 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -36,6 +36,7 @@
#include "editor/editor_scale.h"
#include "editor/progress_dialog.h"
+#include "editor/editor_node.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/control.h"
@@ -99,6 +100,7 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, ""));
}
void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() {
@@ -106,7 +108,7 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_id", "id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::set_id);
ClassDB::bind_method(D_METHOD("get_id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "id"), "set_id", "get_id");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0," + itos(INT_MAX) + ",1"), "set_id", "get_id");
ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
}
@@ -273,7 +275,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
const int &alternative = E->get().alternative;
bool valid = false;
- TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
ERR_FAIL_COND_V(!tile_data, false);
tile_data->set(p_name, p_value, &valid);
@@ -358,7 +360,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
const Vector2i &coords = E->get().tile;
const int &alternative = E->get().alternative;
- TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
ERR_FAIL_COND_V(!tile_data, false);
bool valid = false;
@@ -431,7 +433,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
const Vector2i &coords = E->get().tile;
const int &alternative = E->get().alternative;
- TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
ERR_FAIL_COND(!tile_data);
List<PropertyInfo> list;
@@ -485,7 +487,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(TileSetAtlasSource *p_
const int &alternative = E->get().alternative;
if (tile_set_atlas_source && tile_set_atlas_source->has_tile(coords) && tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
- TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
if (tile_data->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
tile_data->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
}
@@ -501,7 +503,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(TileSetAtlasSource *p_
const int &alternative = E->get().alternative;
if (tile_set_atlas_source->has_tile(coords) && tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
- TileData *tile_data = Object::cast_to<TileData>(tile_set_atlas_source->get_tile_data(coords, alternative));
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
if (!tile_data->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
tile_data->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
}
@@ -608,8 +610,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
// Theming.
- tile_data_editors_tree->add_theme_constant_override("vseparation", 1);
- tile_data_editors_tree->add_theme_constant_override("hseparation", 3);
+ tile_data_editors_tree->add_theme_constant_override("v_separation", 1);
+ tile_data_editors_tree->add_theme_constant_override("h_separation", 3);
Color group_color = get_theme_color(SNAME("prop_category"), SNAME("Editor"));
@@ -1141,7 +1143,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
// Left click pressed.
if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
@@ -1287,7 +1289,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
alternative_tiles_control_unscaled->update();
tile_atlas_view->update();
return;
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT) {
// Right click pressed.
if (mb->is_pressed()) {
drag_type = DRAG_TYPE_MAY_POPUP_MENU;
@@ -1426,7 +1428,7 @@ void TileSetAtlasSourceEditor::_end_dragging() {
// Determine if we clear, then add or remove to the selection.
bool add_to_selection = true;
- if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
Vector2i coords = tile_set_atlas_source->get_tile_at_coords(start_base_tiles_coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
if (selection.has({ coords, 0 })) {
@@ -1693,8 +1695,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
- Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
- Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
bool can_grow[4];
for (int i = 0; i < 4; i++) {
can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
@@ -1891,7 +1893,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
drag_type = DRAG_TYPE_NONE;
Vector2 mouse_local_pos = alternative_tiles_control->get_local_mouse_position();
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
// Left click pressed.
if (tools_button_group->get_pressed_button() == tool_select_button) {
@@ -1907,7 +1909,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
_update_tile_id_label();
}
}
- } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ } else if (mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed()) {
// Right click pressed
Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
@@ -2061,7 +2063,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
int new_polygons_count = p_new_value;
int old_polygons_count = tile_data_proxy->get(vformat("physics_layer_%d/polygons_count", layer_index));
if (new_polygons_count < old_polygons_count) {
- for (int i = new_polygons_count - 1; i < old_polygons_count; i++) {
+ for (int i = new_polygons_count; i < old_polygons_count; i++) {
ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/points", layer_index, i));
ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, i));
ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/one_way_margin", layer_index, i));
@@ -2268,7 +2270,7 @@ void TileSetAtlasSourceEditor::_auto_remove_tiles() {
void TileSetAtlasSourceEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
tool_setup_atlas_source_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
tool_select_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
tool_paint_button->set_icon(get_theme_icon(SNAME("CanvasItem"), SNAME("EditorIcons")));
@@ -2279,8 +2281,9 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
resize_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
resize_handle_disabled = get_theme_icon(SNAME("EditorHandleDisabled"), SNAME("EditorIcons"));
- break;
- case NOTIFICATION_INTERNAL_PROCESS:
+ } break;
+
+ case NOTIFICATION_INTERNAL_PROCESS: {
if (tile_set_changed_needs_update) {
// Update everything.
_update_source_inspector();
@@ -2296,9 +2299,7 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
tile_set_changed_needs_update = false;
}
- break;
- default:
- break;
+ } break;
}
}
@@ -2310,6 +2311,8 @@ void TileSetAtlasSourceEditor::_bind_methods() {
}
TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
set_process_unhandled_key_input(true);
set_process_internal(true);
@@ -2320,7 +2323,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
// Middle panel.
ScrollContainer *middle_panel = memnew(ScrollContainer);
- middle_panel->set_enable_h_scroll(false);
+ middle_panel->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
middle_panel->set_custom_minimum_size(Size2i(200, 0) * EDSCALE);
split_container_right_side->add_child(middle_panel);
@@ -2338,14 +2341,14 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_inspector = memnew(EditorInspector);
tile_inspector->set_undo_redo(undo_redo);
- tile_inspector->set_enable_v_scroll(false);
+ tile_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
tile_inspector->edit(tile_proxy_object);
tile_inspector->set_use_folding(true);
tile_inspector->connect("property_selected", callable_mp(this, &TileSetAtlasSourceEditor::_inspector_property_selected));
middle_vbox_container->add_child(tile_inspector);
tile_inspector_no_tile_selected_label = memnew(Label);
- tile_inspector_no_tile_selected_label->set_align(Label::ALIGN_CENTER);
+ tile_inspector_no_tile_selected_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
tile_inspector_no_tile_selected_label->set_text(TTR("No tile selected."));
middle_vbox_container->add_child(tile_inspector_no_tile_selected_label);
@@ -2384,7 +2387,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
atlas_source_inspector = memnew(EditorInspector);
atlas_source_inspector->set_undo_redo(undo_redo);
- atlas_source_inspector->set_enable_v_scroll(false);
+ atlas_source_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
atlas_source_inspector->edit(atlas_source_proxy_object);
middle_vbox_container->add_child(atlas_source_inspector);
@@ -2453,7 +2456,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tools_settings_erase_button = memnew(Button);
tools_settings_erase_button->set_flat(true);
tools_settings_erase_button->set_toggle_mode(true);
- tools_settings_erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
+ tools_settings_erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E));
tools_settings_erase_button->set_shortcut_context(this);
tool_settings->add_child(tools_settings_erase_button);
@@ -2485,7 +2488,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
right_panel->add_child(tile_atlas_view);
base_tile_popup_menu = memnew(PopupMenu);
- base_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), KEY_DELETE), TILE_DELETE);
+ base_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
base_tile_popup_menu->add_item(TTR("Create an Alternative Tile"), TILE_CREATE_ALTERNATIVE);
base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
tile_atlas_view->add_child(base_tile_popup_menu);
@@ -2508,7 +2511,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
alternative_tile_popup_menu = memnew(PopupMenu);
- alternative_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete_tile", TTR("Delete"), KEY_DELETE), TILE_DELETE);
+ alternative_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete_tile", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
alternative_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
tile_atlas_view->add_child(alternative_tile_popup_menu);
@@ -2526,17 +2529,202 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view_missing_source_label = memnew(Label);
tile_atlas_view_missing_source_label->set_text(TTR("Add or select an atlas texture to the left panel."));
- tile_atlas_view_missing_source_label->set_align(Label::ALIGN_CENTER);
- tile_atlas_view_missing_source_label->set_valign(Label::VALIGN_CENTER);
+ tile_atlas_view_missing_source_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ tile_atlas_view_missing_source_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
tile_atlas_view_missing_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
tile_atlas_view_missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
tile_atlas_view_missing_source_label->hide();
right_panel->add_child(tile_atlas_view_missing_source_label);
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetAtlasSourceEditor::_undo_redo_inspector_callback));
+
+ // Inspector plugin.
+ Ref<EditorInspectorPluginTileData> tile_data_inspector_plugin;
+ tile_data_inspector_plugin.instantiate();
+ EditorInspector::add_inspector_plugin(tile_data_inspector_plugin);
}
TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() {
memdelete(tile_proxy_object);
memdelete(atlas_source_proxy_object);
}
+
+////// EditorPropertyTilePolygon //////
+
+void EditorPropertyTilePolygon::_add_focusable_children(Node *p_node) {
+ Control *control = Object::cast_to<Control>(p_node);
+ if (control && control->get_focus_mode() != Control::FOCUS_NONE) {
+ add_focusable(control);
+ }
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _add_focusable_children(p_node->get_child(i));
+ }
+}
+
+void EditorPropertyTilePolygon::_polygons_changed() {
+ if (String(count_property).is_empty()) {
+ if (base_type == "OccluderPolygon2D") {
+ // Single OccluderPolygon2D.
+ Ref<OccluderPolygon2D> occluder;
+ if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
+ occluder.instantiate();
+ occluder->set_polygon(generic_tile_polygon_editor->get_polygon(0));
+ }
+ emit_changed(get_edited_property(), occluder);
+ } else if (base_type == "NavigationPolygon") {
+ Ref<NavigationPolygon> navigation_polygon;
+ if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
+ navigation_polygon.instantiate();
+ for (int i = 0; i < generic_tile_polygon_editor->get_polygon_count(); i++) {
+ Vector<Vector2> polygon = generic_tile_polygon_editor->get_polygon(i);
+ navigation_polygon->add_outline(polygon);
+ }
+ navigation_polygon->make_polygons_from_outlines();
+ }
+ emit_changed(get_edited_property(), navigation_polygon);
+ }
+ } else {
+ if (base_type.is_empty()) {
+ // Multiple array of vertices.
+ Vector<String> changed_properties;
+ Array values;
+ int count = generic_tile_polygon_editor->get_polygon_count();
+ changed_properties.push_back(count_property);
+ values.push_back(count);
+ for (int i = 0; i < count; i++) {
+ changed_properties.push_back(vformat(element_pattern, i));
+ values.push_back(generic_tile_polygon_editor->get_polygon(i));
+ }
+ emit_signal(SNAME("multiple_properties_changed"), changed_properties, values, false);
+ }
+ }
+}
+
+void EditorPropertyTilePolygon::update_property() {
+ TileSetAtlasSourceEditor::AtlasTileProxyObject *atlas_tile_proxy_object = Object::cast_to<TileSetAtlasSourceEditor::AtlasTileProxyObject>(get_edited_object());
+ ERR_FAIL_COND(!atlas_tile_proxy_object);
+ ERR_FAIL_COND(atlas_tile_proxy_object->get_edited_tiles().is_empty());
+
+ TileSetAtlasSource *tile_set_atlas_source = atlas_tile_proxy_object->get_edited_tile_set_atlas_source();
+ generic_tile_polygon_editor->set_tile_set(Ref<TileSet>(tile_set_atlas_source->get_tile_set()));
+
+ // Set the background
+ Vector2i coords = atlas_tile_proxy_object->get_edited_tiles().front()->get().tile;
+ int alternative = atlas_tile_proxy_object->get_edited_tiles().front()->get().alternative;
+ TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
+ generic_tile_polygon_editor->set_background(tile_set_atlas_source->get_texture(), tile_set_atlas_source->get_tile_texture_region(coords), tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+
+ // Reset the polygons.
+ generic_tile_polygon_editor->clear_polygons();
+
+ if (String(count_property).is_empty()) {
+ if (base_type == "OccluderPolygon2D") {
+ // Single OccluderPolygon2D.
+ Ref<OccluderPolygon2D> occluder = get_edited_object()->get(get_edited_property());
+ generic_tile_polygon_editor->clear_polygons();
+ if (occluder.is_valid()) {
+ generic_tile_polygon_editor->add_polygon(occluder->get_polygon());
+ }
+ } else if (base_type == "NavigationPolygon") {
+ // Single OccluderPolygon2D.
+ Ref<NavigationPolygon> navigation_polygon = get_edited_object()->get(get_edited_property());
+ generic_tile_polygon_editor->clear_polygons();
+ if (navigation_polygon.is_valid()) {
+ for (int i = 0; i < navigation_polygon->get_outline_count(); i++) {
+ generic_tile_polygon_editor->add_polygon(navigation_polygon->get_outline(i));
+ }
+ }
+ }
+ } else {
+ int count = get_edited_object()->get(count_property);
+ if (base_type.is_empty()) {
+ // Multiple array of vertices.
+ generic_tile_polygon_editor->clear_polygons();
+ for (int i = 0; i < count; i++) {
+ generic_tile_polygon_editor->add_polygon(get_edited_object()->get(vformat(element_pattern, i)));
+ }
+ }
+ }
+}
+
+void EditorPropertyTilePolygon::setup_single_mode(const StringName &p_property, const String &p_base_type) {
+ set_object_and_property(nullptr, p_property);
+ base_type = p_base_type;
+
+ generic_tile_polygon_editor->set_multiple_polygon_mode(false);
+}
+
+void EditorPropertyTilePolygon::setup_multiple_mode(const StringName &p_property, const StringName &p_count_property, const String &p_element_pattern, const String &p_base_type) {
+ set_object_and_property(nullptr, p_property);
+ count_property = p_count_property;
+ element_pattern = p_element_pattern;
+ base_type = p_base_type;
+
+ generic_tile_polygon_editor->set_multiple_polygon_mode(true);
+}
+
+EditorPropertyTilePolygon::EditorPropertyTilePolygon() {
+ // Setup the polygon editor.
+ generic_tile_polygon_editor = memnew(GenericTilePolygonEditor);
+ generic_tile_polygon_editor->set_use_undo_redo(false);
+ generic_tile_polygon_editor->clear_polygons();
+ add_child(generic_tile_polygon_editor);
+ generic_tile_polygon_editor->connect("polygons_changed", callable_mp(this, &EditorPropertyTilePolygon::_polygons_changed));
+
+ // Add all focussable children of generic_tile_polygon_editor as focussable.
+ _add_focusable_children(generic_tile_polygon_editor);
+}
+
+////// EditorInspectorPluginTileData //////
+
+bool EditorInspectorPluginTileData::can_handle(Object *p_object) {
+ return Object::cast_to<TileSetAtlasSourceEditor::AtlasTileProxyObject>(p_object) != nullptr;
+}
+
+bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+ Vector<String> components = String(p_path).split("/", true, 2);
+ if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
+ // Occlusion layers.
+ int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (components[1] == "polygon") {
+ EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
+ ep->setup_single_mode(p_path, "OccluderPolygon2D");
+ add_property_editor(p_path, ep);
+ return true;
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
+ // Physics layers.
+ int layer_index = components[0].trim_prefix("physics_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (components[1] == "polygons_count") {
+ EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
+ ep->setup_multiple_mode(vformat("physics_layer_%d/polygons", layer_index), vformat("physics_layer_%d/polygons_count", layer_index), vformat("physics_layer_%d/polygon_%%d/points", layer_index), "");
+ Vector<String> properties;
+ properties.push_back(p_path);
+ int count = p_object->get(vformat("physics_layer_%d/polygons_count", layer_index));
+ for (int i = 0; i < count; i++) {
+ properties.push_back(vformat(vformat("physics_layer_%d/polygon_%d/points", layer_index, i)));
+ }
+ add_property_editor_for_multiple_properties("Polygons", properties, ep);
+ return true;
+ } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
+ int polygon_index = components[1].trim_prefix("polygon_").to_int();
+ ERR_FAIL_COND_V(polygon_index < 0, false);
+ if (components[2] == "points") {
+ return true;
+ }
+ }
+ } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
+ // Navigation layers.
+ int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
+ ERR_FAIL_COND_V(layer_index < 0, false);
+ if (components[1] == "polygon") {
+ EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
+ ep->setup_single_mode(p_path, "NavigationPolygon");
+ add_property_editor(p_path, ep);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index ea6f2847ae..b26b7edbfa 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -34,7 +34,6 @@
#include "tile_atlas_view.h"
#include "tile_data_editors.h"
-#include "editor/editor_node.h"
#include "scene/gui/split_container.h"
#include "scene/resources/tile_set.h"
@@ -43,7 +42,7 @@ class TileSet;
class TileSetAtlasSourceEditor : public HBoxContainer {
GDCLASS(TileSetAtlasSourceEditor, HBoxContainer);
-private:
+public:
// A class to store which tiles are selected.
struct TileSelection {
Vector2i tile = TileSetSource::INVALID_ATLAS_COORDS;
@@ -86,7 +85,7 @@ private:
GDCLASS(AtlasTileProxyObject, Object);
private:
- TileSetAtlasSourceEditor *tiles_set_atlas_source_editor;
+ TileSetAtlasSourceEditor *tiles_set_atlas_source_editor = nullptr;
TileSetAtlasSource *tile_set_atlas_source = nullptr;
Set<TileSelection> tiles = Set<TileSelection>();
@@ -99,6 +98,9 @@ private:
static void _bind_methods();
public:
+ TileSetAtlasSource *get_edited_tile_set_atlas_source() const { return tile_set_atlas_source; };
+ Set<TileSelection> get_edited_tiles() const { return tiles; };
+
// Update the proxyed object.
void edit(TileSetAtlasSource *p_tile_set_atlas_source, Set<TileSelection> p_tiles = Set<TileSelection>());
@@ -107,20 +109,21 @@ private:
}
};
+private:
Ref<TileSet> tile_set;
TileSetAtlasSource *tile_set_atlas_source = nullptr;
int tile_set_atlas_source_id = TileSet::INVALID_SOURCE;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
bool tile_set_changed_needs_update = false;
// -- Properties painting --
- VBoxContainer *tile_data_painting_editor_container;
- Label *tile_data_editors_label;
- Button *tile_data_editor_dropdown_button;
- Popup *tile_data_editors_popup;
- Tree *tile_data_editors_tree;
+ VBoxContainer *tile_data_painting_editor_container = nullptr;
+ Label *tile_data_editors_label = nullptr;
+ Button *tile_data_editor_dropdown_button = nullptr;
+ Popup *tile_data_editors_popup = nullptr;
+ Tree *tile_data_editors_tree = nullptr;
void _tile_data_editor_dropdown_button_draw();
void _tile_data_editor_dropdown_button_pressed();
@@ -132,21 +135,21 @@ private:
void _tile_data_editors_tree_selected();
// -- Inspector --
- AtlasTileProxyObject *tile_proxy_object;
- Label *tile_inspector_label;
- EditorInspector *tile_inspector;
- Label *tile_inspector_no_tile_selected_label;
+ AtlasTileProxyObject *tile_proxy_object = nullptr;
+ Label *tile_inspector_label = nullptr;
+ EditorInspector *tile_inspector = nullptr;
+ Label *tile_inspector_no_tile_selected_label = nullptr;
String selected_property;
void _inspector_property_selected(String p_property);
- TileSetAtlasSourceProxyObject *atlas_source_proxy_object;
- Label *atlas_source_inspector_label;
- EditorInspector *atlas_source_inspector;
+ TileSetAtlasSourceProxyObject *atlas_source_proxy_object = nullptr;
+ Label *atlas_source_inspector_label = nullptr;
+ EditorInspector *atlas_source_inspector = nullptr;
// -- Atlas view --
- HBoxContainer *toolbox;
- Label *tile_atlas_view_missing_source_label;
- TileAtlasView *tile_atlas_view;
+ HBoxContainer *toolbox = nullptr;
+ Label *tile_atlas_view_missing_source_label = nullptr;
+ TileAtlasView *tile_atlas_view = nullptr;
// Dragging
enum DragType {
@@ -199,17 +202,17 @@ private:
// Tool buttons.
Ref<ButtonGroup> tools_button_group;
- Button *tool_setup_atlas_source_button;
- Button *tool_select_button;
- Button *tool_paint_button;
- Label *tool_tile_id_label;
+ Button *tool_setup_atlas_source_button = nullptr;
+ Button *tool_select_button = nullptr;
+ Button *tool_paint_button = nullptr;
+ Label *tool_tile_id_label = nullptr;
// Tool settings.
- HBoxContainer *tool_settings;
- VSeparator *tool_settings_vsep;
- HBoxContainer *tool_settings_tile_data_toolbar_container;
- Button *tools_settings_erase_button;
- MenuButton *tool_advanced_menu_buttom;
+ HBoxContainer *tool_settings = nullptr;
+ VSeparator *tool_settings_vsep = nullptr;
+ HBoxContainer *tool_settings_tile_data_toolbar_container = nullptr;
+ Button *tools_settings_erase_button = nullptr;
+ MenuButton *tool_advanced_menu_buttom = nullptr;
// Selection.
Set<TileSelection> selection;
@@ -220,12 +223,12 @@ private:
// A control on the tile atlas to draw and handle input events.
Vector2i hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
- PopupMenu *base_tile_popup_menu;
- PopupMenu *empty_base_tile_popup_menu;
+ PopupMenu *base_tile_popup_menu = nullptr;
+ PopupMenu *empty_base_tile_popup_menu = nullptr;
Ref<Texture2D> resize_handle;
Ref<Texture2D> resize_handle_disabled;
- Control *tile_atlas_control;
- Control *tile_atlas_control_unscaled;
+ Control *tile_atlas_control = nullptr;
+ Control *tile_atlas_control_unscaled = nullptr;
void _tile_atlas_control_draw();
void _tile_atlas_control_unscaled_draw();
void _tile_atlas_control_mouse_exited();
@@ -235,9 +238,9 @@ private:
// A control over the alternative tiles.
Vector3i hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
- PopupMenu *alternative_tile_popup_menu;
- Control *alternative_tiles_control;
- Control *alternative_tiles_control_unscaled;
+ PopupMenu *alternative_tile_popup_menu = nullptr;
+ Control *alternative_tiles_control = nullptr;
+ Control *alternative_tiles_control_unscaled = nullptr;
void _tile_alternatives_control_draw();
void _tile_alternatives_control_unscaled_draw();
void _tile_alternatives_control_mouse_exited();
@@ -261,7 +264,7 @@ private:
// -- Misc --
void _auto_create_tiles();
void _auto_remove_tiles();
- AcceptDialog *confirm_auto_create_tiles;
+ AcceptDialog *confirm_auto_create_tiles = nullptr;
void _tile_set_changed();
void _tile_proxy_object_changed(String p_what);
@@ -281,4 +284,34 @@ public:
~TileSetAtlasSourceEditor();
};
+class EditorPropertyTilePolygon : public EditorProperty {
+ GDCLASS(EditorPropertyTilePolygon, EditorProperty);
+
+ StringName count_property;
+ String element_pattern;
+ String base_type;
+
+ void _add_focusable_children(Node *p_node);
+
+ GenericTilePolygonEditor *generic_tile_polygon_editor = nullptr;
+ void _polygons_changed();
+
+public:
+ virtual void update_property() override;
+ void setup_single_mode(const StringName &p_property, const String &p_base_type);
+ void setup_multiple_mode(const StringName &p_property, const StringName &p_count_property, const String &p_element_pattern, const String &p_base_type);
+ EditorPropertyTilePolygon();
+};
+
+class EditorInspectorPluginTileData : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorPluginTileData, EditorInspectorPlugin);
+
+ void _occlusion_polygon_set_callback();
+ void _polygons_changed(Object *p_generic_tile_polygon_editor, Object *p_object, const String &p_path);
+
+public:
+ virtual bool can_handle(Object *p_object) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+};
+
#endif // TILE_SET_ATLAS_SOURCE_EDITOR_H
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 915ce50836..fb4a563992 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,6 +33,8 @@
#include "tile_data_editors.h"
#include "tiles_editor_plugin.h"
+#include "editor/editor_file_system.h"
+#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "scene/gui/box_container.h"
@@ -137,9 +139,8 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
sources_list->clear();
// Update the atlas sources.
- for (int i = 0; i < tile_set->get_source_count(); i++) {
- int source_id = tile_set->get_source_id(i);
-
+ List<int> source_ids = TilesEditorPlugin::get_singleton()->get_sorted_sources(tile_set);
+ for (const int &source_id : source_ids) {
TileSetSource *source = *tile_set->get_source(source_id);
Ref<Texture2D> texture;
@@ -156,9 +157,9 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
texture = atlas_source->get_texture();
if (item_text.is_empty()) {
if (texture.is_valid()) {
- item_text = vformat("%s (ID:%d)", texture->get_path().get_file(), source_id);
+ item_text = vformat("%s (ID: %d)", texture->get_path().get_file(), source_id);
} else {
- item_text = vformat(TTR("No Texture Atlas Source (ID:%d)"), source_id);
+ item_text = vformat(TTR("No Texture Atlas Source (ID: %d)"), source_id);
}
}
}
@@ -168,20 +169,20 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
if (scene_collection_source) {
texture = get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons"));
if (item_text.is_empty()) {
- item_text = vformat(TTR("Scene Collection Source (ID:%d)"), source_id);
+ item_text = vformat(TTR("Scene Collection Source (ID: %d)"), source_id);
}
}
// Use default if not valid.
if (item_text.is_empty()) {
- item_text = vformat(TTR("Unknown Type Source (ID:%d)"), source_id);
+ item_text = vformat(TTR("Unknown Type Source (ID: %d)"), source_id);
}
if (!texture.is_valid()) {
texture = missing_texture_texture;
}
sources_list->add_item(item_text, texture);
- sources_list->set_item_metadata(i, source_id);
+ sources_list->set_item_metadata(-1, source_id);
}
// Set again the current selected item if needed.
@@ -189,6 +190,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
for (int i = 0; i < sources_list->get_item_count(); i++) {
if ((int)sources_list->get_item_metadata(i) == to_select) {
sources_list->set_current(i);
+ sources_list->ensure_current_is_visible();
if (old_selected != to_select) {
sources_list->emit_signal(SNAME("item_selected"), sources_list->get_current());
}
@@ -312,16 +314,34 @@ void TileSetEditor::_sources_advanced_menu_id_pressed(int p_id_pressed) {
}
}
+void TileSetEditor::_set_source_sort(int p_sort) {
+ TilesEditorPlugin::get_singleton()->set_sorting_option(p_sort);
+ for (int i = 0; i != TilesEditorPlugin::SOURCE_SORT_MAX; i++) {
+ source_sort_button->get_popup()->set_item_checked(i, (i == (int)p_sort));
+ }
+
+ int old_selected = TileSet::INVALID_SOURCE;
+ if (sources_list->get_current() >= 0) {
+ int source_id = sources_list->get_item_metadata(sources_list->get_current());
+ if (tile_set->has_source(source_id)) {
+ old_selected = source_id;
+ }
+ }
+ _update_sources_list(old_selected);
+}
+
void TileSetEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
sources_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
sources_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ source_sort_button->set_icon(get_theme_icon(SNAME("Sort"), SNAME("EditorIcons")));
sources_advanced_menu_button->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
missing_texture_texture = get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons"));
- break;
- case NOTIFICATION_INTERNAL_PROCESS:
+ } break;
+
+ case NOTIFICATION_INTERNAL_PROCESS: {
if (tile_set_changed_needs_update) {
if (tile_set.is_valid()) {
tile_set->set_edited(true);
@@ -330,9 +350,7 @@ void TileSetEditor::_notification(int p_what) {
_update_patterns_list();
tile_set_changed_needs_update = false;
}
- break;
- default:
- break;
+ } break;
}
}
@@ -441,7 +459,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
String str = pi.name.trim_prefix(p_array_prefix);
int to_char_index = 0;
while (to_char_index < str.length()) {
- if (str[to_char_index] < '0' || str[to_char_index] > '9') {
+ if (!is_digit(str[to_char_index])) {
break;
}
to_char_index++;
@@ -465,7 +483,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
Vector2i tile_id = tas->get_tile_id(j);
for (int k = 0; k < tas->get_alternative_tiles_count(tile_id); k++) {
int alternative_id = tas->get_alternative_tile_id(tile_id, k);
- TileData *tile_data = Object::cast_to<TileData>(tas->get_tile_data(tile_id, alternative_id));
+ TileData *tile_data = tas->get_tile_data(tile_id, alternative_id);
ERR_FAIL_COND(!tile_data);
// Actually saving stuff.
@@ -584,7 +602,7 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
Vector2i tile_id = tas->get_tile_id(j);
for (int k = 0; k < tas->get_alternative_tiles_count(tile_id); k++) {
int alternative_id = tas->get_alternative_tile_id(tile_id, k);
- TileData *tile_data = Object::cast_to<TileData>(tas->get_tile_data(tile_id, alternative_id));
+ TileData *tile_data = tas->get_tile_data(tile_id, alternative_id);
ERR_FAIL_COND(!tile_data);
if (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") {
@@ -640,10 +658,13 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
TileSetEditor::TileSetEditor() {
singleton = this;
+ undo_redo = EditorNode::get_undo_redo();
+
set_process_internal(true);
// TabBar.
tabs_bar = memnew(TabBar);
+ tabs_bar->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
tabs_bar->set_clip_tabs(false);
tabs_bar->add_tab(TTR("Tiles"));
tabs_bar->add_tab(TTR("Patterns"));
@@ -670,19 +691,33 @@ TileSetEditor::TileSetEditor() {
split_container_left_side->set_custom_minimum_size(Size2i(70, 0) * EDSCALE);
split_container->add_child(split_container_left_side);
+ source_sort_button = memnew(MenuButton);
+ source_sort_button->set_flat(true);
+ source_sort_button->set_tooltip(TTR("Sort sources"));
+
+ PopupMenu *p = source_sort_button->get_popup();
+ p->connect("id_pressed", callable_mp(this, &TileSetEditor::_set_source_sort));
+ p->add_radio_check_item(TTR("Sort by ID (Ascending)"), TilesEditorPlugin::SOURCE_SORT_ID);
+ p->add_radio_check_item(TTR("Sort by ID (Descending)"), TilesEditorPlugin::SOURCE_SORT_ID_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Name (Ascending)"), TilesEditorPlugin::SOURCE_SORT_NAME);
+ p->add_radio_check_item(TTR("Sort by Name (Descending)"), TilesEditorPlugin::SOURCE_SORT_NAME_REVERSE);
+ p->set_item_checked(TilesEditorPlugin::SOURCE_SORT_ID, true);
+
sources_list = memnew(ItemList);
sources_list->set_fixed_icon_size(Size2i(60, 60) * EDSCALE);
sources_list->set_h_size_flags(SIZE_EXPAND_FILL);
sources_list->set_v_size_flags(SIZE_EXPAND_FILL);
sources_list->connect("item_selected", callable_mp(this, &TileSetEditor::_source_selected));
sources_list->connect("item_selected", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_sources_lists_current));
- sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list), varray(sources_list));
+ sources_list->connect("visibility_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::synchronize_sources_list), varray(sources_list, source_sort_button));
+ sources_list->add_user_signal(MethodInfo("sort_request"));
+ sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list), varray(-1));
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
sources_list->set_drag_forwarding(this);
split_container_left_side->add_child(sources_list);
HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);
- sources_bottom_actions->set_alignment(HBoxContainer::ALIGN_END);
+ sources_bottom_actions->set_alignment(BoxContainer::ALIGNMENT_END);
split_container_left_side->add_child(sources_bottom_actions);
sources_delete_button = memnew(Button);
@@ -704,6 +739,7 @@ TileSetEditor::TileSetEditor() {
sources_advanced_menu_button->get_popup()->add_item(TTR("Manage Tile Proxies"));
sources_advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileSetEditor::_sources_advanced_menu_id_pressed));
sources_bottom_actions->add_child(sources_advanced_menu_button);
+ sources_bottom_actions->add_child(source_sort_button);
atlas_merging_dialog = memnew(AtlasMergingDialog);
add_child(atlas_merging_dialog);
@@ -722,8 +758,8 @@ TileSetEditor::TileSetEditor() {
no_source_selected_label->set_text(TTR("No TileSet source selected. Select or create a TileSet source."));
no_source_selected_label->set_h_size_flags(SIZE_EXPAND_FILL);
no_source_selected_label->set_v_size_flags(SIZE_EXPAND_FILL);
- no_source_selected_label->set_align(Label::ALIGN_CENTER);
- no_source_selected_label->set_valign(Label::VALIGN_CENTER);
+ no_source_selected_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ no_source_selected_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
split_container_right_side->add_child(no_source_selected_label);
// Atlases editor.
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index 58312ce3df..e633de37b0 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,6 +33,7 @@
#include "atlas_merging_dialog.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/tab_bar.h"
#include "scene/resources/tile_set.h"
#include "tile_proxies_manager_dialog.h"
#include "tile_set_atlas_source_editor.h"
@@ -46,18 +47,18 @@ class TileSetEditor : public VBoxContainer {
private:
Ref<TileSet> tile_set;
bool tile_set_changed_needs_update = false;
- HSplitContainer *split_container;
+ HSplitContainer *split_container = nullptr;
// TabBar.
- HBoxContainer *tile_set_toolbar;
- TabBar *tabs_bar;
+ HBoxContainer *tile_set_toolbar = nullptr;
+ TabBar *tabs_bar = nullptr;
// Tiles.
- Label *no_source_selected_label;
- TileSetAtlasSourceEditor *tile_set_atlas_source_editor;
- TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor;
+ Label *no_source_selected_label = nullptr;
+ TileSetAtlasSourceEditor *tile_set_atlas_source_editor = nullptr;
+ TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor = nullptr;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
@@ -65,22 +66,24 @@ private:
void _update_sources_list(int force_selected_id = -1);
// Sources management.
- Button *sources_delete_button;
- MenuButton *sources_add_button;
- MenuButton *sources_advanced_menu_button;
- ItemList *sources_list;
+ Button *sources_delete_button = nullptr;
+ MenuButton *sources_add_button = nullptr;
+ MenuButton *source_sort_button = nullptr;
+ MenuButton *sources_advanced_menu_button = nullptr;
+ ItemList *sources_list = nullptr;
Ref<Texture2D> missing_texture_texture;
void _source_selected(int p_source_index);
void _source_delete_pressed();
void _source_add_id_pressed(int p_id_pressed);
void _sources_advanced_menu_id_pressed(int p_id_pressed);
+ void _set_source_sort(int p_sort);
- AtlasMergingDialog *atlas_merging_dialog;
- TileProxiesManagerDialog *tile_proxies_manager_dialog;
+ AtlasMergingDialog *atlas_merging_dialog = nullptr;
+ TileProxiesManagerDialog *tile_proxies_manager_dialog = nullptr;
// Patterns.
- ItemList *patterns_item_list;
- Label *patterns_help_label;
+ ItemList *patterns_item_list = nullptr;
+ Label *patterns_help_label = nullptr;
void _patterns_item_list_gui_input(const Ref<InputEvent> &p_event);
void _pattern_preview_done(Ref<TileMapPattern> p_pattern, Ref<Texture2D> p_texture);
bool select_last_pattern = false;
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index d687d9651d..9a4b14616f 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,6 +30,8 @@
#include "tile_set_scenes_collection_source_editor.h"
+#include "editor/editor_file_system.h"
+#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -328,12 +330,13 @@ void TileSetScenesCollectionSourceEditor::_update_scenes_list() {
void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
scene_tile_add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
scene_tile_delete_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
_update_scenes_list();
- break;
- case NOTIFICATION_INTERNAL_PROCESS:
+ } break;
+
+ case NOTIFICATION_INTERNAL_PROCESS: {
if (tile_set_scenes_collection_source_changed_needs_update) {
// Update everything.
_update_source_inspector();
@@ -342,14 +345,13 @@ void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
_update_tile_inspector();
tile_set_scenes_collection_source_changed_needs_update = false;
}
- break;
- case NOTIFICATION_VISIBILITY_CHANGED:
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
// Update things just in case.
_update_scenes_list();
_update_action_buttons();
- break;
- default:
- break;
+ } break;
}
}
@@ -392,13 +394,12 @@ void TileSetScenesCollectionSourceEditor::_drop_data_fw(const Point2 &p_point, c
if (p_from == scene_tiles_list) {
// Handle dropping a texture in the list of atlas resources.
- int scene_id = -1;
Dictionary d = p_data;
Vector<String> files = d["files"];
for (int i = 0; i < files.size(); i++) {
Ref<PackedScene> resource = ResourceLoader::load(files[i]);
if (resource.is_valid()) {
- scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
+ int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
undo_redo->create_action(TTR("Add a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", resource, scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
@@ -452,6 +453,8 @@ void TileSetScenesCollectionSourceEditor::_bind_methods() {
}
TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+
// -- Right side --
HSplitContainer *split_container_right_side = memnew(HSplitContainer);
split_container_right_side->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -459,7 +462,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
// Middle panel.
ScrollContainer *middle_panel = memnew(ScrollContainer);
- middle_panel->set_enable_h_scroll(false);
+ middle_panel->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
middle_panel->set_custom_minimum_size(Size2i(200, 0) * EDSCALE);
split_container_right_side->add_child(middle_panel);
@@ -477,7 +480,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
scenes_collection_source_inspector = memnew(EditorInspector);
scenes_collection_source_inspector->set_undo_redo(undo_redo);
- scenes_collection_source_inspector->set_enable_v_scroll(false);
+ scenes_collection_source_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
scenes_collection_source_inspector->edit(scenes_collection_source_proxy_object);
middle_vbox_container->add_child(scenes_collection_source_inspector);
@@ -493,7 +496,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
tile_inspector = memnew(EditorInspector);
tile_inspector->set_undo_redo(undo_redo);
- tile_inspector->set_enable_v_scroll(false);
+ tile_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
tile_inspector->edit(tile_proxy_object);
tile_inspector->set_use_folding(true);
middle_vbox_container->add_child(tile_inspector);
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
index 4e33128be5..657bfca032 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,10 +31,14 @@
#ifndef TILE_SET_SCENES_COLLECTION_SOURCE_EDITOR_H
#define TILE_SET_SCENES_COLLECTION_SOURCE_EDITOR_H
-#include "editor/editor_node.h"
+#include "editor/editor_inspector.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/item_list.h"
#include "scene/resources/tile_set.h"
+class UndoRedo;
+
class TileSetScenesCollectionSourceEditor : public HBoxContainer {
GDCLASS(TileSetScenesCollectionSourceEditor, HBoxContainer);
@@ -66,7 +70,7 @@ private:
GDCLASS(SceneTileProxyObject, Object);
private:
- TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor;
+ TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor = nullptr;
TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
int source_id;
@@ -93,23 +97,23 @@ private:
TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
int tile_set_source_id = -1;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ UndoRedo *undo_redo = nullptr;
bool tile_set_scenes_collection_source_changed_needs_update = false;
// Source inspector.
- TileSetScenesCollectionProxyObject *scenes_collection_source_proxy_object;
- Label *scenes_collection_source_inspector_label;
- EditorInspector *scenes_collection_source_inspector;
+ TileSetScenesCollectionProxyObject *scenes_collection_source_proxy_object = nullptr;
+ Label *scenes_collection_source_inspector_label = nullptr;
+ EditorInspector *scenes_collection_source_inspector = nullptr;
// Tile inspector.
- SceneTileProxyObject *tile_proxy_object;
- Label *tile_inspector_label;
- EditorInspector *tile_inspector;
+ SceneTileProxyObject *tile_proxy_object = nullptr;
+ Label *tile_inspector_label = nullptr;
+ EditorInspector *tile_inspector = nullptr;
- ItemList *scene_tiles_list;
- Button *scene_tile_add_button;
- Button *scene_tile_delete_button;
+ ItemList *scene_tiles_list = nullptr;
+ Button *scene_tile_add_button = nullptr;
+ Button *scene_tile_delete_button = nullptr;
void _tile_set_scenes_collection_source_changed();
void _scenes_collection_source_proxy_object_changed(String p_what);
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index f1918073fb..543304346e 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -47,12 +47,16 @@
TilesEditorPlugin *TilesEditorPlugin::singleton = nullptr;
-void TilesEditorPlugin::_pattern_preview_done(const Variant &p_udata) {
- pattern_preview_done.set();
+void TilesEditorPlugin::_preview_frame_started() {
+ RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_pattern_preview_done));
+}
+
+void TilesEditorPlugin::_pattern_preview_done() {
+ pattern_preview_done.post();
}
void TilesEditorPlugin::_thread_func(void *ud) {
- TilesEditorPlugin *te = (TilesEditorPlugin *)ud;
+ TilesEditorPlugin *te = static_cast<TilesEditorPlugin *>(ud);
te->_thread();
}
@@ -109,15 +113,12 @@ void TilesEditorPlugin::_thread() {
tile_map->set_scale(scale);
tile_map->set_position(-(scale * encompassing_rect.get_center()) + thumbnail_size2 / 2);
- // Add the viewport at the lasst moment to avoid rendering too early.
+ // Add the viewport at the last moment to avoid rendering too early.
EditorNode::get_singleton()->add_child(viewport);
- pattern_preview_done.clear();
- RS::get_singleton()->request_frame_drawn_callback(const_cast<TilesEditorPlugin *>(this), "_pattern_preview_done", Variant());
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT);
- while (!pattern_preview_done.is_set()) {
- OS::get_singleton()->delay_usec(10);
- }
+ pattern_preview_done.wait();
Ref<Image> image = viewport->get_texture()->get_image();
Ref<ImageTexture> image_texture;
@@ -156,6 +157,15 @@ void TilesEditorPlugin::_update_editors() {
// Update the viewport.
CanvasItemEditor::get_singleton()->update_viewport();
+
+ // Update visibility of bottom panel buttons.
+ if (tileset_editor_button->is_pressed() && !tile_set.is_valid()) {
+ if (tile_map) {
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor);
+ } else {
+ EditorNode::get_singleton()->hide_bottom_panel();
+ }
+ }
}
void TilesEditorPlugin::_notification(int p_what) {
@@ -180,15 +190,15 @@ void TilesEditorPlugin::make_visible(bool p_visible) {
tileset_editor_button->set_visible(tile_set.is_valid());
tilemap_editor_button->set_visible(tile_map);
if (tile_map) {
- editor_node->make_bottom_panel_item_visible(tilemap_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor);
} else {
- editor_node->make_bottom_panel_item_visible(tileset_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor);
}
} else {
tileset_editor_button->hide();
tilemap_editor_button->hide();
- editor_node->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
}
@@ -206,15 +216,29 @@ void TilesEditorPlugin::set_sources_lists_current(int p_current) {
atlas_sources_lists_current = p_current;
}
-void TilesEditorPlugin::synchronize_sources_list(Object *p_current) {
- ItemList *item_list = Object::cast_to<ItemList>(p_current);
+void TilesEditorPlugin::synchronize_sources_list(Object *p_current_list, Object *p_current_sort_button) {
+ ItemList *item_list = Object::cast_to<ItemList>(p_current_list);
+ MenuButton *sorting_button = Object::cast_to<MenuButton>(p_current_sort_button);
ERR_FAIL_COND(!item_list);
+ ERR_FAIL_COND(!sorting_button);
+
+ if (sorting_button->is_visible_in_tree()) {
+ for (int i = 0; i != SOURCE_SORT_MAX; i++) {
+ sorting_button->get_popup()->set_item_checked(i, (i == (int)source_sort));
+ }
+ }
if (item_list->is_visible_in_tree()) {
if (atlas_sources_lists_current < 0 || atlas_sources_lists_current >= item_list->get_item_count()) {
item_list->deselect_all();
} else {
+ // Make sure the selection is not overwritten after sorting.
+ int atlas_sources_lists_current_mem = atlas_sources_lists_current;
+ item_list->emit_signal(SNAME("sort_request"));
+ atlas_sources_lists_current = atlas_sources_lists_current_mem;
+
item_list->set_current(atlas_sources_lists_current);
+ item_list->ensure_current_is_visible();
item_list->emit_signal(SNAME("item_selected"), atlas_sources_lists_current);
}
}
@@ -234,6 +258,87 @@ void TilesEditorPlugin::synchronize_atlas_view(Object *p_current) {
}
}
+void TilesEditorPlugin::set_sorting_option(int p_option) {
+ source_sort = p_option;
+}
+
+List<int> TilesEditorPlugin::get_sorted_sources(const Ref<TileSet> tile_set) const {
+ SourceNameComparator::tile_set = tile_set;
+ List<int> source_ids;
+
+ for (int i = 0; i < tile_set->get_source_count(); i++) {
+ source_ids.push_back(tile_set->get_source_id(i));
+ }
+
+ switch (source_sort) {
+ case SOURCE_SORT_ID_REVERSE:
+ // Already sorted.
+ source_ids.reverse();
+ break;
+ case SOURCE_SORT_NAME:
+ source_ids.sort_custom<SourceNameComparator>();
+ break;
+ case SOURCE_SORT_NAME_REVERSE:
+ source_ids.sort_custom<SourceNameComparator>();
+ source_ids.reverse();
+ break;
+ default: // SOURCE_SORT_ID
+ break;
+ }
+
+ SourceNameComparator::tile_set.unref();
+ return source_ids;
+}
+
+Ref<TileSet> TilesEditorPlugin::SourceNameComparator::tile_set;
+
+bool TilesEditorPlugin::SourceNameComparator::operator()(const int &p_a, const int &p_b) const {
+ String name_a;
+ String name_b;
+
+ {
+ TileSetSource *source = *tile_set->get_source(p_a);
+
+ if (!source->get_name().is_empty()) {
+ name_a = source->get_name();
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ Ref<Texture2D> texture = atlas_source->get_texture();
+ if (name_a.is_empty() && texture.is_valid()) {
+ name_a = texture->get_path().get_file();
+ }
+ }
+
+ if (name_a.is_empty()) {
+ name_a = itos(p_a);
+ }
+ }
+
+ {
+ TileSetSource *source = *tile_set->get_source(p_b);
+
+ if (!source->get_name().is_empty()) {
+ name_b = source->get_name();
+ }
+
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ Ref<Texture2D> texture = atlas_source->get_texture();
+ if (name_b.is_empty() && texture.is_valid()) {
+ name_b = texture->get_path().get_file();
+ }
+ }
+
+ if (name_b.is_empty()) {
+ name_b = itos(p_b);
+ }
+ }
+
+ return NaturalNoCaseComparator()(name_a, name_b);
+}
+
void TilesEditorPlugin::edit(Object *p_object) {
// Disconnect to changes.
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
@@ -248,7 +353,7 @@ void TilesEditorPlugin::edit(Object *p_object) {
tile_map_id = p_object->get_instance_id();
tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
tile_set = tile_map->get_tileset();
- editor_node->make_bottom_panel_item_visible(tilemap_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(tilemap_editor);
} else if (p_object->is_class("TileSet")) {
tile_set = Ref<TileSet>(p_object);
if (tile_map) {
@@ -257,7 +362,7 @@ void TilesEditorPlugin::edit(Object *p_object) {
tile_map_id = ObjectID();
}
}
- editor_node->make_bottom_panel_item_visible(tileset_editor);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(tileset_editor);
}
}
@@ -274,18 +379,12 @@ bool TilesEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("TileMap") || p_object->is_class("TileSet");
}
-void TilesEditorPlugin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_pattern_preview_done", "pattern"), &TilesEditorPlugin::_pattern_preview_done);
-}
-
-TilesEditorPlugin::TilesEditorPlugin(EditorNode *p_node) {
+TilesEditorPlugin::TilesEditorPlugin() {
set_process_internal(true);
// Update the singleton.
singleton = this;
- editor_node = p_node;
-
// Tileset editor.
tileset_editor = memnew(TileSetEditor);
tileset_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -304,9 +403,9 @@ TilesEditorPlugin::TilesEditorPlugin(EditorNode *p_node) {
pattern_preview_thread.start(_thread_func, this);
// Bottom buttons.
- tileset_editor_button = p_node->add_bottom_panel_item(TTR("TileSet"), tileset_editor);
+ tileset_editor_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TileSet"), tileset_editor);
tileset_editor_button->hide();
- tilemap_editor_button = p_node->add_bottom_panel_item(TTR("TileMap"), tilemap_editor);
+ tilemap_editor_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("TileMap"), tilemap_editor);
tilemap_editor_button->hide();
// Initialization.
diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h
index dd52bdc31a..a22e782b34 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.h
+++ b/editor/plugins/tiles/tiles_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -43,18 +43,25 @@ class TilesEditorPlugin : public EditorPlugin {
static TilesEditorPlugin *singleton;
-private:
- EditorNode *editor_node;
+public:
+ enum SourceSortOption {
+ SOURCE_SORT_ID = 0,
+ SOURCE_SORT_ID_REVERSE,
+ SOURCE_SORT_NAME,
+ SOURCE_SORT_NAME_REVERSE,
+ SOURCE_SORT_MAX
+ };
+private:
bool tile_map_changed_needs_update = false;
ObjectID tile_map_id;
Ref<TileSet> tile_set;
- Button *tilemap_editor_button;
- TileMapEditor *tilemap_editor;
+ Button *tilemap_editor_button = nullptr;
+ TileMapEditor *tilemap_editor = nullptr;
- Button *tileset_editor_button;
- TileSetEditor *tileset_editor;
+ Button *tileset_editor_button = nullptr;
+ TileSetEditor *tileset_editor = nullptr;
void _update_editors();
@@ -65,6 +72,14 @@ private:
void _tile_map_changed();
+ // Source sorting.
+ int source_sort = SOURCE_SORT_ID;
+
+ struct SourceNameComparator {
+ static Ref<TileSet> tile_set;
+ bool operator()(const int &p_a, const int &p_b) const;
+ };
+
// Patterns preview generation.
struct QueueItem {
Ref<TileSet> tile_set;
@@ -77,14 +92,14 @@ private:
Thread pattern_preview_thread;
SafeFlag pattern_thread_exit;
SafeFlag pattern_thread_exited;
- mutable SafeFlag pattern_preview_done;
- void _pattern_preview_done(const Variant &p_udata);
+ Semaphore pattern_preview_done;
+ void _preview_frame_started();
+ void _pattern_preview_done();
static void _thread_func(void *ud);
void _thread();
protected:
void _notification(int p_what);
- static void _bind_methods();
public:
_FORCE_INLINE_ static TilesEditorPlugin *get_singleton() { return singleton; }
@@ -97,16 +112,20 @@ public:
// To synchronize the atlas sources lists.
void set_sources_lists_current(int p_current);
- void synchronize_sources_list(Object *p_current);
+ void synchronize_sources_list(Object *p_current_list, Object *p_current_sort_button);
void set_atlas_view_transform(float p_zoom, Vector2 p_scroll);
void synchronize_atlas_view(Object *p_current);
+ // Sorting.
+ void set_sorting_option(int p_option);
+ List<int> get_sorted_sources(const Ref<TileSet> tile_set) const;
+
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- TilesEditorPlugin(EditorNode *p_node);
+ TilesEditorPlugin();
~TilesEditorPlugin();
};
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index aaa29bcb7a..443d5975cd 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -49,6 +49,11 @@ void VersionControlEditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
}
+void VersionControlEditorPlugin::_create_vcs_metadata_files() {
+ String dir = "res://";
+ EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(metadata_selection->get_selected()), dir);
+}
+
void VersionControlEditorPlugin::_selected_a_vcs(int p_id) {
List<StringName> available_addons = get_available_vcs_names();
const StringName selected_vcs = set_up_choice->get_item_text(p_id);
@@ -71,6 +76,10 @@ VersionControlEditorPlugin *VersionControlEditorPlugin::get_singleton() {
return singleton ? singleton : memnew(VersionControlEditorPlugin);
}
+void VersionControlEditorPlugin::popup_vcs_metadata_dialog() {
+ metadata_dialog->popup_centered();
+}
+
void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) {
fetch_available_vcs_addon_names();
List<StringName> available_addons = get_available_vcs_names();
@@ -257,7 +266,7 @@ void VersionControlEditorPlugin::_display_file_diff(String p_file_path) {
void VersionControlEditorPlugin::_refresh_file_diff() {
String open_file = diff_file_name->get_text();
- if (open_file != "") {
+ if (!open_file.is_empty()) {
_display_file_diff(diff_file_name->get_text());
}
}
@@ -290,7 +299,7 @@ void VersionControlEditorPlugin::_update_commit_status() {
}
void VersionControlEditorPlugin::_update_commit_button() {
- commit_button->set_disabled(commit_message->get_text().strip_edges() == "");
+ commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty());
}
void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) {
@@ -320,7 +329,7 @@ void VersionControlEditorPlugin::register_editor() {
if (!EditorVCSInterface::get_singleton()) {
EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
TabContainer *dock_vbc = (TabContainer *)version_commit_dock->get_parent_control();
- dock_vbc->set_tab_title(version_commit_dock->get_index(), TTR("Commit"));
+ dock_vbc->set_tab_title(dock_vbc->get_tab_idx_from_control(version_commit_dock), TTR("Commit"));
Button *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
set_version_control_tool_button(vc);
@@ -374,6 +383,30 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
version_control_actions = memnew(PopupMenu);
+ metadata_dialog = memnew(ConfirmationDialog);
+ metadata_dialog->set_title(TTR("Create Version Control Metadata"));
+ metadata_dialog->set_min_size(Size2(200, 40));
+ version_control_actions->add_child(metadata_dialog);
+
+ VBoxContainer *metadata_vb = memnew(VBoxContainer);
+ HBoxContainer *metadata_hb = memnew(HBoxContainer);
+ metadata_hb->set_custom_minimum_size(Size2(200, 20));
+ Label *l = memnew(Label);
+ l->set_text(TTR("Create VCS metadata files for:"));
+ metadata_hb->add_child(l);
+ metadata_selection = memnew(OptionButton);
+ metadata_selection->set_custom_minimum_size(Size2(100, 20));
+ metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE);
+ metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);
+ metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
+ metadata_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files));
+ metadata_hb->add_child(metadata_selection);
+ metadata_vb->add_child(metadata_hb);
+ l = memnew(Label);
+ l->set_text(TTR("Existing VCS metadata files will be overwritten."));
+ metadata_vb->add_child(l);
+ metadata_dialog->add_child(metadata_vb);
+
set_up_dialog = memnew(AcceptDialog);
set_up_dialog->set_title(TTR("Set Up Version Control"));
set_up_dialog->set_min_size(Size2(400, 100));
@@ -383,11 +416,11 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
set_up_ok_button->set_text(TTR("Close"));
set_up_vbc = memnew(VBoxContainer);
- set_up_vbc->set_alignment(VBoxContainer::ALIGN_CENTER);
+ set_up_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
set_up_dialog->add_child(set_up_vbc);
set_up_hbc = memnew(HBoxContainer);
- set_up_hbc->set_h_size_flags(HBoxContainer::SIZE_EXPAND_FILL);
+ set_up_hbc->set_h_size_flags(BoxContainer::SIZE_EXPAND_FILL);
set_up_vbc->add_child(set_up_hbc);
set_up_vcs_status = memnew(RichTextLabel);
@@ -414,7 +447,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
version_commit_dock->set_visible(false);
commit_box_vbc = memnew(VBoxContainer);
- commit_box_vbc->set_alignment(VBoxContainer::ALIGN_BEGIN);
+ commit_box_vbc->set_alignment(VBoxContainer::ALIGNMENT_BEGIN);
commit_box_vbc->set_h_size_flags(VBoxContainer::SIZE_EXPAND_FILL);
commit_box_vbc->set_v_size_flags(VBoxContainer::SIZE_EXPAND_FILL);
version_commit_dock->add_child(commit_box_vbc);
@@ -488,7 +521,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
commit_message->connect("text_changed", callable_mp(this, &VersionControlEditorPlugin::_update_commit_button));
commit_message->connect("gui_input", callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input));
commit_box_vbc->add_child(commit_message);
- ED_SHORTCUT("version_control/commit", TTR("Commit"), KEY_MASK_CMD | KEY_ENTER);
+ ED_SHORTCUT("version_control/commit", TTR("Commit"), KeyModifierMask::CMD | Key::ENTER);
commit_button = memnew(Button);
commit_button->set_text(TTR("Commit Changes"));
@@ -497,7 +530,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
commit_box_vbc->add_child(commit_button);
commit_status = memnew(Label);
- commit_status->set_align(Label::ALIGN_CENTER);
+ commit_status->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
commit_box_vbc->add_child(commit_status);
version_control_dock = memnew(PanelContainer);
@@ -522,7 +555,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
diff_file_name = memnew(Label);
diff_file_name->set_text(TTR("No file diff is active"));
diff_file_name->set_h_size_flags(Label::SIZE_EXPAND_FILL);
- diff_file_name->set_align(Label::ALIGN_RIGHT);
+ diff_file_name->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
diff_hbc->add_child(diff_file_name);
diff_refresh_button = memnew(Button);
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index d2ba63c86c..39a56de772 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -33,8 +33,9 @@
#include "editor/editor_plugin.h"
#include "editor/editor_vcs_interface.h"
-#include "scene/gui/container.h"
+#include "scene/gui/box_container.h"
#include "scene/gui/rich_text_label.h"
+#include "scene/gui/split_container.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/tree.h"
@@ -56,48 +57,51 @@ private:
int staged_files_count;
List<StringName> available_addons;
- PopupMenu *version_control_actions;
- AcceptDialog *set_up_dialog;
- VBoxContainer *set_up_vbc;
- HBoxContainer *set_up_hbc;
- Label *set_up_vcs_label;
- OptionButton *set_up_choice;
- PanelContainer *set_up_init_settings;
- Button *set_up_init_button;
- RichTextLabel *set_up_vcs_status;
- Button *set_up_ok_button;
+ PopupMenu *version_control_actions = nullptr;
+ ConfirmationDialog *metadata_dialog = nullptr;
+ OptionButton *metadata_selection = nullptr;
+ AcceptDialog *set_up_dialog = nullptr;
+ VBoxContainer *set_up_vbc = nullptr;
+ HBoxContainer *set_up_hbc = nullptr;
+ Label *set_up_vcs_label = nullptr;
+ OptionButton *set_up_choice = nullptr;
+ PanelContainer *set_up_init_settings = nullptr;
+ Button *set_up_init_button = nullptr;
+ RichTextLabel *set_up_vcs_status = nullptr;
+ Button *set_up_ok_button = nullptr;
HashMap<ChangeType, String> change_type_to_strings;
HashMap<ChangeType, Color> change_type_to_color;
- VBoxContainer *version_commit_dock;
- VBoxContainer *commit_box_vbc;
- HSplitContainer *stage_tools;
- Tree *stage_files;
- TreeItem *new_files;
- TreeItem *modified_files;
- TreeItem *renamed_files;
- TreeItem *deleted_files;
- TreeItem *typechange_files;
- Label *staging_area_label;
- HSplitContainer *stage_buttons;
- Button *stage_all_button;
- Button *stage_selected_button;
- Button *refresh_button;
- TextEdit *commit_message;
- Button *commit_button;
- Label *commit_status;
-
- PanelContainer *version_control_dock;
- Button *version_control_dock_button;
- VBoxContainer *diff_vbc;
- HBoxContainer *diff_hbc;
- Button *diff_refresh_button;
- Label *diff_file_name;
- Label *diff_heading;
- RichTextLabel *diff;
+ VBoxContainer *version_commit_dock = nullptr;
+ VBoxContainer *commit_box_vbc = nullptr;
+ HSplitContainer *stage_tools = nullptr;
+ Tree *stage_files = nullptr;
+ TreeItem *new_files = nullptr;
+ TreeItem *modified_files = nullptr;
+ TreeItem *renamed_files = nullptr;
+ TreeItem *deleted_files = nullptr;
+ TreeItem *typechange_files = nullptr;
+ Label *staging_area_label = nullptr;
+ HSplitContainer *stage_buttons = nullptr;
+ Button *stage_all_button = nullptr;
+ Button *stage_selected_button = nullptr;
+ Button *refresh_button = nullptr;
+ TextEdit *commit_message = nullptr;
+ Button *commit_button = nullptr;
+ Label *commit_status = nullptr;
+
+ PanelContainer *version_control_dock = nullptr;
+ Button *version_control_dock_button = nullptr;
+ VBoxContainer *diff_vbc = nullptr;
+ HBoxContainer *diff_hbc = nullptr;
+ Button *diff_refresh_button = nullptr;
+ Label *diff_file_name = nullptr;
+ Label *diff_heading = nullptr;
+ RichTextLabel *diff = nullptr;
void _populate_available_vcs_names();
+ void _create_vcs_metadata_files();
void _selected_a_vcs(int p_id);
void _initialize_vcs();
void _send_commit_msg();
@@ -121,6 +125,7 @@ protected:
public:
static VersionControlEditorPlugin *get_singleton();
+ void popup_vcs_metadata_dialog();
void popup_vcs_set_up_dialog(const Control *p_gui_base);
void set_version_control_tool_button(Button *p_button) { version_control_dock_button = p_button; }
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index c06eafae50..f184049d41 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,11 +37,13 @@
#include "core/math/math_defs.h"
#include "core/os/keyboard.h"
#include "editor/editor_log.h"
+#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
+#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
#include "scene/resources/visual_shader_nodes.h"
#include "scene/resources/visual_shader_particle_nodes.h"
@@ -117,7 +119,7 @@ void VisualShaderGraphPlugin::register_shader(VisualShader *p_shader) {
visual_shader = Ref<VisualShader>(p_shader);
}
-void VisualShaderGraphPlugin::set_connections(List<VisualShader::Connection> &p_connections) {
+void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connection> &p_connections) {
connections = p_connections;
}
@@ -132,7 +134,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
if (links[p_node_id].preview_visible && !is_dirty() && links[p_node_id].preview_box != nullptr) {
links[p_node_id].graph_node->remove_child(links[p_node_id].preview_box);
memdelete(links[p_node_id].preview_box);
- links[p_node_id].graph_node->set_size(Vector2(-1, -1));
+ links[p_node_id].graph_node->reset_size();
links[p_node_id].preview_visible = false;
}
@@ -183,9 +185,15 @@ void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_
switch (p_value.get_type()) {
case Variant::COLOR: {
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (!editor) {
+ break;
+ }
button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);
- if (!button->is_connected("draw", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_draw_color_over_button))) {
- button->connect("draw", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_draw_color_over_button), varray(button, p_value));
+
+ Callable ce = callable_mp(editor, &VisualShaderEditor::_draw_color_over_button);
+ if (!button->is_connected("draw", ce)) {
+ button->connect("draw", ce, varray(button, p_value));
}
} break;
case Variant::BOOL: {
@@ -195,10 +203,18 @@ void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_
case Variant::FLOAT: {
button->set_text(String::num(p_value, 4));
} break;
+ case Variant::VECTOR2: {
+ Vector2 v = p_value;
+ button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3));
+ } break;
case Variant::VECTOR3: {
Vector3 v = p_value;
button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3));
} break;
+ case Variant::QUATERNION: {
+ Quaternion v = p_value;
+ button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3) + "," + String::num(v.w, 3));
+ } break;
default: {
}
}
@@ -256,7 +272,7 @@ void VisualShaderGraphPlugin::update_node_size(int p_node_id) {
if (!links.has(p_node_id)) {
return;
}
- links[p_node_id].graph_node->set_size(Size2(-1, -1));
+ links[p_node_id].graph_node->reset_size();
}
void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) {
@@ -320,33 +336,54 @@ void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_u
}
void VisualShaderGraphPlugin::update_theme() {
- vector_expanded_color[0] = VisualShaderEditor::get_singleton()->get_theme_color(SNAME("axis_x_color"), SNAME("Editor")); // red
- vector_expanded_color[1] = VisualShaderEditor::get_singleton()->get_theme_color(SNAME("axis_y_color"), SNAME("Editor")); // green
- vector_expanded_color[2] = VisualShaderEditor::get_singleton()->get_theme_color(SNAME("axis_z_color"), SNAME("Editor")); // blue
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (!editor) {
+ return;
+ }
+ vector_expanded_color[0] = editor->get_theme_color(SNAME("axis_x_color"), SNAME("Editor")); // red
+ vector_expanded_color[1] = editor->get_theme_color(SNAME("axis_y_color"), SNAME("Editor")); // green
+ vector_expanded_color[2] = editor->get_theme_color(SNAME("axis_z_color"), SNAME("Editor")); // blue
+ vector_expanded_color[3] = editor->get_theme_color(SNAME("axis_w_color"), SNAME("Editor")); // alpha
}
void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
- if (p_type != visual_shader->get_shader_type()) {
+ if (!visual_shader.is_valid() || p_type != visual_shader->get_shader_type()) {
+ return;
+ }
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (!editor) {
return;
}
+ GraphEdit *graph = editor->graph;
+ if (!graph) {
+ return;
+ }
+ VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();
+ if (!graph_plugin) {
+ return;
+ }
+ Shader::Mode mode = visual_shader->get_mode();
Control *offset;
static Ref<StyleBoxEmpty> label_style = make_empty_stylebox(2, 1, 2, 1);
- static const Color type_color[6] = {
+ static const Color type_color[] = {
Color(0.38, 0.85, 0.96), // scalar (float)
Color(0.49, 0.78, 0.94), // scalar (int)
- Color(0.84, 0.49, 0.93), // vector
+ Color(0.74, 0.57, 0.95), // vector2
+ Color(0.84, 0.49, 0.93), // vector3
+ Color(1.0, 0.125, 0.95), // vector4
Color(0.55, 0.65, 0.94), // boolean
Color(0.96, 0.66, 0.43), // transform
Color(1.0, 1.0, 0.0), // sampler
};
- static const String vector_expanded_name[3] = {
+ static const String vector_expanded_name[4] = {
"red",
"green",
- "blue"
+ "blue",
+ "alpha"
};
Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);
@@ -370,13 +407,15 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
}
GraphNode *node = memnew(GraphNode);
+ graph->add_child(node);
+ editor->_update_created_node(node);
register_link(p_type, p_id, vsnode.ptr(), node);
if (is_resizable) {
size = resizable_node->get_size();
node->set_resizable(true);
- node->connect("resize_request", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_node_resized), varray((int)p_type, p_id));
+ node->connect("resize_request", callable_mp(editor, &VisualShaderEditor::_node_resized), varray((int)p_type, p_id));
}
if (is_expression) {
expression = expression_node->get_expression();
@@ -388,10 +427,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (p_id >= 2) {
node->set_show_close_button(true);
- node->connect("close_request", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_delete_node_request), varray(p_type, p_id), CONNECT_DEFERRED);
+ node->connect("close_request", callable_mp(editor, &VisualShaderEditor::_delete_node_request), varray(p_type, p_id), CONNECT_DEFERRED);
}
- node->connect("dragged", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_node_dragged), varray(p_id));
+ node->connect("dragged", callable_mp(editor, &VisualShaderEditor::_node_dragged), varray(p_id));
Control *custom_editor = nullptr;
int port_offset = 1;
@@ -416,6 +455,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
comment_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
comment_label->set_text(comment_node->get_description());
}
+ editor->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size);
}
Ref<VisualShaderNodeParticleEmit> emit = vsnode;
@@ -424,32 +464,30 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
}
Ref<VisualShaderNodeUniform> uniform = vsnode;
- if (uniform.is_valid()) {
- VisualShaderEditor::get_singleton()->graph->add_child(node);
- VisualShaderEditor::get_singleton()->_update_created_node(node);
+ HBoxContainer *hb = nullptr;
+ if (uniform.is_valid()) {
LineEdit *uniform_name = memnew(LineEdit);
register_uniform_name(p_id, uniform_name);
+ uniform_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
uniform_name->set_text(uniform->get_uniform_name());
- node->add_child(uniform_name);
- uniform_name->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_changed), varray(p_id));
- uniform_name->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_focus_out), varray(uniform_name, p_id));
-
- if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
- //shortcut
- VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0);
- node->set_slot(1, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]);
- if (!vsnode->is_use_prop_slots()) {
- return;
- }
+ uniform_name->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_uniform_line_edit_changed), varray(p_id));
+ uniform_name->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_uniform_line_edit_focus_out), varray(uniform_name, p_id));
+
+ if (vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
+ hb = memnew(HBoxContainer);
+ hb->add_child(uniform_name);
+ node->add_child(hb);
+ } else {
+ node->add_child(uniform_name);
}
port_offset++;
}
- for (int i = 0; i < VisualShaderEditor::get_singleton()->plugins.size(); i++) {
+ for (int i = 0; i < editor->plugins.size(); i++) {
vsnode->set_meta("id", p_id);
vsnode->set_meta("shader_type", (int)p_type);
- custom_editor = VisualShaderEditor::get_singleton()->plugins.write[i]->create_editor(visual_shader, vsnode);
+ custom_editor = editor->plugins.write[i]->create_editor(visual_shader, vsnode);
vsnode->remove_meta("id");
vsnode->remove_meta("shader_type");
if (custom_editor) {
@@ -461,146 +499,76 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
}
Ref<VisualShaderNodeCurveTexture> curve = vsnode;
- if (curve.is_valid()) {
- if (curve->get_texture().is_valid() && !curve->get_texture()->is_connected("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve))) {
- curve->get_texture()->connect("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve), varray(p_id));
- }
-
- HBoxContainer *hbox = memnew(HBoxContainer);
- custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- hbox->add_child(custom_editor);
- custom_editor = hbox;
- }
-
Ref<VisualShaderNodeCurveXYZTexture> curve_xyz = vsnode;
- if (curve_xyz.is_valid()) {
- if (curve_xyz->get_texture().is_valid() && !curve_xyz->get_texture()->is_connected("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve_xyz))) {
- curve_xyz->get_texture()->connect("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve_xyz), varray(p_id));
- }
- HBoxContainer *hbox = memnew(HBoxContainer);
- custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- hbox->add_child(custom_editor);
- custom_editor = hbox;
+ bool is_curve = curve.is_valid() || curve_xyz.is_valid();
+ if (is_curve) {
+ hb = memnew(HBoxContainer);
+ node->add_child(hb);
}
- if (custom_editor && !vsnode->is_use_prop_slots() && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) {
- //will be embedded in first port
- } else if (custom_editor) {
- port_offset++;
- node->add_child(custom_editor);
-
- bool is_curve = curve.is_valid() || curve_xyz.is_valid();
-
- if (is_curve) {
- // a default value handling
- {
- Variant default_value;
- bool port_left_used = false;
-
- for (const VisualShader::Connection &E : connections) {
- if (E.to_node == p_id && E.to_port == 0) {
- port_left_used = true;
- break;
- }
- }
-
- if (!port_left_used) {
- default_value = vsnode->get_input_port_default_value(0);
- }
-
- Button *button = memnew(Button);
- custom_editor->add_child(button);
- register_default_input_button(p_id, 0, button);
- custom_editor->move_child(button, 0);
-
- button->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_edit_port_default_input), varray(button, p_id, 0));
- if (default_value.get_type() != Variant::NIL) {
- set_input_port_default_value(p_type, p_id, 0, default_value);
- } else {
- button->hide();
- }
- }
-
- VisualShaderEditor::get_singleton()->graph->add_child(node);
- VisualShaderEditor::get_singleton()->_update_created_node(node);
-
- TextureButton *preview = memnew(TextureButton);
- preview->set_toggle_mode(true);
- preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons")));
- preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
- preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
-
- register_output_port(p_id, 0, preview);
-
- preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, 0), CONNECT_DEFERRED);
- custom_editor->add_child(preview);
+ if (curve.is_valid()) {
+ custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- if (vsnode->get_output_port_for_preview() >= 0) {
- show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview());
- }
+ Callable ce = callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve);
+ if (curve->get_texture().is_valid() && !curve->get_texture()->is_connected("changed", ce)) {
+ curve->get_texture()->connect("changed", ce, varray(p_id));
}
- if (curve.is_valid()) {
- CurveEditor *curve_editor = memnew(CurveEditor);
- node->add_child(curve_editor);
- register_curve_editor(p_id, 0, curve_editor);
- curve_editor->set_custom_minimum_size(Size2(300, 0));
- curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- if (curve->get_texture().is_valid()) {
- curve_editor->set_curve(curve->get_texture()->get_curve());
- }
+ CurveEditor *curve_editor = memnew(CurveEditor);
+ node->add_child(curve_editor);
+ register_curve_editor(p_id, 0, curve_editor);
+ curve_editor->set_custom_minimum_size(Size2(300, 0));
+ curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ if (curve->get_texture().is_valid()) {
+ curve_editor->set_curve(curve->get_texture()->get_curve());
}
+ }
- if (curve_xyz.is_valid()) {
- CurveEditor *curve_editor_x = memnew(CurveEditor);
- node->add_child(curve_editor_x);
- register_curve_editor(p_id, 0, curve_editor_x);
- curve_editor_x->set_custom_minimum_size(Size2(300, 0));
- curve_editor_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- if (curve_xyz->get_texture().is_valid()) {
- curve_editor_x->set_curve(curve_xyz->get_texture()->get_curve_x());
- }
-
- CurveEditor *curve_editor_y = memnew(CurveEditor);
- node->add_child(curve_editor_y);
- register_curve_editor(p_id, 1, curve_editor_y);
- curve_editor_y->set_custom_minimum_size(Size2(300, 0));
- curve_editor_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- if (curve_xyz->get_texture().is_valid()) {
- curve_editor_y->set_curve(curve_xyz->get_texture()->get_curve_y());
- }
+ if (curve_xyz.is_valid()) {
+ custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- CurveEditor *curve_editor_z = memnew(CurveEditor);
- node->add_child(curve_editor_z);
- register_curve_editor(p_id, 2, curve_editor_z);
- curve_editor_z->set_custom_minimum_size(Size2(300, 0));
- curve_editor_z->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- if (curve_xyz->get_texture().is_valid()) {
- curve_editor_z->set_curve(curve_xyz->get_texture()->get_curve_z());
- }
+ Callable ce = callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve_xyz);
+ if (curve_xyz->get_texture().is_valid() && !curve_xyz->get_texture()->is_connected("changed", ce)) {
+ curve_xyz->get_texture()->connect("changed", ce, varray(p_id));
}
- if (is_curve) {
- VisualShaderNode::PortType port_left = vsnode->get_input_port_type(0);
- VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0);
- node->set_slot(1, true, port_left, type_color[port_left], true, port_right, type_color[port_right]);
+ CurveEditor *curve_editor_x = memnew(CurveEditor);
+ node->add_child(curve_editor_x);
+ register_curve_editor(p_id, 0, curve_editor_x);
+ curve_editor_x->set_custom_minimum_size(Size2(300, 0));
+ curve_editor_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ if (curve_xyz->get_texture().is_valid()) {
+ curve_editor_x->set_curve(curve_xyz->get_texture()->get_curve_x());
+ }
- VisualShaderEditor::get_singleton()->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size);
+ CurveEditor *curve_editor_y = memnew(CurveEditor);
+ node->add_child(curve_editor_y);
+ register_curve_editor(p_id, 1, curve_editor_y);
+ curve_editor_y->set_custom_minimum_size(Size2(300, 0));
+ curve_editor_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ if (curve_xyz->get_texture().is_valid()) {
+ curve_editor_y->set_curve(curve_xyz->get_texture()->get_curve_y());
}
- if (vsnode->is_use_prop_slots()) {
- String error = vsnode->get_warning(visual_shader->get_mode(), p_type);
- if (error != String()) {
- Label *error_label = memnew(Label);
- error_label->add_theme_color_override("font_color", VisualShaderEditor::get_singleton()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
- error_label->set_text(error);
- node->add_child(error_label);
- }
+ CurveEditor *curve_editor_z = memnew(CurveEditor);
+ node->add_child(curve_editor_z);
+ register_curve_editor(p_id, 2, curve_editor_z);
+ curve_editor_z->set_custom_minimum_size(Size2(300, 0));
+ curve_editor_z->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ if (curve_xyz->get_texture().is_valid()) {
+ curve_editor_z->set_curve(curve_xyz->get_texture()->get_curve_z());
+ }
+ }
- return;
+ if (custom_editor) {
+ if (is_curve || (hb == nullptr && !vsnode->is_use_prop_slots() && (vsnode->get_output_port_count() == 0 || vsnode->get_output_port_name(0) == "") && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == ""))) {
+ //will be embedded in first port
+ } else {
+ port_offset++;
+ node->add_child(custom_editor);
+ custom_editor = nullptr;
}
- custom_editor = nullptr;
}
if (is_group) {
@@ -625,14 +593,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Button *add_input_btn = memnew(Button);
add_input_btn->set_text(TTR("Add Input"));
- add_input_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_add_input_port), varray(p_id, group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, input_port_name), CONNECT_DEFERRED);
+ add_input_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_add_input_port), varray(p_id, group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR_3D, input_port_name), CONNECT_DEFERRED);
hb2->add_child(add_input_btn);
hb2->add_spacer();
Button *add_output_btn = memnew(Button);
add_output_btn->set_text(TTR("Add Output"));
- add_output_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_add_output_port), varray(p_id, group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, output_port_name), CONNECT_DEFERRED);
+ add_output_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_add_output_port), varray(p_id, group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR_3D, output_port_name), CONNECT_DEFERRED);
hb2->add_child(add_output_btn);
node->add_child(hb2);
@@ -642,8 +610,18 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
int output_port_count = 0;
for (int i = 0; i < vsnode->get_output_port_count(); i++) {
if (vsnode->_is_output_port_expanded(i)) {
- if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
- output_port_count += 3;
+ switch (vsnode->get_output_port_type(i)) {
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
+ output_port_count += 2;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
+ output_port_count += 3;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ output_port_count += 4;
+ } break;
+ default:
+ break;
}
}
output_port_count++;
@@ -653,10 +631,30 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
int expanded_port_counter = 0;
for (int i = 0, j = 0; i < max_ports; i++, j++) {
- if (expanded_type == VisualShaderNode::PORT_TYPE_VECTOR && expanded_port_counter >= 3) {
- expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
- expanded_port_counter = 0;
- i -= 3;
+ switch (expanded_type) {
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
+ if (expanded_port_counter >= 2) {
+ expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
+ expanded_port_counter = 0;
+ i -= 2;
+ }
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
+ if (expanded_port_counter >= 3) {
+ expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
+ expanded_port_counter = 0;
+ i -= 3;
+ }
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ if (expanded_port_counter >= 4) {
+ expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
+ expanded_port_counter = 0;
+ i -= 4;
+ }
+ } break;
+ default:
+ break;
}
if (vsnode->is_port_separator(i)) {
@@ -693,7 +691,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
name_right = vector_expanded_name[expanded_port_counter++];
}
- HBoxContainer *hb = memnew(HBoxContainer);
+ bool is_first_hbox = false;
+ if (i == 0 && hb != nullptr) {
+ is_first_hbox = true;
+ } else {
+ hb = memnew(HBoxContainer);
+ }
hb->add_theme_constant_override("separation", 7 * EDSCALE);
Variant default_value;
@@ -705,7 +708,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Button *button = memnew(Button);
hb->add_child(button);
register_default_input_button(p_id, i, button);
- button->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_edit_port_default_input), varray(button, p_id, i));
+ button->connect("pressed", callable_mp(editor, &VisualShaderEditor::_edit_port_default_input), varray(button, p_id, i));
if (default_value.get_type() != Variant::NIL) { // only a label
set_input_port_default_value(p_type, p_id, i, default_value);
} else {
@@ -722,26 +725,28 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
hb->add_child(type_box);
type_box->add_item(TTR("Float"));
type_box->add_item(TTR("Int"));
- type_box->add_item(TTR("Vector"));
+ type_box->add_item(TTR("Vector2"));
+ type_box->add_item(TTR("Vector3"));
+ type_box->add_item(TTR("Vector4"));
type_box->add_item(TTR("Boolean"));
type_box->add_item(TTR("Transform"));
type_box->add_item(TTR("Sampler"));
type_box->select(group_node->get_input_port_type(i));
type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- type_box->connect("item_selected", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_type), varray(p_id, i), CONNECT_DEFERRED);
+ type_box->connect("item_selected", callable_mp(editor, &VisualShaderEditor::_change_input_port_type), varray(p_id, i), CONNECT_DEFERRED);
LineEdit *name_box = memnew(LineEdit);
hb->add_child(name_box);
name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));
name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
name_box->set_text(name_left);
- name_box->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
- name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, false), CONNECT_DEFERRED);
+ name_box->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_change_input_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
+ name_box->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, false), CONNECT_DEFERRED);
Button *remove_btn = memnew(Button);
remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
- remove_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_remove_input_port), varray(p_id, i), CONNECT_DEFERRED);
+ remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_input_port), varray(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
} else {
Label *label = memnew(Label);
@@ -749,17 +754,17 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
label->add_theme_style_override("normal", label_style); //more compact
hb->add_child(label);
- if (vsnode->get_input_port_default_hint(i) != "" && !port_left_used) {
+ if (vsnode->is_input_port_default(i, mode) && !port_left_used) {
Label *hint_label = memnew(Label);
- hint_label->set_text("[" + vsnode->get_input_port_default_hint(i) + "]");
- hint_label->add_theme_color_override("font_color", VisualShaderEditor::get_singleton()->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit")));
+ hint_label->set_text(TTR("[default]"));
+ hint_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit")));
hint_label->add_theme_style_override("normal", label_style);
hb->add_child(hint_label);
}
}
}
- if (!is_group) {
+ if (!is_group && !is_first_hbox) {
hb->add_spacer();
}
@@ -768,7 +773,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Button *remove_btn = memnew(Button);
remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
- remove_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_remove_output_port), varray(p_id, i), CONNECT_DEFERRED);
+ remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_output_port), varray(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
LineEdit *name_box = memnew(LineEdit);
@@ -776,19 +781,21 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));
name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
name_box->set_text(name_right);
- name_box->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
- name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, true), CONNECT_DEFERRED);
+ name_box->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_change_output_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED);
+ name_box->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, true), CONNECT_DEFERRED);
OptionButton *type_box = memnew(OptionButton);
hb->add_child(type_box);
type_box->add_item(TTR("Float"));
type_box->add_item(TTR("Int"));
- type_box->add_item(TTR("Vector"));
+ type_box->add_item(TTR("Vector2"));
+ type_box->add_item(TTR("Vector3"));
+ type_box->add_item(TTR("Vector4"));
type_box->add_item(TTR("Boolean"));
type_box->add_item(TTR("Transform"));
type_box->select(group_node->get_output_port_type(i));
type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- type_box->connect("item_selected", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_type), varray(p_id, i), CONNECT_DEFERRED);
+ type_box->connect("item_selected", callable_mp(editor, &VisualShaderEditor::_change_output_port_type), varray(p_id, i), CONNECT_DEFERRED);
} else {
Label *label = memnew(Label);
label->set_text(name_right);
@@ -802,23 +809,23 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (vsnode->is_output_port_expandable(i)) {
TextureButton *expand = memnew(TextureButton);
expand->set_toggle_mode(true);
- expand->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons")));
- expand->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons")));
+ expand->set_normal_texture(editor->get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons")));
+ expand->set_pressed_texture(editor->get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons")));
expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
expand->set_pressed(vsnode->_is_output_port_expanded(i));
- expand->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_expand_output_port), varray(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED);
+ expand->connect("pressed", callable_mp(editor, &VisualShaderEditor::_expand_output_port), varray(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED);
hb->add_child(expand);
}
if (vsnode->has_output_port_preview(i) && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) {
TextureButton *preview = memnew(TextureButton);
preview->set_toggle_mode(true);
- preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons")));
- preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
+ preview->set_normal_texture(editor->get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons")));
+ preview->set_pressed_texture(editor->get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
register_output_port(p_id, j, preview);
- preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, j), CONNECT_DEFERRED);
+ preview->connect("pressed", callable_mp(editor, &VisualShaderEditor::_preview_select_port), varray(p_id, j), CONNECT_DEFERRED);
hb->add_child(preview);
}
}
@@ -830,40 +837,105 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
port_offset++;
}
- node->add_child(hb);
+ if (!is_first_hbox) {
+ node->add_child(hb);
+ }
if (expanded_type != VisualShaderNode::PORT_TYPE_SCALAR) {
continue;
}
- node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]);
+ int idx = 1;
+ if (!is_first_hbox) {
+ idx = i + port_offset;
+ }
+ node->set_slot(idx, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]);
if (vsnode->_is_output_port_expanded(i)) {
- if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) {
- port_offset++;
- valid_left = (i + 1) < vsnode->get_input_port_count();
- port_left = VisualShaderNode::PORT_TYPE_SCALAR;
- if (valid_left) {
- port_left = vsnode->get_input_port_type(i + 1);
- }
- node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
- port_offset++;
+ switch (vsnode->get_output_port_type(i)) {
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
+ port_offset++;
+ valid_left = (i + 1) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 1);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
+ port_offset++;
- valid_left = (i + 2) < vsnode->get_input_port_count();
- port_left = VisualShaderNode::PORT_TYPE_SCALAR;
- if (valid_left) {
- port_left = vsnode->get_input_port_type(i + 2);
- }
- node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
- port_offset++;
+ valid_left = (i + 2) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 2);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
+
+ expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_2D;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
+ port_offset++;
+ valid_left = (i + 1) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 1);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
+ port_offset++;
- valid_left = (i + 3) < vsnode->get_input_port_count();
- port_left = VisualShaderNode::PORT_TYPE_SCALAR;
- if (valid_left) {
- port_left = vsnode->get_input_port_type(i + 3);
- }
- node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);
- expanded_type = VisualShaderNode::PORT_TYPE_VECTOR;
+ valid_left = (i + 2) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 2);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
+ port_offset++;
+
+ valid_left = (i + 3) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 3);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);
+
+ expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_3D;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ port_offset++;
+ valid_left = (i + 1) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 1);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
+ port_offset++;
+
+ valid_left = (i + 2) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 2);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
+ port_offset++;
+
+ valid_left = (i + 3) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 3);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);
+ port_offset++;
+
+ valid_left = (i + 4) < vsnode->get_input_port_count();
+ port_left = VisualShaderNode::PORT_TYPE_SCALAR;
+ if (valid_left) {
+ port_left = vsnode->get_input_port_type(i + 4);
+ }
+ node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[3]);
+
+ expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_4D;
+ } break;
+ default:
+ break;
}
}
}
@@ -876,10 +948,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
node->add_child(offset);
- String error = vsnode->get_warning(visual_shader->get_mode(), p_type);
- if (error != String()) {
+ String error = vsnode->get_warning(mode, p_type);
+ if (!error.is_empty()) {
Label *error_label = memnew(Label);
- error_label->add_theme_color_override("font_color", VisualShaderEditor::get_singleton()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ error_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("error_color"), SNAME("Editor")));
error_label->set_text(error);
node->add_child(error_label);
}
@@ -905,7 +977,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
expression_box->set_syntax_highlighter(expression_syntax_highlighter);
expression_box->add_theme_color_override("background_color", background_color);
- for (const String &E : VisualShaderEditor::get_singleton()->keyword_list) {
+ for (const String &E : editor->keyword_list) {
if (ShaderLanguage::is_control_flow_keyword(E)) {
expression_syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);
} else {
@@ -913,8 +985,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
}
}
- expression_box->add_theme_font_override("font", VisualShaderEditor::get_singleton()->get_theme_font(SNAME("expression"), SNAME("EditorFonts")));
- expression_box->add_theme_font_size_override("font_size", VisualShaderEditor::get_singleton()->get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts")));
+ expression_box->add_theme_font_override("font", editor->get_theme_font(SNAME("expression"), SNAME("EditorFonts")));
+ expression_box->add_theme_font_size_override("font_size", editor->get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts")));
expression_box->add_theme_color_override("font_color", text_color);
expression_syntax_highlighter->set_number_color(number_color);
expression_syntax_highlighter->set_symbol_color(symbol_color);
@@ -935,18 +1007,11 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
expression_box->set_context_menu_enabled(false);
expression_box->set_draw_line_numbers(true);
- expression_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_expression_focus_out), varray(expression_box, p_id));
+ expression_box->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_expression_focus_out), varray(expression_box, p_id));
}
- if (!uniform.is_valid()) {
- VisualShaderEditor::get_singleton()->graph->add_child(node);
- if (is_comment) {
- VisualShaderEditor::get_singleton()->graph->move_child(node, 0); // to prevents a bug where comment node overlaps its content
- }
- VisualShaderEditor::get_singleton()->_update_created_node(node);
- if (is_resizable) {
- VisualShaderEditor::get_singleton()->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size);
- }
+ if (is_comment) {
+ graph->move_child(node, 0); // to prevents a bug where comment node overlaps its content
}
}
@@ -959,8 +1024,18 @@ void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id) {
}
void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
- if (visual_shader->get_shader_type() == p_type) {
- VisualShaderEditor::get_singleton()->graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (!editor) {
+ return;
+ }
+ GraphEdit *graph = editor->graph;
+ if (!graph) {
+ return;
+ }
+
+ if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) {
+ graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
+
connections.push_back({ p_from_node, p_from_port, p_to_node, p_to_port });
if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr) {
links[p_to_node].input_ports[p_to_port].default_input_button->hide();
@@ -969,8 +1044,18 @@ void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_fro
}
void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
- if (visual_shader->get_shader_type() == p_type) {
- VisualShaderEditor::get_singleton()->graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (!editor) {
+ return;
+ }
+ GraphEdit *graph = editor->graph;
+ if (!graph) {
+ return;
+ }
+
+ if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) {
+ graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
+
for (const List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {
if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
connections.erase(E);
@@ -1001,8 +1086,10 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
}
visual_shader = Ref<VisualShader>(p_visual_shader);
graph_plugin->register_shader(visual_shader.ptr());
- if (!visual_shader->is_connected("changed", callable_mp(this, &VisualShaderEditor::_update_preview))) {
- visual_shader->connect("changed", callable_mp(this, &VisualShaderEditor::_update_preview));
+
+ Callable ce = callable_mp(this, &VisualShaderEditor::_update_preview);
+ if (!visual_shader->is_connected("changed", ce)) {
+ visual_shader->connect("changed", ce);
}
#ifndef DISABLE_DEPRECATED
Dictionary engine_version = Engine::get_singleton()->get_version_info();
@@ -1029,8 +1116,9 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
_set_mode(visual_shader->get_mode());
} else {
if (visual_shader.is_valid()) {
- if (visual_shader->is_connected("changed", callable_mp(this, &VisualShaderEditor::_update_preview))) {
- visual_shader->disconnect("changed", callable_mp(this, &VisualShaderEditor::_update_preview));
+ Callable ce = callable_mp(this, &VisualShaderEditor::_update_preview);
+ if (visual_shader->is_connected("changed", ce)) {
+ visual_shader->disconnect("changed", ce);
}
}
visual_shader.unref();
@@ -1040,6 +1128,7 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
hide();
} else {
if (changed) { // to avoid tree collapse
+ _update_varying_tree();
_update_options_menu();
_update_preview();
_update_graph();
@@ -1047,8 +1136,12 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
}
}
+void VisualShaderEditor::update_nodes() {
+ _update_nodes();
+}
+
void VisualShaderEditor::add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {
- if (plugins.find(p_plugin) != -1) {
+ if (plugins.has(p_plugin)) {
return;
}
plugins.push_back(p_plugin);
@@ -1061,7 +1154,7 @@ void VisualShaderEditor::remove_plugin(const Ref<VisualShaderNodePlugin> &p_plug
void VisualShaderEditor::clear_custom_types() {
for (int i = 0; i < add_options.size(); i++) {
if (add_options[i].is_custom) {
- add_options.remove(i);
+ add_options.remove_at(i);
i--;
}
}
@@ -1130,10 +1223,7 @@ bool VisualShaderEditor::_is_available(int p_mode) {
return (p_mode == -1 || (p_mode & current_mode) != 0);
}
-void VisualShaderEditor::update_custom_nodes() {
- if (members_dialog->is_visible()) {
- return;
- }
+void VisualShaderEditor::_update_nodes() {
clear_custom_types();
List<StringName> class_list;
ScriptServer::get_global_class_list(&class_list);
@@ -1149,6 +1239,9 @@ void VisualShaderEditor::update_custom_nodes() {
Ref<VisualShaderNodeCustom> ref;
ref.instantiate();
ref->set_script(script);
+ if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
+ continue;
+ }
String name;
if (ref->has_method("_get_name")) {
@@ -1191,7 +1284,7 @@ void VisualShaderEditor::update_custom_nodes() {
category = category.rstrip("/");
category = category.lstrip("/");
category = "Addons/" + category;
- if (subcategory != "") {
+ if (!subcategory.is_empty()) {
category += "/" + subcategory;
}
@@ -1205,6 +1298,32 @@ void VisualShaderEditor::update_custom_nodes() {
}
}
+ // Disables not-supported copied items.
+ {
+ for (CopyItem &item : copy_items_buffer) {
+ Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(item.node.ptr());
+
+ if (custom.is_valid()) {
+ if (!custom->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
+ item.disabled = true;
+ } else {
+ item.disabled = false;
+ }
+ } else {
+ for (int i = 0; i < add_options.size(); i++) {
+ if (add_options[i].type == item.node->get_class_name()) {
+ if ((add_options[i].func != visual_shader->get_mode() && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {
+ item.disabled = true;
+ } else {
+ item.disabled = false;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
Array keys = added.keys();
keys.sort();
@@ -1277,7 +1396,9 @@ void VisualShaderEditor::_update_options_menu() {
if (input.is_valid()) {
input->set_shader_mode(visual_shader->get_mode());
input->set_shader_type(visual_shader->get_shader_type());
- input->set_input_name(add_options[i].sub_func_str);
+ if (!add_options[i].ops.is_empty() && add_options[i].ops[0].get_type() == Variant::STRING) {
+ input->set_input_name((String)add_options[i].ops[0]);
+ }
}
Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(vsn.ptr());
@@ -1394,9 +1515,15 @@ void VisualShaderEditor::_update_options_menu() {
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), SNAME("EditorIcons")));
break;
- case VisualShaderNode::PORT_TYPE_VECTOR:
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")));
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")));
break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")));
+ break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), SNAME("EditorIcons")));
break;
@@ -1421,6 +1548,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_fog->set_visible(false);
edit_type = edit_type_sky;
custom_mode_box->set_visible(false);
+ varying_button->hide();
mode = MODE_FLAGS_SKY;
} else if (p_which == VisualShader::MODE_FOG) {
edit_type_standard->set_visible(false);
@@ -1429,6 +1557,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_fog->set_visible(true);
edit_type = edit_type_fog;
custom_mode_box->set_visible(false);
+ varying_button->hide();
mode = MODE_FLAGS_FOG;
} else if (p_which == VisualShader::MODE_PARTICLES) {
edit_type_standard->set_visible(false);
@@ -1441,6 +1570,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
} else {
custom_mode_box->set_visible(true);
}
+ varying_button->hide();
mode = MODE_FLAGS_PARTICLES;
} else {
edit_type_particles->set_visible(false);
@@ -1449,6 +1579,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_fog->set_visible(false);
edit_type = edit_type_standard;
custom_mode_box->set_visible(false);
+ varying_button->show();
mode = MODE_FLAGS_SPATIAL_CANVASITEM;
}
visual_shader->set_shader_type(get_current_shader_type());
@@ -1492,7 +1623,9 @@ void VisualShaderEditor::_update_uniforms(bool p_update_refs) {
if (uniform.is_valid()) {
Ref<VisualShaderNodeFloatUniform> float_uniform = vsnode;
Ref<VisualShaderNodeIntUniform> int_uniform = vsnode;
+ Ref<VisualShaderNodeVec2Uniform> vec2_uniform = vsnode;
Ref<VisualShaderNodeVec3Uniform> vec3_uniform = vsnode;
+ Ref<VisualShaderNodeVec4Uniform> vec4_uniform = vsnode;
Ref<VisualShaderNodeColorUniform> color_uniform = vsnode;
Ref<VisualShaderNodeBooleanUniform> bool_uniform = vsnode;
Ref<VisualShaderNodeTransformUniform> transform_uniform = vsnode;
@@ -1504,8 +1637,12 @@ void VisualShaderEditor::_update_uniforms(bool p_update_refs) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_INT;
} else if (bool_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_BOOLEAN;
+ } else if (vec2_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR2;
} else if (vec3_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR;
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR3;
+ } else if (vec4_uniform.is_valid()) {
+ uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR4;
} else if (transform_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_TRANSFORM;
} else if (color_uniform.is_valid()) {
@@ -1574,6 +1711,7 @@ void VisualShaderEditor::_update_graph() {
Vector<int> nodes = visual_shader->get_node_list(type);
_update_uniforms(false);
+ _update_varyings();
graph_plugin->clear_links();
graph_plugin->make_dirty(true);
@@ -1687,7 +1825,7 @@ void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p
ERR_FAIL_COND(!line_edit);
String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, false);
- if (validated_name == String() || prev_name == validated_name) {
+ if (validated_name.is_empty() || prev_name == validated_name) {
line_edit->set_text(node->get_input_port_name(p_port_id));
return;
}
@@ -1695,8 +1833,6 @@ void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p
undo_redo->create_action(TTR("Change Input Port Name"));
undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, validated_name);
undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id));
- undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node_id);
- undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node_id);
undo_redo->commit_action();
}
@@ -1715,7 +1851,7 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *
ERR_FAIL_COND(!line_edit);
String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, true);
- if (validated_name == String() || prev_name == validated_name) {
+ if (validated_name.is_empty() || prev_name == validated_name) {
line_edit->set_text(node->get_output_port_name(p_port_id));
return;
}
@@ -1723,8 +1859,6 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *
undo_redo->create_action(TTR("Change Output Port Name"));
undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, validated_name);
undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, prev_name);
- undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node_id);
- undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node_id);
undo_redo->commit_action();
}
@@ -1744,8 +1878,18 @@ void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expa
undo_redo->add_undo_method(node.ptr(), "_set_output_port_expanded", p_port, !p_expand);
int type_size = 0;
- if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_VECTOR) {
- type_size = 3;
+ switch (node->get_output_port_type(p_port)) {
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
+ type_size = 2;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
+ type_size = 3;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ type_size = 4;
+ } break;
+ default:
+ break;
}
List<VisualShader::Connection> conns;
@@ -1976,21 +2120,19 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
}
gn->set_custom_minimum_size(size);
- gn->set_size(Size2(1, 1));
+ gn->reset_size();
if (!expression_node.is_null() && text_box) {
Size2 box_size = size;
- if (gn != nullptr) {
- if (box_size.x < 150 * EDSCALE || box_size.y < 0) {
- box_size.x = gn->get_size().x;
- }
+ if (box_size.x < 150 * EDSCALE || box_size.y < 0) {
+ box_size.x = gn->get_size().x;
}
box_size.x -= text_box->get_offset(SIDE_LEFT);
box_size.x -= 28 * EDSCALE;
box_size.y -= text_box->get_offset(SIDE_TOP);
box_size.y -= 28 * EDSCALE;
text_box->set_custom_minimum_size(box_size);
- text_box->set_size(Size2(1, 1));
+ text_box->reset_size();
}
}
}
@@ -2038,8 +2180,8 @@ void VisualShaderEditor::_comment_title_popup_show(const Point2 &p_position, int
}
void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) {
- comment_title_change_edit->set_size(Size2(-1, -1));
- comment_title_change_popup->set_size(Size2(-1, -1));
+ comment_title_change_edit->reset_size();
+ comment_title_change_popup->reset_size();
}
void VisualShaderEditor::_comment_title_text_submitted(const String &p_new_text) {
@@ -2078,13 +2220,14 @@ void VisualShaderEditor::_comment_desc_popup_show(const Point2 &p_position, int
}
comment_desc_change_edit->set_text(node->get_description());
comment_desc_change_popup->set_meta("id", p_node_id);
+ comment_desc_change_popup->reset_size();
comment_desc_change_popup->popup();
comment_desc_change_popup->set_position(p_position);
}
void VisualShaderEditor::_comment_desc_text_changed() {
- comment_desc_change_edit->set_size(Size2(-1, -1));
- comment_desc_change_popup->set_size(Size2(-1, -1));
+ comment_desc_change_edit->reset_size();
+ comment_desc_change_popup->reset_size();
}
void VisualShaderEditor::_comment_desc_confirm() {
@@ -2192,13 +2335,36 @@ void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node,
editing_port = p_port;
}
-void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
+void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, const Vector<Variant> &p_ops) {
+ // INPUT
+ {
+ VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(p_node);
+
+ if (input) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::STRING);
+ input->set_input_name((String)p_ops[0]);
+ return;
+ }
+ }
+
+ // FLOAT_CONST
+ {
+ VisualShaderNodeFloatConstant *float_const = Object::cast_to<VisualShaderNodeFloatConstant>(p_node);
+
+ if (float_const) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::FLOAT);
+ float_const->set_constant((float)p_ops[0]);
+ return;
+ }
+ }
+
// FLOAT_OP
{
VisualShaderNodeFloatOp *floatOp = Object::cast_to<VisualShaderNodeFloatOp>(p_node);
if (floatOp) {
- floatOp->set_operator((VisualShaderNodeFloatOp::Operator)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ floatOp->set_operator((VisualShaderNodeFloatOp::Operator)(int)p_ops[0]);
return;
}
}
@@ -2208,7 +2374,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeFloatFunc *floatFunc = Object::cast_to<VisualShaderNodeFloatFunc>(p_node);
if (floatFunc) {
- floatFunc->set_function((VisualShaderNodeFloatFunc::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ floatFunc->set_function((VisualShaderNodeFloatFunc::Function)(int)p_ops[0]);
return;
}
}
@@ -2218,7 +2385,10 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeVectorOp *vecOp = Object::cast_to<VisualShaderNodeVectorOp>(p_node);
if (vecOp) {
- vecOp->set_operator((VisualShaderNodeVectorOp::Operator)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);
+ vecOp->set_operator((VisualShaderNodeVectorOp::Operator)(int)p_ops[0]);
+ vecOp->set_op_type((VisualShaderNodeVectorOp::OpType)(int)p_ops[1]);
return;
}
}
@@ -2228,7 +2398,10 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeVectorFunc *vecFunc = Object::cast_to<VisualShaderNodeVectorFunc>(p_node);
if (vecFunc) {
- vecFunc->set_function((VisualShaderNodeVectorFunc::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);
+ vecFunc->set_function((VisualShaderNodeVectorFunc::Function)(int)p_ops[0]);
+ vecFunc->set_op_type((VisualShaderNodeVectorFunc::OpType)(int)p_ops[1]);
return;
}
}
@@ -2238,7 +2411,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeColorOp *colorOp = Object::cast_to<VisualShaderNodeColorOp>(p_node);
if (colorOp) {
- colorOp->set_operator((VisualShaderNodeColorOp::Operator)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ colorOp->set_operator((VisualShaderNodeColorOp::Operator)(int)p_ops[0]);
return;
}
}
@@ -2248,7 +2422,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeColorFunc *colorFunc = Object::cast_to<VisualShaderNodeColorFunc>(p_node);
if (colorFunc) {
- colorFunc->set_function((VisualShaderNodeColorFunc::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ colorFunc->set_function((VisualShaderNodeColorFunc::Function)(int)p_ops[0]);
return;
}
}
@@ -2258,7 +2433,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeIntOp *intOp = Object::cast_to<VisualShaderNodeIntOp>(p_node);
if (intOp) {
- intOp->set_operator((VisualShaderNodeIntOp::Operator)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ intOp->set_operator((VisualShaderNodeIntOp::Operator)(int)p_ops[0]);
return;
}
}
@@ -2268,7 +2444,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeIntFunc *intFunc = Object::cast_to<VisualShaderNodeIntFunc>(p_node);
if (intFunc) {
- intFunc->set_function((VisualShaderNodeIntFunc::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ intFunc->set_function((VisualShaderNodeIntFunc::Function)(int)p_ops[0]);
return;
}
}
@@ -2278,7 +2455,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeTransformOp *matOp = Object::cast_to<VisualShaderNodeTransformOp>(p_node);
if (matOp) {
- matOp->set_operator((VisualShaderNodeTransformOp::Operator)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ matOp->set_operator((VisualShaderNodeTransformOp::Operator)(int)p_ops[0]);
return;
}
}
@@ -2288,17 +2466,41 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeTransformFunc *matFunc = Object::cast_to<VisualShaderNodeTransformFunc>(p_node);
if (matFunc) {
- matFunc->set_function((VisualShaderNodeTransformFunc::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ matFunc->set_function((VisualShaderNodeTransformFunc::Function)(int)p_ops[0]);
return;
}
}
- //UV_FUNC
+ // VECTOR_COMPOSE
+ {
+ VisualShaderNodeVectorCompose *vecCompose = Object::cast_to<VisualShaderNodeVectorCompose>(p_node);
+
+ if (vecCompose) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ vecCompose->set_op_type((VisualShaderNodeVectorCompose::OpType)(int)p_ops[0]);
+ return;
+ }
+ }
+
+ // VECTOR_DECOMPOSE
+ {
+ VisualShaderNodeVectorDecompose *vecDecompose = Object::cast_to<VisualShaderNodeVectorDecompose>(p_node);
+
+ if (vecDecompose) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ vecDecompose->set_op_type((VisualShaderNodeVectorDecompose::OpType)(int)p_ops[0]);
+ return;
+ }
+ }
+
+ // UV_FUNC
{
VisualShaderNodeUVFunc *uvFunc = Object::cast_to<VisualShaderNodeUVFunc>(p_node);
if (uvFunc) {
- uvFunc->set_function((VisualShaderNodeUVFunc::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ uvFunc->set_function((VisualShaderNodeUVFunc::Function)(int)p_ops[0]);
return;
}
}
@@ -2308,7 +2510,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(p_node);
if (is) {
- is->set_function((VisualShaderNodeIs::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ is->set_function((VisualShaderNodeIs::Function)(int)p_ops[0]);
return;
}
}
@@ -2318,24 +2521,32 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeCompare *cmp = Object::cast_to<VisualShaderNodeCompare>(p_node);
if (cmp) {
- cmp->set_function((VisualShaderNodeCompare::Function)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ cmp->set_function((VisualShaderNodeCompare::Function)(int)p_ops[0]);
return;
}
}
- // DERIVATIVE
+ // DISTANCE
{
- VisualShaderNodeScalarDerivativeFunc *sderFunc = Object::cast_to<VisualShaderNodeScalarDerivativeFunc>(p_node);
+ VisualShaderNodeVectorDistance *dist = Object::cast_to<VisualShaderNodeVectorDistance>(p_node);
- if (sderFunc) {
- sderFunc->set_function((VisualShaderNodeScalarDerivativeFunc::Function)p_op_idx);
+ if (dist) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ dist->set_op_type((VisualShaderNodeVectorDistance::OpType)(int)p_ops[0]);
return;
}
+ }
- VisualShaderNodeVectorDerivativeFunc *vderFunc = Object::cast_to<VisualShaderNodeVectorDerivativeFunc>(p_node);
+ // DERIVATIVE
+ {
+ VisualShaderNodeDerivativeFunc *derFunc = Object::cast_to<VisualShaderNodeDerivativeFunc>(p_node);
- if (vderFunc) {
- vderFunc->set_function((VisualShaderNodeVectorDerivativeFunc::Function)p_op_idx);
+ if (derFunc) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);
+ derFunc->set_function((VisualShaderNodeDerivativeFunc::Function)(int)p_ops[0]);
+ derFunc->set_op_type((VisualShaderNodeDerivativeFunc::OpType)(int)p_ops[1]);
return;
}
}
@@ -2345,7 +2556,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeMix *mix = Object::cast_to<VisualShaderNodeMix>(p_node);
if (mix) {
- mix->set_op_type((VisualShaderNodeMix::OpType)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ mix->set_op_type((VisualShaderNodeMix::OpType)(int)p_ops[0]);
return;
}
}
@@ -2355,7 +2567,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeClamp *clampFunc = Object::cast_to<VisualShaderNodeClamp>(p_node);
if (clampFunc) {
- clampFunc->set_op_type((VisualShaderNodeClamp::OpType)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ clampFunc->set_op_type((VisualShaderNodeClamp::OpType)(int)p_ops[0]);
return;
}
}
@@ -2365,7 +2578,28 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeSwitch *switchFunc = Object::cast_to<VisualShaderNodeSwitch>(p_node);
if (switchFunc) {
- switchFunc->set_op_type((VisualShaderNodeSwitch::OpType)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ switchFunc->set_op_type((VisualShaderNodeSwitch::OpType)(int)p_ops[0]);
+ return;
+ }
+ }
+
+ // FACEFORWARD
+ {
+ VisualShaderNodeFaceForward *faceForward = Object::cast_to<VisualShaderNodeFaceForward>(p_node);
+ if (faceForward) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ faceForward->set_op_type((VisualShaderNodeFaceForward::OpType)(int)p_ops[0]);
+ return;
+ }
+ }
+
+ // LENGTH
+ {
+ VisualShaderNodeVectorLen *length = Object::cast_to<VisualShaderNodeVectorLen>(p_node);
+ if (length) {
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ length->set_op_type((VisualShaderNodeVectorLen::OpType)(int)p_ops[0]);
return;
}
}
@@ -2375,7 +2609,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeSmoothStep *smoothStepFunc = Object::cast_to<VisualShaderNodeSmoothStep>(p_node);
if (smoothStepFunc) {
- smoothStepFunc->set_op_type((VisualShaderNodeSmoothStep::OpType)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ smoothStepFunc->set_op_type((VisualShaderNodeSmoothStep::OpType)(int)p_ops[0]);
return;
}
}
@@ -2385,7 +2620,8 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeStep *stepFunc = Object::cast_to<VisualShaderNodeStep>(p_node);
if (stepFunc) {
- stepFunc->set_op_type((VisualShaderNodeStep::OpType)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ stepFunc->set_op_type((VisualShaderNodeStep::OpType)(int)p_ops[0]);
return;
}
}
@@ -2395,12 +2631,13 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) {
VisualShaderNodeMultiplyAdd *fmaFunc = Object::cast_to<VisualShaderNodeMultiplyAdd>(p_node);
if (fmaFunc) {
- fmaFunc->set_op_type((VisualShaderNodeMultiplyAdd::OpType)p_op_idx);
+ ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
+ fmaFunc->set_op_type((VisualShaderNodeMultiplyAdd::OpType)(int)p_ops[0]);
}
}
}
-void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_path, int p_node_idx) {
+void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, String p_resource_path, int p_node_idx) {
ERR_FAIL_INDEX(p_idx, add_options.size());
VisualShader::Type type = get_current_shader_type();
@@ -2409,28 +2646,12 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
bool is_custom = add_options[p_idx].is_custom;
- if (!is_custom && add_options[p_idx].type != String()) {
+ if (!is_custom && !add_options[p_idx].type.is_empty()) {
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[p_idx].type));
ERR_FAIL_COND(!vsn);
-
- VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn);
-
- if (constant) {
- if ((int)add_options[p_idx].value != -1) {
- constant->set_constant(add_options[p_idx].value);
- }
- } else {
- if (p_op_idx != -1) {
- VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsn);
-
- if (input) {
- input->set_input_name(add_options[p_idx].sub_func_str);
- } else {
- _setup_node(vsn, p_op_idx);
- }
- }
+ if (!p_ops.is_empty()) {
+ _setup_node(vsn, p_ops);
}
-
VisualShaderNodeUniformRef *uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(vsn);
if (uniform_ref && to_node != -1 && to_slot != -1) {
@@ -2457,13 +2678,21 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
vsnode = Ref<VisualShaderNode>(vsn);
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
- String base_type = add_options[p_idx].script->get_instance_base_type();
+ StringName base_type = add_options[p_idx].script->get_instance_base_type();
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));
ERR_FAIL_COND(!vsn);
vsnode = Ref<VisualShaderNode>(vsn);
vsnode->set_script(add_options[p_idx].script);
}
+ bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr);
+ bool is_texture3d = (Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr()) != nullptr);
+ bool is_texture2d_array = (Object::cast_to<VisualShaderNodeTexture2DArray>(vsnode.ptr()) != nullptr);
+ bool is_cubemap = (Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr()) != nullptr);
+ bool is_curve = (Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr()) != nullptr);
+ bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr);
+ bool is_uniform = (Object::cast_to<VisualShaderNodeUniform>(vsnode.ptr()) != nullptr);
+
Point2 position = graph->get_scroll_ofs();
if (saved_node_pos_dirty) {
@@ -2510,9 +2739,15 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
initial_expression_code = "output0 = 1;";
break;
- case VisualShaderNode::PORT_TYPE_VECTOR:
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D:
+ initial_expression_code = "output0 = vec2(1.0, 1.0);";
+ break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D:
initial_expression_code = "output0 = vec3(1.0, 1.0, 1.0);";
break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D:
+ initial_expression_code = "output0 = vec4(1.0, 1.0, 1.0, 1.0);";
+ break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
initial_expression_code = "output0 = true;";
break;
@@ -2530,9 +2765,9 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
}
if (vsnode->get_output_port_count() > 0 || created_expression_port) {
int _from_node = id_to_use;
- int _from_slot = 0;
if (created_expression_port) {
+ int _from_slot = 0;
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);
undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);
@@ -2570,9 +2805,9 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
if (vsnode->get_input_port_count() > 0 || created_expression_port) {
int _to_node = id_to_use;
- int _to_slot = 0;
if (created_expression_port) {
+ int _to_slot = 0;
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
@@ -2589,23 +2824,32 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
}
}
}
+
+ if (output_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
+ if (is_texture2d) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeTexture::SOURCE_PORT);
+ }
+ if (is_texture3d || is_texture2d_array) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeSample3D::SOURCE_PORT);
+ }
+ if (is_cubemap) {
+ undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeCubemap::SOURCE_PORT);
+ }
+ }
}
}
_member_cancel();
- VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(vsnode.ptr());
- if (uniform) {
+ if (is_uniform) {
undo_redo->add_do_method(this, "_update_uniforms", true);
undo_redo->add_undo_method(this, "_update_uniforms", true);
}
- VisualShaderNodeCurveTexture *curve = Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr());
- if (curve) {
+ if (is_curve) {
graph_plugin->call_deferred(SNAME("update_curve"), id_to_use);
}
- VisualShaderNodeCurveXYZTexture *curve_xyz = Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr());
- if (curve_xyz) {
+ if (is_curve_xyz) {
graph_plugin->call_deferred(SNAME("update_curve_xyz"), id_to_use);
}
@@ -2614,27 +2858,132 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
} else {
//post-initialization
- VisualShaderNodeTexture *texture2d = Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr());
- VisualShaderNodeTexture3D *texture3d = Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr());
-
- if (texture2d || texture3d || curve || curve_xyz) {
+ if (is_texture2d || is_texture3d || is_curve || is_curve_xyz) {
undo_redo->add_do_method(vsnode.ptr(), "set_texture", ResourceLoader::load(p_resource_path));
return;
}
- VisualShaderNodeCubemap *cubemap = Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr());
- if (cubemap) {
+ if (is_cubemap) {
undo_redo->add_do_method(vsnode.ptr(), "set_cube_map", ResourceLoader::load(p_resource_path));
return;
}
- VisualShaderNodeTexture2DArray *texture2d_array = Object::cast_to<VisualShaderNodeTexture2DArray>(vsnode.ptr());
- if (texture2d_array) {
+ if (is_texture2d_array) {
undo_redo->add_do_method(vsnode.ptr(), "set_texture_array", ResourceLoader::load(p_resource_path));
}
}
}
+void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) {
+ undo_redo->create_action(vformat(TTR("Add Varying to Visual Shader: %s"), p_name));
+
+ undo_redo->add_do_method(visual_shader.ptr(), "add_varying", p_name, p_mode, p_type);
+ undo_redo->add_undo_method(visual_shader.ptr(), "remove_varying", p_name);
+
+ undo_redo->add_do_method(this, "_update_varyings");
+ undo_redo->add_undo_method(this, "_update_varyings");
+
+ for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {
+ if (p_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {
+ continue;
+ }
+
+ VisualShader::Type type = VisualShader::Type(i);
+ Vector<int> nodes = visual_shader->get_node_list(type);
+
+ for (int j = 0; j < nodes.size(); j++) {
+ int node_id = nodes[j];
+ Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
+ Ref<VisualShaderNodeVarying> var = vsnode;
+
+ if (var.is_valid()) {
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);
+ }
+ }
+ }
+
+ undo_redo->add_do_method(this, "_update_varying_tree");
+ undo_redo->add_undo_method(this, "_update_varying_tree");
+ undo_redo->commit_action();
+}
+
+void VisualShaderEditor::_remove_varying(const String &p_name) {
+ undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name));
+
+ VisualShader::VaryingMode mode = visual_shader->get_varying_mode(p_name);
+
+ undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", p_name);
+ undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", p_name, mode, visual_shader->get_varying_type(p_name));
+
+ undo_redo->add_do_method(this, "_update_varyings");
+ undo_redo->add_undo_method(this, "_update_varyings");
+
+ for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {
+ if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {
+ continue;
+ }
+
+ VisualShader::Type type = VisualShader::Type(i);
+ Vector<int> nodes = visual_shader->get_node_list(type);
+
+ for (int j = 0; j < nodes.size(); j++) {
+ int node_id = nodes[j];
+ Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
+ Ref<VisualShaderNodeVarying> var = vsnode;
+
+ if (var.is_valid()) {
+ String var_name = var->get_varying_name();
+
+ if (var_name == p_name) {
+ undo_redo->add_do_method(var.ptr(), "set_varying_name", "[None]");
+ undo_redo->add_undo_method(var.ptr(), "set_varying_name", var_name);
+ undo_redo->add_do_method(var.ptr(), "set_varying_type", VisualShader::VARYING_TYPE_FLOAT);
+ undo_redo->add_undo_method(var.ptr(), "set_varying_type", var->get_varying_type());
+ }
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);
+ }
+ }
+
+ List<VisualShader::Connection> connections;
+ visual_shader->get_node_connections(type, &connections);
+
+ for (VisualShader::Connection &E : connections) {
+ Ref<VisualShaderNodeVaryingGetter> var_getter = Object::cast_to<VisualShaderNodeVaryingGetter>(visual_shader->get_node(type, E.from_node).ptr());
+ if (var_getter.is_valid() && E.from_port > 0) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ }
+ Ref<VisualShaderNodeVaryingSetter> var_setter = Object::cast_to<VisualShaderNodeVaryingSetter>(visual_shader->get_node(type, E.to_node).ptr());
+ if (var_setter.is_valid() && E.to_port > 0) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ }
+ }
+ }
+
+ undo_redo->add_do_method(this, "_update_varying_tree");
+ undo_redo->add_undo_method(this, "_update_varying_tree");
+ undo_redo->commit_action();
+}
+
+void VisualShaderEditor::_update_varyings() {
+ VisualShaderNodeVarying::clear_varyings();
+
+ for (int i = 0; i < visual_shader->get_varyings_count(); i++) {
+ const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);
+
+ if (var != nullptr) {
+ VisualShaderNodeVarying::add_varying(var->name, var->mode, var->type);
+ }
+ }
+}
+
void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node) {
VisualShader::Type type = get_current_shader_type();
drag_buffer.push_back({ type, p_node, p_from, p_to });
@@ -2916,6 +3265,25 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
}
}
+ // vec2
+ if (!caught) {
+ if (!p_vice_versa) {
+ Ref<VisualShaderNodeVec2Constant> vec2_const = Object::cast_to<VisualShaderNodeVec2Constant>(node.ptr());
+ if (vec2_const.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Uniform");
+ var = vec2_const->get_constant();
+ caught = true;
+ }
+ } else {
+ Ref<VisualShaderNodeVec2Uniform> vec2_uniform = Object::cast_to<VisualShaderNodeVec2Uniform>(node.ptr());
+ if (vec2_uniform.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Uniform", "VisualShaderNodeVec2Constant");
+ var = vec2_uniform->get_default_value();
+ caught = true;
+ }
+ }
+ }
+
// vec3
if (!caught) {
if (!p_vice_versa) {
@@ -2935,6 +3303,25 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
}
}
+ // vec4
+ if (!caught) {
+ if (!p_vice_versa) {
+ Ref<VisualShaderNodeVec4Constant> vec4_const = Object::cast_to<VisualShaderNodeVec4Constant>(node.ptr());
+ if (vec4_const.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Uniform");
+ var = vec4_const->get_constant();
+ caught = true;
+ }
+ } else {
+ Ref<VisualShaderNodeVec4Uniform> vec4_uniform = Object::cast_to<VisualShaderNodeVec4Uniform>(node.ptr());
+ if (vec4_uniform.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Uniform", "VisualShaderNodeVec4Constant");
+ var = vec4_uniform->get_default_value();
+ caught = true;
+ }
+ }
+ }
+
// color
if (!caught) {
if (!p_vice_versa) {
@@ -3051,7 +3438,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
VisualShader::Type type = get_current_shader_type();
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
selected_constants.clear();
selected_uniforms.clear();
selected_comment = -1;
@@ -3092,15 +3479,23 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
selected_float_constant = -1;
}
- if (to_change.is_empty() && copy_items_buffer.is_empty()) {
+ bool copy_buffer_empty = true;
+ for (const CopyItem &item : copy_items_buffer) {
+ if (!item.disabled) {
+ copy_buffer_empty = false;
+ break;
+ }
+ }
+
+ if (to_change.is_empty() && copy_buffer_empty) {
_show_members_dialog(true);
} else {
popup_menu->set_item_disabled(NodeMenuOptions::CUT, to_change.is_empty());
popup_menu->set_item_disabled(NodeMenuOptions::COPY, to_change.is_empty());
- popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_items_buffer.is_empty());
+ popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_buffer_empty);
popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.is_empty());
popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.is_empty());
- popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_items_buffer.is_empty());
+ popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_buffer_empty);
int temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR2);
if (temp != -1) {
@@ -3165,9 +3560,9 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
}
menu_point = graph->get_local_mouse_position();
- Point2 gpos = Input::get_singleton()->get_mouse_position();
+ Point2 gpos = get_screen_position() + get_local_mouse_position();
popup_menu->set_position(gpos);
- popup_menu->set_size(Size2(-1, -1));
+ popup_menu->reset_size();
popup_menu->popup();
}
}
@@ -3184,120 +3579,170 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNod
saved_node_pos_dirty = true;
saved_node_pos = graph->get_local_mouse_position();
- Point2 gpos = Input::get_singleton()->get_mouse_position();
- members_dialog->popup();
+ Point2 gpos = get_screen_position() + get_local_mouse_position();
members_dialog->set_position(gpos);
} else {
- members_dialog->popup();
saved_node_pos_dirty = false;
- members_dialog->set_position(graph->get_global_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
+ members_dialog->set_position(graph->get_screen_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
}
+ members_dialog->popup();
- // keep dialog within window bounds
- Size2 window_size = DisplayServer::get_singleton()->window_get_size();
+ // Keep dialog within window bounds.
+ Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());
Rect2 dialog_rect = Rect2(members_dialog->get_position(), members_dialog->get_size());
- if (dialog_rect.position.y + dialog_rect.size.y > window_size.y) {
- int difference = dialog_rect.position.y + dialog_rect.size.y - window_size.y;
- members_dialog->set_position(members_dialog->get_position() - Point2(0, difference));
- }
- if (dialog_rect.position.x + dialog_rect.size.x > window_size.x) {
- int difference = dialog_rect.position.x + dialog_rect.size.x - window_size.x;
- members_dialog->set_position(members_dialog->get_position() - Point2(difference, 0));
- }
+ Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2());
+ members_dialog->set_position(members_dialog->get_position() - difference);
- node_filter->call_deferred(SNAME("grab_focus")); // still not visible
+ node_filter->call_deferred(SNAME("grab_focus")); // Still not visible.
node_filter->select_all();
}
+void VisualShaderEditor::_show_varying_menu() {
+ varying_options->set_item_disabled(int(VaryingMenuOptions::REMOVE), visual_shader->get_varyings_count() == 0);
+ varying_options->set_position(graph->get_screen_position() + varying_button->get_position() + Size2(0, varying_button->get_size().height));
+ varying_options->popup();
+}
+
+void VisualShaderEditor::_varying_menu_id_pressed(int p_idx) {
+ switch (VaryingMenuOptions(p_idx)) {
+ case VaryingMenuOptions::ADD: {
+ _show_add_varying_dialog();
+ } break;
+ case VaryingMenuOptions::REMOVE: {
+ _show_remove_varying_dialog();
+ } break;
+ default:
+ break;
+ }
+}
+
+void VisualShaderEditor::_show_add_varying_dialog() {
+ _varying_name_changed(varying_name->get_text());
+
+ add_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
+ add_varying_dialog->popup();
+
+ // Keep dialog within window bounds.
+ Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());
+ Rect2 dialog_rect = Rect2(add_varying_dialog->get_position(), add_varying_dialog->get_size());
+ Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2());
+ add_varying_dialog->set_position(add_varying_dialog->get_position() - difference);
+}
+
+void VisualShaderEditor::_show_remove_varying_dialog() {
+ remove_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
+ remove_varying_dialog->popup();
+
+ // Keep dialog within window bounds.
+ Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());
+ Rect2 dialog_rect = Rect2(remove_varying_dialog->get_position(), remove_varying_dialog->get_size());
+ Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2());
+ remove_varying_dialog->set_position(remove_varying_dialog->get_position() - difference);
+}
+
void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
Ref<InputEventKey> ie = p_ie;
- if (ie.is_valid() && (ie->get_keycode() == KEY_UP || ie->get_keycode() == KEY_DOWN || ie->get_keycode() == KEY_ENTER || ie->get_keycode() == KEY_KP_ENTER)) {
+ if (ie.is_valid() && (ie->get_keycode() == Key::UP || ie->get_keycode() == Key::DOWN || ie->get_keycode() == Key::ENTER || ie->get_keycode() == Key::KP_ENTER)) {
members->gui_input(ie);
node_filter->accept_event();
}
}
void VisualShaderEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- node_filter->set_clear_button_enabled(true);
-
- // collapse tree by default
-
- TreeItem *category = members->get_root()->get_first_child();
- while (category) {
- category->set_collapsed(true);
- TreeItem *sub_category = category->get_first_child();
- while (sub_category) {
- sub_category->set_collapsed(true);
- sub_category = sub_category->get_next();
- }
- category = category->get_next();
- }
- }
+ switch (p_what) {
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
+ } break;
- if (p_what == NOTIFICATION_DRAG_BEGIN) {
- Dictionary dd = get_viewport()->gui_get_drag_data();
- if (members->is_visible_in_tree() && dd.has("id")) {
- members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
- }
- } else if (p_what == NOTIFICATION_DRAG_END) {
- members->set_drop_mode_flags(0);
- }
+ case NOTIFICATION_ENTER_TREE: {
+ node_filter->set_clear_button_enabled(true);
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- highend_label->set_modulate(get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
+ // collapse tree by default
- node_filter->set_right_icon(Control::get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ TreeItem *category = members->get_root()->get_first_child();
+ while (category) {
+ category->set_collapsed(true);
+ TreeItem *sub_category = category->get_first_child();
+ while (sub_category) {
+ sub_category->set_collapsed(true);
+ sub_category = sub_category->get_next();
+ }
+ category = category->get_next();
+ }
- preview_shader->set_icon(Control::get_theme_icon(SNAME("Shader"), SNAME("EditorIcons")));
+ graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ highend_label->set_modulate(get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
- {
- Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color");
- Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");
- Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
- Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
- Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
- Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");
- Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");
- Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");
- Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
+ node_filter->set_right_icon(Control::get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- preview_text->add_theme_color_override("background_color", background_color);
+ preview_shader->set_icon(Control::get_theme_icon(SNAME("Shader"), SNAME("EditorIcons")));
- for (const String &E : keyword_list) {
- if (ShaderLanguage::is_control_flow_keyword(E)) {
- syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);
- } else {
- syntax_highlighter->add_keyword_color(E, keyword_color);
+ {
+ Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color");
+ Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");
+ Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
+ Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
+ Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
+ Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");
+ Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");
+ Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");
+ Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
+ Color error_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
+
+ preview_text->add_theme_color_override("background_color", background_color);
+ varying_error_label->add_theme_color_override("font_color", error_color);
+
+ for (const String &E : keyword_list) {
+ if (ShaderLanguage::is_control_flow_keyword(E)) {
+ syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);
+ } else {
+ syntax_highlighter->add_keyword_color(E, keyword_color);
+ }
}
- }
- preview_text->add_theme_font_override("font", get_theme_font(SNAME("expression"), SNAME("EditorFonts")));
- preview_text->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts")));
- preview_text->add_theme_color_override("font_color", text_color);
- syntax_highlighter->set_number_color(number_color);
- syntax_highlighter->set_symbol_color(symbol_color);
- syntax_highlighter->set_function_color(function_color);
- syntax_highlighter->set_member_variable_color(members_color);
- syntax_highlighter->clear_color_regions();
- syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
- syntax_highlighter->add_color_region("//", "", comment_color, true);
+ preview_text->add_theme_font_override("font", get_theme_font(SNAME("expression"), SNAME("EditorFonts")));
+ preview_text->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts")));
+ preview_text->add_theme_color_override("font_color", text_color);
+ syntax_highlighter->set_number_color(number_color);
+ syntax_highlighter->set_symbol_color(symbol_color);
+ syntax_highlighter->set_function_color(function_color);
+ syntax_highlighter->set_member_variable_color(members_color);
+ syntax_highlighter->clear_color_regions();
+ syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
+ syntax_highlighter->add_color_region("//", "", comment_color, true);
+
+ preview_text->clear_comment_delimiters();
+ preview_text->add_comment_delimiter("/*", "*/", false);
+ preview_text->add_comment_delimiter("//", "", true);
+
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
+ error_label->add_theme_font_override("font", get_theme_font(SNAME("status_source"), SNAME("EditorFonts")));
+ error_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), SNAME("EditorFonts")));
+ error_label->add_theme_color_override("font_color", error_color);
+ }
- preview_text->clear_comment_delimiters();
- preview_text->add_comment_delimiter("/*", "*/", false);
- preview_text->add_comment_delimiter("//", "", true);
+ tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
- error_label->add_theme_font_override("font", get_theme_font(SNAME("status_source"), SNAME("EditorFonts")));
- error_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), SNAME("EditorFonts")));
- error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
- }
+ if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) {
+ _update_graph();
+ }
+ } break;
- tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
+ case NOTIFICATION_DRAG_BEGIN: {
+ Dictionary dd = get_viewport()->gui_get_drag_data();
+ if (members->is_visible_in_tree() && dd.has("id")) {
+ members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
+ }
+ } break;
- if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) {
- _update_graph();
- }
+ case NOTIFICATION_DRAG_END: {
+ members->set_drop_mode_flags(0);
+ } break;
}
}
@@ -3387,6 +3832,17 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, c
if (p_duplicate) {
undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));
} else {
+ bool copy_buffer_empty = true;
+ for (const CopyItem &item : copy_items_buffer) {
+ if (!item.disabled) {
+ copy_buffer_empty = false;
+ break;
+ }
+ }
+ if (copy_buffer_empty) {
+ return;
+ }
+
undo_redo->create_action(TTR("Paste VisualShader Node(s)"));
}
@@ -3399,16 +3855,7 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, c
Set<int> added_set;
for (CopyItem &item : r_items) {
- bool unsupported = false;
- for (int i = 0; i < add_options.size(); i++) {
- if (add_options[i].type == item.node->get_class_name()) {
- if (!_is_available(add_options[i].mode)) {
- unsupported = true;
- }
- break;
- }
- }
- if (unsupported) {
+ if (item.disabled) {
unsupported_set.insert(item.id);
continue;
}
@@ -3449,7 +3896,10 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, c
}
id_from = base_id;
- for (int i = 0; i < r_items.size(); i++) {
+ for (const CopyItem &item : r_items) {
+ if (item.disabled) {
+ continue;
+ }
undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from);
undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_from);
id_from++;
@@ -3550,7 +4000,7 @@ void VisualShaderEditor::_mode_selected(int p_id) {
}
visual_shader->set_shader_type(VisualShader::Type(p_id + offset));
- _update_options_menu();
+ _update_nodes();
_update_graph();
graph->grab_focus();
@@ -3578,7 +4028,10 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
return;
}
- bool type_changed = p_input->get_input_type_by_name(p_name) != p_input->get_input_type_by_name(prev_name);
+ VisualShaderNode::PortType next_input_type = p_input->get_input_type_by_name(p_name);
+ VisualShaderNode::PortType prev_input_type = p_input->get_input_type_by_name(prev_name);
+
+ bool type_changed = next_input_type != prev_input_type;
UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(TTR("Visual Shader Input Type Changed"));
@@ -3586,31 +4039,54 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
undo_redo->add_do_method(p_input.ptr(), "set_input_name", p_name);
undo_redo->add_undo_method(p_input.ptr(), "set_input_name", prev_name);
- // update output port
- for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
- VisualShader::Type type = VisualShader::Type(type_id);
- int id = visual_shader->find_node_id(type, p_input);
- if (id != VisualShader::NODE_ID_INVALID) {
- if (type_changed) {
+ if (type_changed) {
+ for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
+ VisualShader::Type type = VisualShader::Type(type_id);
+
+ int id = visual_shader->find_node_id(type, p_input);
+ if (id != VisualShader::NODE_ID_INVALID) {
+ bool is_expanded = p_input->is_output_port_expandable(0) && p_input->_is_output_port_expanded(0);
+
+ int type_size = 0;
+ if (is_expanded) {
+ switch (next_input_type) {
+ case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
+ type_size = 2;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
+ type_size = 3;
+ } break;
+ case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
+ type_size = 4;
+ } break;
+ default:
+ break;
+ }
+ }
+
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
for (const VisualShader::Connection &E : conns) {
- if (E.from_node == id) {
- if (visual_shader->is_port_types_compatible(p_input->get_input_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- continue;
+ int from_node = E.from_node;
+ int from_port = E.from_port;
+ int to_node = E.to_node;
+ int to_port = E.to_port;
+
+ if (from_node == id) {
+ bool is_incompatible_types = !visual_shader->is_port_types_compatible(p_input->get_input_type_by_name(p_name), visual_shader->get_node(type, to_node)->get_input_port_type(to_port));
+
+ if (is_incompatible_types || from_port > type_size) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
}
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
}
}
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
}
- undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
- undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
- break;
}
}
@@ -3661,6 +4137,75 @@ void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_
undo_redo->commit_action();
}
+void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name) {
+ String prev_name = p_varying->get_varying_name();
+
+ if (p_name == prev_name) {
+ return;
+ }
+
+ bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
+
+ UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo->create_action(TTR("Varying Name Changed"));
+
+ undo_redo->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
+ undo_redo->add_undo_method(p_varying.ptr(), "set_varying_name", prev_name);
+
+ VisualShader::VaryingType vtype = p_varying->get_varying_type_by_name(p_name);
+ VisualShader::VaryingType prev_vtype = p_varying->get_varying_type_by_name(prev_name);
+
+ bool type_changed = vtype != prev_vtype;
+
+ if (type_changed) {
+ undo_redo->add_do_method(p_varying.ptr(), "set_varying_type", vtype);
+ undo_redo->add_undo_method(p_varying.ptr(), "set_varying_type", prev_vtype);
+ }
+
+ // update ports
+ for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
+ VisualShader::Type type = VisualShader::Type(type_id);
+ int id = visual_shader->find_node_id(type, p_varying);
+
+ if (id != VisualShader::NODE_ID_INVALID) {
+ if (type_changed) {
+ List<VisualShader::Connection> conns;
+ visual_shader->get_node_connections(type, &conns);
+
+ for (const VisualShader::Connection &E : conns) {
+ if (is_getter) {
+ if (E.from_node == id) {
+ if (visual_shader->is_port_types_compatible(p_varying->get_varying_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {
+ continue;
+ }
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ }
+ } else {
+ if (E.to_node == id) {
+ if (visual_shader->is_port_types_compatible(p_varying->get_varying_type_by_name(p_name), visual_shader->get_node(type, E.from_node)->get_output_port_type(E.from_port))) {
+ continue;
+ }
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ }
+ }
+ }
+ }
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
+ break;
+ }
+ }
+
+ undo_redo->commit_action();
+}
+
void VisualShaderEditor::_float_constant_selected(int p_which) {
ERR_FAIL_INDEX(p_which, MAX_FLOAT_CONST_DEFS);
@@ -3703,7 +4248,7 @@ void VisualShaderEditor::_member_create() {
TreeItem *item = members->get_selected();
if (item != nullptr && item->has_meta("id")) {
int idx = members->get_selected()->get_meta("id");
- _add_node(idx, add_options[idx].sub_func);
+ _add_node(idx, add_options[idx].ops);
members_dialog->hide();
}
}
@@ -3715,6 +4260,95 @@ void VisualShaderEditor::_member_cancel() {
from_slot = -1;
}
+void VisualShaderEditor::_update_varying_tree() {
+ varyings->clear();
+ TreeItem *root = varyings->create_item();
+
+ int count = visual_shader->get_varyings_count();
+
+ for (int i = 0; i < count; i++) {
+ const VisualShader::Varying *varying = visual_shader->get_varying_by_index(i);
+
+ if (varying) {
+ TreeItem *item = varyings->create_item(root);
+ item->set_text(0, varying->name);
+
+ if (i == 0) {
+ item->select(0);
+ }
+
+ switch (varying->type) {
+ case VisualShader::VARYING_TYPE_FLOAT:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")));
+ break;
+ case VisualShader::VARYING_TYPE_VECTOR_2D:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")));
+ break;
+ case VisualShader::VARYING_TYPE_VECTOR_3D:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")));
+ break;
+ case VisualShader::VARYING_TYPE_VECTOR_4D:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")));
+ break;
+ case VisualShader::VARYING_TYPE_COLOR:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Color"), SNAME("EditorIcons")));
+ break;
+ case VisualShader::VARYING_TYPE_TRANSFORM:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ varying_options->set_item_disabled(int(VaryingMenuOptions::REMOVE), count == 0);
+}
+
+void VisualShaderEditor::_varying_create() {
+ _add_varying(varying_name->get_text(), (VisualShader::VaryingMode)varying_mode->get_selected(), (VisualShader::VaryingType)varying_type->get_selected());
+ add_varying_dialog->hide();
+}
+
+void VisualShaderEditor::_varying_name_changed(const String &p_text) {
+ String name = p_text;
+
+ if (!name.is_valid_identifier()) {
+ varying_error_label->show();
+ varying_error_label->set_text(TTR("Invalid name for varying."));
+ add_varying_dialog->get_ok_button()->set_disabled(true);
+ return;
+ }
+ if (visual_shader->has_varying(name)) {
+ varying_error_label->show();
+ varying_error_label->set_text(TTR("Varying with that name is already exist."));
+ add_varying_dialog->get_ok_button()->set_disabled(true);
+ return;
+ }
+ if (varying_error_label->is_visible()) {
+ varying_error_label->hide();
+ add_varying_dialog->set_size(Size2(add_varying_dialog->get_size().x, 0));
+ }
+ add_varying_dialog->get_ok_button()->set_disabled(false);
+}
+
+void VisualShaderEditor::_varying_deleted() {
+ TreeItem *item = varyings->get_selected();
+
+ if (item != nullptr) {
+ _remove_varying(item->get_text(0));
+ remove_varying_dialog->hide();
+ }
+}
+
+void VisualShaderEditor::_varying_selected() {
+ add_varying_dialog->get_ok_button()->set_disabled(false);
+}
+
+void VisualShaderEditor::_varying_unselected() {
+ add_varying_dialog->get_ok_button()->set_disabled(true);
+}
+
void VisualShaderEditor::_tools_menu_option(int p_idx) {
TreeItem *category = members->get_root()->get_first_child();
@@ -3781,10 +4415,10 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
_convert_constants_to_uniforms(true);
break;
case NodeMenuOptions::SET_COMMENT_TITLE:
- _comment_title_popup_show(get_global_mouse_position(), selected_comment);
+ _comment_title_popup_show(get_screen_position() + get_local_mouse_position(), selected_comment);
break;
case NodeMenuOptions::SET_COMMENT_DESCRIPTION:
- _comment_desc_popup_show(get_global_mouse_position(), selected_comment);
+ _comment_desc_popup_show(get_screen_position() + get_local_mouse_position(), selected_comment);
break;
default:
break;
@@ -3806,11 +4440,6 @@ Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
Dictionary d;
d["id"] = id;
- if (op.sub_func == -1) {
- d["sub_func"] = op.sub_func_str;
- } else {
- d["sub_func"] = op.sub_func;
- }
Label *label = memnew(Label);
label->set_text(it->get_text(0));
@@ -3843,7 +4472,7 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
int idx = d["id"];
saved_node_pos = p_point;
saved_node_pos_dirty = true;
- _add_node(idx, add_options[idx].sub_func);
+ _add_node(idx, add_options[idx].ops);
} else if (d.has("files")) {
undo_redo->create_action(TTR("Add Node(s) to Visual Shader"));
@@ -3868,33 +4497,33 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
}
if (idx != -1) {
- _add_node(idx, -1, arr[i], i);
+ _add_node(idx, {}, arr[i], i);
}
}
} else if (type == "CurveTexture") {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_node(curve_node_option_idx, -1, arr[i], i);
+ _add_node(curve_node_option_idx, {}, arr[i], i);
} else if (type == "CurveXYZTexture") {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_node(curve_xyz_node_option_idx, -1, arr[i], i);
+ _add_node(curve_xyz_node_option_idx, {}, arr[i], i);
} else if (ClassDB::get_parent_class(type) == "Texture2D") {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_node(texture2d_node_option_idx, -1, arr[i], i);
+ _add_node(texture2d_node_option_idx, {}, arr[i], i);
} else if (type == "Texture2DArray") {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_node(texture2d_array_node_option_idx, -1, arr[i], i);
+ _add_node(texture2d_array_node_option_idx, {}, arr[i], i);
} else if (ClassDB::get_parent_class(type) == "Texture3D") {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_node(texture3d_node_option_idx, -1, arr[i], i);
+ _add_node(texture3d_node_option_idx, {}, arr[i], i);
} else if (type == "Cubemap") {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
- _add_node(cubemap_node_option_idx, -1, arr[i], i);
+ _add_node(cubemap_node_option_idx, {}, arr[i], i);
}
}
}
@@ -3936,7 +4565,7 @@ void VisualShaderEditor::_preview_size_changed() {
static ShaderLanguage::DataType _get_global_variable_type(const StringName &p_variable) {
RS::GlobalVariableType gvt = RS::get_singleton()->global_variable_get_type(p_variable);
- return RS::global_variable_type_get_shader_datatype(gvt);
+ return (ShaderLanguage::DataType)RS::global_variable_type_get_shader_datatype(gvt);
}
void VisualShaderEditor::_update_preview() {
@@ -3949,9 +4578,15 @@ void VisualShaderEditor::_update_preview() {
preview_text->set_text(code);
+ ShaderLanguage::ShaderCompileInfo info;
+ info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode()));
+ info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));
+ info.shader_types = ShaderTypes::get_singleton()->get_types();
+ info.global_variable_type_func = _get_global_variable_type;
+
ShaderLanguage sl;
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
+ Error err = sl.compile(code, info);
for (int i = 0; i < preview_text->get_line_count(); i++) {
preview_text->set_line_background_color(i, Color(0, 0, 0, 0));
@@ -3981,15 +4616,18 @@ void VisualShaderEditor::_visibility_changed() {
}
void VisualShaderEditor::_bind_methods() {
+ ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes);
ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
- ClassDB::bind_method("_update_options_menu", &VisualShaderEditor::_update_options_menu);
ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node);
ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed);
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
ClassDB::bind_method("_uniform_select_item", &VisualShaderEditor::_uniform_select_item);
+ ClassDB::bind_method("_varying_select_item", &VisualShaderEditor::_varying_select_item);
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
ClassDB::bind_method("_clear_copy_buffer", &VisualShaderEditor::_clear_copy_buffer);
ClassDB::bind_method("_update_uniforms", &VisualShaderEditor::_update_uniforms);
+ ClassDB::bind_method("_update_varyings", &VisualShaderEditor::_update_varyings);
+ ClassDB::bind_method("_update_varying_tree", &VisualShaderEditor::_update_varying_tree);
ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);
ClassDB::bind_method("_nodes_dragged", &VisualShaderEditor::_nodes_dragged);
ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected);
@@ -4008,19 +4646,8 @@ VisualShaderEditor *VisualShaderEditor::singleton = nullptr;
VisualShaderEditor::VisualShaderEditor() {
singleton = this;
- updating = false;
- saved_node_pos_dirty = false;
- saved_node_pos = Point2(0, 0);
ShaderLanguage::get_keyword_list(&keyword_list);
- pending_update_preview = false;
- shader_error = false;
-
- to_node = -1;
- to_slot = -1;
- from_node = -1;
- from_slot = -1;
-
graph = memnew(GraphEdit);
graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
graph->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -4032,7 +4659,9 @@ VisualShaderEditor::VisualShaderEditor() {
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);
- graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_2D);
+ graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_3D);
+ graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_4D);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_TRANSFORM);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SAMPLER);
//graph->add_valid_left_disconnect_type(0);
@@ -4051,20 +4680,46 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect("visibility_changed", callable_mp(this, &VisualShaderEditor::_visibility_changed));
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT);
- graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_2D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_3D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_4D);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN);
+
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR);
- graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_2D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_3D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_4D);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_BOOLEAN);
- graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR);
- graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR_INT);
- graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR);
- graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_BOOLEAN);
+
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR_INT);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_2D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_3D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_4D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_BOOLEAN);
+
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR_INT);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_2D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_3D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_4D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_BOOLEAN);
+
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR_INT);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_2D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_3D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_4D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_BOOLEAN);
+
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_INT);
- graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_2D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_3D);
+ graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_4D);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN);
+
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER);
@@ -4117,11 +4772,23 @@ VisualShaderEditor::VisualShaderEditor() {
add_node = memnew(Button);
add_node->set_flat(true);
- graph->get_zoom_hbox()->add_child(add_node);
add_node->set_text(TTR("Add Node..."));
+ graph->get_zoom_hbox()->add_child(add_node);
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog), varray(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX));
+ varying_button = memnew(Button);
+ varying_button->set_flat(true);
+ varying_button->set_text(TTR("Manage Varyings"));
+ graph->get_zoom_hbox()->add_child(varying_button);
+ varying_button->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_varying_menu));
+
+ varying_options = memnew(PopupMenu);
+ add_child(varying_options);
+ varying_options->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD));
+ varying_options->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE));
+ varying_options->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed));
+
preview_shader = memnew(Button);
preview_shader->set_flat(true);
preview_shader->set_toggle_mode(true);
@@ -4245,10 +4912,79 @@ VisualShaderEditor::VisualShaderEditor() {
members_dialog->connect("cancelled", callable_mp(this, &VisualShaderEditor::_member_cancel));
add_child(members_dialog);
+ // add varyings dialog
+ {
+ add_varying_dialog = memnew(ConfirmationDialog);
+ add_varying_dialog->set_title(TTR("Create Shader Varying"));
+ add_varying_dialog->set_exclusive(false);
+ add_varying_dialog->get_ok_button()->set_text(TTR("Create"));
+ add_varying_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_varying_create));
+ add_varying_dialog->get_ok_button()->set_disabled(true);
+ add_child(add_varying_dialog);
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ add_varying_dialog->add_child(vb);
+
+ HBoxContainer *hb = memnew(HBoxContainer);
+ vb->add_child(hb);
+ hb->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ varying_type = memnew(OptionButton);
+ hb->add_child(varying_type);
+ varying_type->add_item("Float");
+ varying_type->add_item("Vector2");
+ varying_type->add_item("Vector3");
+ varying_type->add_item("Vector4");
+ varying_type->add_item("Color");
+ varying_type->add_item("Transform");
+
+ varying_name = memnew(LineEdit);
+ hb->add_child(varying_name);
+ varying_name->set_custom_minimum_size(Size2(150 * EDSCALE, 0));
+ varying_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ varying_name->connect("text_changed", callable_mp(this, &VisualShaderEditor::_varying_name_changed));
+
+ varying_mode = memnew(OptionButton);
+ hb->add_child(varying_mode);
+ varying_mode->add_item("Vertex -> [Fragment, Light]");
+ varying_mode->add_item("Fragment -> Light");
+
+ varying_error_label = memnew(Label);
+ vb->add_child(varying_error_label);
+ varying_error_label->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ varying_error_label->hide();
+ }
+
+ // remove varying dialog
+ {
+ remove_varying_dialog = memnew(ConfirmationDialog);
+ remove_varying_dialog->set_title(TTR("Delete Shader Varying"));
+ remove_varying_dialog->set_exclusive(false);
+ remove_varying_dialog->get_ok_button()->set_text(TTR("Delete"));
+ remove_varying_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_varying_deleted));
+ add_child(remove_varying_dialog);
+
+ VBoxContainer *vb = memnew(VBoxContainer);
+ remove_varying_dialog->add_child(vb);
+
+ varyings = memnew(Tree);
+ vb->add_child(varyings);
+ varyings->set_h_size_flags(SIZE_EXPAND_FILL);
+ varyings->set_v_size_flags(SIZE_EXPAND_FILL);
+ varyings->set_hide_root(true);
+ varyings->set_allow_reselect(true);
+ varyings->set_hide_folding(false);
+ varyings->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));
+ varyings->connect("item_activated", callable_mp(this, &VisualShaderEditor::_varying_deleted));
+ varyings->connect("item_selected", callable_mp(this, &VisualShaderEditor::_varying_selected));
+ varyings->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_varying_unselected));
+ }
+
alert = memnew(AcceptDialog);
alert->get_label()->set_autowrap_mode(Label::AUTOWRAP_WORD);
- alert->get_label()->set_align(Label::ALIGN_CENTER);
- alert->get_label()->set_valign(Label::VALIGN_CENTER);
+ alert->get_label()->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ alert->get_label()->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);
add_child(alert);
@@ -4258,8 +4994,8 @@ VisualShaderEditor::VisualShaderEditor() {
comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed));
comment_title_change_edit->connect("text_submitted", callable_mp(this, &VisualShaderEditor::_comment_title_text_submitted));
comment_title_change_popup->add_child(comment_title_change_edit);
- comment_title_change_edit->set_size(Size2(-1, -1));
- comment_title_change_popup->set_size(Size2(-1, -1));
+ comment_title_change_edit->reset_size();
+ comment_title_change_popup->reset_size();
comment_title_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_title_popup_focus_out));
comment_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_title_popup_hide));
add_child(comment_title_change_popup);
@@ -4271,8 +5007,8 @@ VisualShaderEditor::VisualShaderEditor() {
comment_desc_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_desc_text_changed));
comment_desc_vbox->add_child(comment_desc_change_edit);
comment_desc_change_edit->set_custom_minimum_size(Size2(300 * EDSCALE, 150 * EDSCALE));
- comment_desc_change_edit->set_size(Size2(-1, -1));
- comment_desc_change_popup->set_size(Size2(-1, -1));
+ comment_desc_change_edit->reset_size();
+ comment_desc_change_popup->reset_size();
comment_desc_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
comment_desc_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_desc_popup_hide));
Button *comment_desc_confirm_button = memnew(Button);
@@ -4287,472 +5023,601 @@ VisualShaderEditor::VisualShaderEditor() {
// COLOR
- add_options.push_back(AddOption("ColorFunc", "Color", "Common", "VisualShaderNodeColorFunc", TTR("Color function."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ColorOp", "Color", "Common", "VisualShaderNodeColorOp", TTR("Color operator."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ColorFunc", "Color", "Common", "VisualShaderNodeColorFunc", TTR("Color function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ColorOp", "Color", "Common", "VisualShaderNodeColorOp", TTR("Color operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+
+ add_options.push_back(AddOption("Grayscale", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("HSV2RGB", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeVectorFunc::FUNC_HSV2RGB, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("RGB2HSV", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeVectorFunc::FUNC_RGB2HSV, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Sepia", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), { VisualShaderNodeColorFunc::FUNC_SEPIA }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+
+ add_options.push_back(AddOption("Burn", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), { VisualShaderNodeColorOp::OP_BURN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Darken", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), { VisualShaderNodeColorOp::OP_DARKEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Difference", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), { VisualShaderNodeColorOp::OP_DIFFERENCE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Dodge", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), { VisualShaderNodeColorOp::OP_DODGE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("HardLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("HardLight operator."), { VisualShaderNodeColorOp::OP_HARD_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Lighten", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), { VisualShaderNodeColorOp::OP_LIGHTEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Overlay", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), { VisualShaderNodeColorOp::OP_OVERLAY }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), { VisualShaderNodeColorOp::OP_SCREEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), { VisualShaderNodeColorOp::OP_SOFT_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Grayscale", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), VisualShaderNodeColorFunc::FUNC_GRAYSCALE, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("HSV2RGB", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts HSV vector to RGB equivalent."), VisualShaderNodeVectorFunc::FUNC_HSV2RGB, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("RGB2HSV", "Color", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts RGB vector to HSV equivalent."), VisualShaderNodeVectorFunc::FUNC_RGB2HSV, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Sepia", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), VisualShaderNodeColorFunc::FUNC_SEPIA, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant.")));
+ add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform.")));
- add_options.push_back(AddOption("Burn", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), VisualShaderNodeColorOp::OP_BURN, VisualShaderNode::PORT_TYPE_VECTOR));
- 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("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));
- add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), VisualShaderNodeColorOp::OP_SOFT_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
+ // COMMON
- add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), -1, -1));
- add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, -1));
+ add_options.push_back(AddOption("DerivativeFunc", "Common", "", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) Derivative function."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
// CONDITIONAL
const String &compare_func_desc = TTR("Returns the boolean result of the %s comparison between two parameters.");
- add_options.push_back(AddOption("Equal", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Equal (==)")), VisualShaderNodeCompare::FUNC_EQUAL, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("GreaterThan", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than (>)")), VisualShaderNodeCompare::FUNC_GREATER_THAN, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("GreaterThanEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than or Equal (>=)")), VisualShaderNodeCompare::FUNC_GREATER_THAN_EQUAL, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("If", "Conditional", "Functions", "VisualShaderNodeIf", TTR("Returns an associated vector if the provided scalars are equal, greater or less."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("IsInf", "Conditional", "Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF and a scalar parameter."), VisualShaderNodeIs::FUNC_IS_INF, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("IsNaN", "Conditional", "Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between NaN and a scalar parameter."), VisualShaderNodeIs::FUNC_IS_NAN, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("LessThan", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), VisualShaderNodeCompare::FUNC_LESS_THAN, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("LessThanEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than or Equal (<=)")), VisualShaderNodeCompare::FUNC_LESS_THAN_EQUAL, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("NotEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), VisualShaderNodeCompare::FUNC_NOT_EQUAL, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("Switch", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated vector if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("SwitchBool", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated boolean if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("SwitchFloat", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated floating-point scalar if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_FLOAT, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("SwitchInt", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated integer scalar if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("SwitchTransform", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated transform if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM));
-
- add_options.push_back(AddOption("Compare", "Conditional", "Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("Is", "Conditional", "Common", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF (or NaN) and a scalar parameter."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
-
- add_options.push_back(AddOption("BooleanConstant", "Conditional", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("BooleanUniform", "Conditional", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("Equal", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Equal (==)")), { VisualShaderNodeCompare::FUNC_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("GreaterThan", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than (>)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("GreaterThanEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than or Equal (>=)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("If", "Conditional", "Functions", "VisualShaderNodeIf", TTR("Returns an associated vector if the provided scalars are equal, greater or less."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("IsInf", "Conditional", "Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF and a scalar parameter."), { VisualShaderNodeIs::FUNC_IS_INF }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("IsNaN", "Conditional", "Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between NaN and a scalar parameter."), { VisualShaderNodeIs::FUNC_IS_NAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("LessThan", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), { VisualShaderNodeCompare::FUNC_LESS_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("LessThanEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than or Equal (<=)")), { VisualShaderNodeCompare::FUNC_LESS_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("NotEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), { VisualShaderNodeCompare::FUNC_NOT_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("Switch", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 3D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Switch2D", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 2D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("SwitchBool", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated boolean if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_BOOLEAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("SwitchFloat", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated floating-point scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_FLOAT }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SwitchInt", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated integer scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_INT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("SwitchTransform", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated transform if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_TRANSFORM }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("Compare", "Conditional", "Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("Is", "Conditional", "Common", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF (or NaN) and a scalar parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
+
+ add_options.push_back(AddOption("BooleanConstant", "Conditional", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("BooleanUniform", "Conditional", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
// INPUT
- const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.");
+ const String translation_gdsl = "\n\n" + TTR("Translated to '%s' in Godot Shading Language.");
+ const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.") + translation_gdsl;
- // SPATIAL-FOR-ALL
+ // NODE3D-FOR-ALL
- add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_camera"), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection"), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("OutputIsSRGB", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "output_is_srgb"), "output_is_srgb", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "projection"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV2", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "viewport_size"), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InvProjectionMatrix", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection_matrix", "INV_PROJECTION_MATRIX"), { "inv_projection_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InvViewMatrix", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_view_matrix", "INV_VIEW_MATRIX"), { "inv_view_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ModelMatrix", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "model_matrix", "MODEL_MATRIX"), { "model_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "normal", "NORMAL"), { "normal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("OutputIsSRGB", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "output_is_srgb", "OUTPUT_IS_SRGB"), { "output_is_srgb" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ProjectionMatrix", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "projection_matrix", "PROJECTION_MATRIX"), { "projection_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv", "UV"), { "uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV2", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv2", "UV2"), { "uv2" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewMatrix", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "view_matrix", "VIEW_MATRIX"), { "view_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "viewport_size", "VIEWPORT_SIZE"), { "viewport_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_SPATIAL));
// CANVASITEM-FOR-ALL
- add_options.push_back(AddOption("Alpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("TexturePixelSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "texture_pixel_size"), "texture_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, -1, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("TexturePixelSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "texture_pixel_size", "TEXTURE_PIXEL_SIZE"), { "texture_pixel_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv", "UV"), { "uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, -1, Shader::MODE_CANVAS_ITEM));
// PARTICLES-FOR-ALL
- add_options.push_back(AddOption("Active", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Alpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("AttractorForce", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "attractor_force"), "attractor_force", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Custom", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("CustomAlpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Delta", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("EmissionTransform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Index", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("LifeTime", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Restart", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Transform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Velocity", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Active", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active", "ACTIVE"), { "active" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("AttractorForce", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "attractor_force", "ATTRACTOR_FORCE"), { "attractor_force" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Custom", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom", "CUSTOM"), { "custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Delta", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta", "DELTA"), { "delta" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("EmissionTransform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform", "EMISSION_TRANSFORM"), { "emission_transform" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Index", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index", "INDEX"), { "index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("LifeTime", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime", "LIFETIME"), { "lifetime" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Restart", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart", "RESTART"), { "restart" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Transform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform", "TRANSFORM"), { "transform" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Velocity", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity", "VELOCITY"), { "velocity" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, -1, Shader::MODE_PARTICLES));
/////////////////
add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter.")));
- const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.");
- const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.");
- const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.");
- const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.");
- const String input_param_for_fog_shader_mode = TTR("'%s' input parameter for fog shader mode.");
- const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.");
- const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.");
- const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.");
- const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode.");
- const String input_param_for_collide_shader_mode = TTR("'%s' input parameter for collide shader mode.");
- const String input_param_for_start_and_process_shader_mode = TTR("'%s' input parameter for start and process shader modes.");
- const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes.");
- const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes.");
+ const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;
+ const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.") + translation_gdsl;
+ const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.") + translation_gdsl;
+ const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.") + translation_gdsl;
+ const String input_param_for_fog_shader_mode = TTR("'%s' input parameter for fog shader mode.") + translation_gdsl;
+ const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.") + translation_gdsl;
+ const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.") + translation_gdsl;
+ const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.") + translation_gdsl;
+ const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode.") + translation_gdsl;
+ const String input_param_for_collide_shader_mode = TTR("'%s' input parameter for collide shader mode." + translation_gdsl);
+ const String input_param_for_start_and_process_shader_mode = TTR("'%s' input parameter for start and process shader modes.") + translation_gdsl;
+ const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes.") + translation_gdsl;
+ const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;
// NODE3D INPUTS
- add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("InstanceId", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id"), "instance_id", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom"), "instance_custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("InstanceCustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom_alpha"), "instance_custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
-
- add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
-
- add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo"), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation"), "attenuation", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Backlight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "backlight"), "backlight", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse"), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Metallic", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic"), "metallic", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InstanceId", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom", "INSTANCE_CUSTOM"), { "instance_custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ModelViewMatrix", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview_matrix", "MODELVIEW_MATRIX"), { "modelview_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size", "POINT_SIZE"), { "point_size" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("VertexId", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex_id", "VERTEX_ID"), { "vertex_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewIndex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewMonoLeft", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewRight", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+
+ add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("DepthTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture", "DEPTH_TEXTURE"), { "depth_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("FrontFacing", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing", "FRONT_FACING"), { "front_facing" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture", "SCREEN_TEXTURE"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewIndex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewMonoLeft", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewRight", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+
+ add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo", "ALBEDO"), { "albedo" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation", "ATTENUATION"), { "attenuation" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Backlight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "backlight", "BACKLIGHT"), { "backlight" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse", "DIFFUSE_LIGHT"), { "diffuse" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light", "LIGHT"), { "light" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color", "LIGHT_COLOR"), { "light_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Metallic", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic", "METALLIC"), { "metallic" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness", "ROUGHNESS"), { "roughness" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular", "SPECULAR_LIGHT"), { "specular" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
// CANVASITEM INPUTS
- add_options.push_back(AddOption("AtLightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Canvas", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "canvas"), "canvas", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom"), "instance_custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("InstanceCustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom_alpha"), "instance_custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Screen", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "screen"), "screen", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
-
- add_options.push_back(AddOption("AtLightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass"), "at_light_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_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, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SpecularShininess", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess"), "specular_shininess", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SpecularShininessAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess_alpha"), "specular_shininess_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SpecularShininessTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture"), "specular_shininess_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_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, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_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, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_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_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightColorAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color_alpha"), "light_color_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightPosition", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_position"), "light_position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightVertex", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "light_vertex"), "light_vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- 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, TYPE_FLAGS_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, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Shadow", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow"), "shadow", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ShadowAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_alpha"), "shadow_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SpecularShininess", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess"), "specular_shininess", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SpecularShininessAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess_alpha"), "specular_shininess_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_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, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("AtLightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass", "AT_LIGHT_PASS"), { "at_light_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("CanvasMatrix", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "canvas_matrix", "CANVAS_MATRIX"), { "canvas_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("InstanceCustom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_custom", "INSTANCE_CUSTOM"), { "instance_custom" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("InstanceId", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "instance_id", "INSTANCE_ID"), { "instance_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ModelMatrix", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "model_matrix", "MODEL_MATRIX"), { "model_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size", "POINT_SIZE"), { "point_size" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenMatrix", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "screen_matrix", "SCREEN_MATRIX"), { "screen_matrix" }, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("VertexId", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex_id", "VERTEX_ID"), { "vertex_id" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+
+ add_options.push_back(AddOption("AtLightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "at_light_pass", "AT_LIGHT_PASS"), { "at_light_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_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"), { "normal_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_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"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_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"), { "screen_pixel_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_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"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_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"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("SpecularShininess", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess", "SPECULAR_SHININESS"), { "specular_shininess" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("SpecularShininessTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE"), { "specular_shininess_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_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"), { "texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_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"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light", "LIGHT"), { "light" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color", "LIGHT_COLOR"), { "light_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightPosition", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_position", "LIGHT_POSITION"), { "light_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightVertex", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "light_vertex", "LIGHT_VERTEX"), { "light_vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal", "NORMAL"), { "normal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_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"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Shadow", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow", "SHADOW_MODULATE"), { "shadow" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("SpecularShininess", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess", "SPECULAR_SHININESS"), { "specular_shininess" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_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"), { "texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
// SKY INPUTS
- add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtHalfResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtQuarterResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("EyeDir", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResAlpha", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Position", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResAlpha", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Radiance", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("ScreenUV", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
- add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass", "AT_CUBEMAP_PASS"), { "at_cubemap_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtHalfResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_half_res_pass", "AT_HALF_RES_PASS"), { "at_half_res_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtQuarterResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_quarter_res_pass", "AT_QUARTER_RES_PASS"), { "at_quarter_res_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("EyeDir", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "eyedir", "EYEDIR"), { "eyedir" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("HalfResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_color", "HALF_RES_COLOR"), { "half_res_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_color", "LIGHT0_COLOR"), { "light0_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_direction", "LIGHT0_DIRECTION"), { "light0_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_enabled", "LIGHT0_ENABLED"), { "light0_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_energy", "LIGHT0_ENERGY"), { "light0_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_color", "LIGHT1_COLOR"), { "light1_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_direction", "LIGHT1_DIRECTION"), { "light1_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_enabled", "LIGHT1_ENABLED"), { "light1_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_energy", "LIGHT1_ENERGY"), { "light1_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_color", "LIGHT2_COLOR"), { "light2_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_direction", "LIGHT2_DIRECTION"), { "light2_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_enabled", "LIGHT2_ENABLED"), { "light2_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_energy", "LIGHT2_ENERGY"), { "light2_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_color", "LIGHT3_COLOR"), { "light3_color" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_direction", "LIGHT3_DIRECTION"), { "light3_direction" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_enabled", "LIGHT3_ENABLED"), { "light3_enabled" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_energy", "LIGHT3_ENERGY"), { "light3_energy" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Position", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "position", "POSITION"), { "position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("QuarterResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_color", "QUARTER_RES_COLOR"), { "quarter_res_color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Radiance", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "radiance", "RADIANCE"), { "radiance" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords", "SKY_COORDS"), { "sky_coords" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
// FOG INPUTS
- add_options.push_back(AddOption("WorldPosition", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position"), "world_position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
- add_options.push_back(AddOption("ObjectPosition", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "object_position"), "object_position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
- add_options.push_back(AddOption("UVW", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw"), "uvw", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
- add_options.push_back(AddOption("Extents", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "extents"), "extents", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
- add_options.push_back(AddOption("Transform", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_FOG, Shader::MODE_FOG));
- add_options.push_back(AddOption("SDF", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "sdf"), "sdf", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
- add_options.push_back(AddOption("Time", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("WorldPosition", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position", "WORLD_POSITION"), { "world_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("ObjectPosition", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "object_position", "OBJECT_POSITION"), { "object_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("UVW", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw", "UVW"), { "uvw" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("Extents", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "extents", "EXTENTS"), { "extents" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("SDF", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "sdf", "SDF"), { "sdf" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("Time", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
// PARTICLES INPUTS
- add_options.push_back(AddOption("CollisionDepth", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth"), "collision_depth", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("CollisionNormal", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_normal"), "collision_normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("CollisionDepth", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth", "COLLISION_DEPTH"), { "collision_depth" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("CollisionNormal", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_normal", "COLLISION_NORMAL"), { "collision_normal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
// PARTICLES
- add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", -1, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("ParticleAccelerator", "Particles", "", "VisualShaderNodeParticleAccelerator", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("ParticleRandomness", "Particles", "", "VisualShaderNodeParticleRandomness", "", -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles", "Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", "A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters.", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", {}, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("ParticleAccelerator", "Particles", "", "VisualShaderNodeParticleAccelerator", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("ParticleRandomness", "Particles", "", "VisualShaderNodeParticleRandomness", "", {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles", "Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", TTR("A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("BoxEmitter", "Particles", "Emitters", "VisualShaderNodeParticleBoxEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("RingEmitter", "Particles", "Emitters", "VisualShaderNodeParticleRingEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("SphereEmitter", "Particles", "Emitters", "VisualShaderNodeParticleSphereEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("BoxEmitter", "Particles", "Emitters", "VisualShaderNodeParticleBoxEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("MeshEmitter", "Particles", "Emitters", "VisualShaderNodeParticleMeshEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("RingEmitter", "Particles", "Emitters", "VisualShaderNodeParticleRingEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("SphereEmitter", "Particles", "Emitters", "VisualShaderNodeParticleSphereEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("ConeVelocity", "Particles", "Velocity", "VisualShaderNodeParticleConeVelocity", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("ConeVelocity", "Particles", "Velocity", "VisualShaderNodeParticleConeVelocity", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
// SCALAR
- add_options.push_back(AddOption("FloatFunc", "Scalar", "Common", "VisualShaderNodeFloatFunc", TTR("Float function."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("IntFunc", "Scalar", "Common", "VisualShaderNodeIntFunc", TTR("Integer function."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("FloatOp", "Scalar", "Common", "VisualShaderNodeFloatOp", TTR("Float operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("IntOp", "Scalar", "Common", "VisualShaderNodeIntOp", TTR("Integer operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("FloatFunc", "Scalar", "Common", "VisualShaderNodeFloatFunc", TTR("Float function."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("FloatOp", "Scalar", "Common", "VisualShaderNodeFloatOp", TTR("Float operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("IntFunc", "Scalar", "Common", "VisualShaderNodeIntFunc", TTR("Integer function."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("IntOp", "Scalar", "Common", "VisualShaderNodeIntOp", TTR("Integer operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
// CONSTANTS
for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {
- add_options.push_back(AddOption(float_constant_defs[i].name, "Scalar", "Constants", "VisualShaderNodeFloatConstant", float_constant_defs[i].desc, -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, float_constant_defs[i].value));
+ add_options.push_back(AddOption(float_constant_defs[i].name, "Scalar", "Constants", "VisualShaderNodeFloatConstant", float_constant_defs[i].desc, { float_constant_defs[i].value }, VisualShaderNode::PORT_TYPE_SCALAR));
}
// FUNCTIONS
- add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeFloatFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeIntFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("ACos", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("ACosH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("ASin", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("ASinH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("ATan", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("ATan2", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeFloatOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("ATanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Ceil", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeFloatFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), VisualShaderNodeClamp::OP_TYPE_FLOAT, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), VisualShaderNodeClamp::OP_TYPE_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Cos", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("CosH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Degrees", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeFloatFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Exp", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-e Exponential."), VisualShaderNodeFloatFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Exp2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 Exponential."), VisualShaderNodeFloatFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Floor", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeFloatFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeFloatFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("InverseSqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeFloatFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Log", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Natural logarithm."), VisualShaderNodeFloatFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), VisualShaderNodeFloatFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), VisualShaderNodeFloatOp::OP_MAX, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), VisualShaderNodeFloatOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two scalars."), VisualShaderNodeMix::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("MultiplyAdd", "Scalar", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), VisualShaderNodeMultiplyAdd::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeFloatFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeIntFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("OneMinus", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), VisualShaderNodeFloatFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeFloatOp::OP_POW, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeFloatFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), VisualShaderNodeFloatFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Round", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer to the parameter."), VisualShaderNodeFloatFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("RoundEven", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest even integer to the parameter."), VisualShaderNodeFloatFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Saturate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeFloatFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeFloatFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeIntFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeFloatFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), VisualShaderNodeSmoothStep::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeStep::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeFloatFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR));
-
- add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), VisualShaderNodeFloatOp::OP_ADD, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), VisualShaderNodeIntOp::OP_ADD, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), VisualShaderNodeFloatOp::OP_DIV, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), VisualShaderNodeIntOp::OP_DIV, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), VisualShaderNodeFloatOp::OP_MUL, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), VisualShaderNodeIntOp::OP_MUL, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Returns the remainder of the two floating-point scalars."), VisualShaderNodeFloatOp::OP_MOD, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the remainder of the two integer scalars."), VisualShaderNodeIntOp::OP_MOD, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), VisualShaderNodeFloatOp::OP_SUB, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), VisualShaderNodeIntOp::OP_SUB, VisualShaderNode::PORT_TYPE_SCALAR_INT));
-
- add_options.push_back(AddOption("FloatConstant", "Scalar", "Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("IntConstant", "Scalar", "Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("FloatUniform", "Scalar", "Variables", "VisualShaderNodeFloatUniform", TTR("Scalar floating-point uniform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("IntUniform", "Scalar", "Variables", "VisualShaderNodeIntUniform", TTR("Scalar integer uniform."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeIntFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("ACos", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOS }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ACosH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOSH }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ASin", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASIN }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ASinH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASINH }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATan", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATAN }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATan2", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeFloatOp::OP_ATAN2 }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("ATanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATANH }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("BitwiseNOT", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the result of bitwise NOT (~a) operation on the integer."), { VisualShaderNodeIntFunc::FUNC_BITWISE_NOT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Ceil", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeFloatFunc::FUNC_CEIL }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_FLOAT }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_INT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Cos", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COS }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("CosH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COSH }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Degrees", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeFloatFunc::FUNC_DEGREES }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("DFdX", "Scalar", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("DFdY", "Scalar", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Exp", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-e Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP2 }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Floor", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeFloatFunc::FUNC_FLOOR }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeFloatFunc::FUNC_FRAC }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("InverseSqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeFloatFunc::FUNC_INVERSE_SQRT }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Natural logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG2 }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), { VisualShaderNodeFloatOp::OP_MAX }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), { VisualShaderNodeFloatOp::OP_MIN }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two scalars."), { VisualShaderNodeMix::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("MultiplyAdd", "Scalar", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), { VisualShaderNodeMultiplyAdd::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeIntFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("OneMinus", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), { VisualShaderNodeFloatFunc::FUNC_ONEMINUS }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeFloatOp::OP_POW }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeFloatFunc::FUNC_RADIANS }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), { VisualShaderNodeFloatFunc::FUNC_RECIPROCAL }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Round", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUND }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("RoundEven", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUNDEVEN }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Saturate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeFloatFunc::FUNC_SATURATE }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeIntFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIN }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SINH }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SQRT }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Sum", "Scalar", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TAN }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TANH }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TRUNC }, VisualShaderNode::PORT_TYPE_SCALAR));
+
+ add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), { VisualShaderNodeFloatOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), { VisualShaderNodeIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseAND", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise AND (a & b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_AND }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseLeftShift", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise left shift (a << b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_LEFT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseOR", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise OR (a | b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_OR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseRightShift", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise right shift (a >> b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_RIGHT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseXOR", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise XOR (a ^ b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_XOR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), { VisualShaderNodeFloatOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), { VisualShaderNodeIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), { VisualShaderNodeIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Returns the remainder of the two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MOD }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the remainder of the two integer scalars."), { VisualShaderNodeIntOp::OP_MOD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), { VisualShaderNodeFloatOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), { VisualShaderNodeIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+
+ add_options.push_back(AddOption("FloatConstant", "Scalar", "Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("IntConstant", "Scalar", "Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("FloatUniform", "Scalar", "Variables", "VisualShaderNodeFloatUniform", TTR("Scalar floating-point uniform."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("IntUniform", "Scalar", "Variables", "VisualShaderNodeIntUniform", TTR("Scalar integer uniform."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
// SDF
{
- add_options.push_back(AddOption("ScreenUVToSDF", "SDF", "", "VisualShaderNodeScreenUVToSDF", TTR("Converts screen UV to a SDF."), -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SDFRaymarch", "SDF", "", "VisualShaderNodeSDFRaymarch", TTR("Casts a ray against the screen SDF and returns the distance travelled."), -1, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("SDFToScreenUV", "SDF", "", "VisualShaderNodeSDFToScreenUV", TTR("Converts a SDF to screen UV."), -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("TextureSDF", "SDF", "", "VisualShaderNodeTextureSDF", TTR("Performs a SDF texture lookup."), -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("TextureSDFNormal", "SDF", "", "VisualShaderNodeTextureSDFNormal", TTR("Performs a SDF normal texture lookup."), -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenUVToSDF", "SDF", "", "VisualShaderNodeScreenUVToSDF", TTR("Converts screen UV to a SDF."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("SDFRaymarch", "SDF", "", "VisualShaderNodeSDFRaymarch", TTR("Casts a ray against the screen SDF and returns the distance travelled."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("SDFToScreenUV", "SDF", "", "VisualShaderNodeSDFToScreenUV", TTR("Converts a SDF to screen UV."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("TextureSDF", "SDF", "", "VisualShaderNodeTextureSDF", TTR("Performs a SDF texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("TextureSDFNormal", "SDF", "", "VisualShaderNodeTextureSDFNormal", TTR("Performs a SDF normal texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
}
// TEXTURES
- add_options.push_back(AddOption("UVFunc", "Textures", "Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("UVFunc", "Textures", "Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
cubemap_node_option_idx = add_options.size();
- add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), -1, -1));
+ add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup.")));
curve_node_option_idx = add_options.size();
- add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), -1, -1));
+ add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup.")));
curve_xyz_node_option_idx = add_options.size();
- add_options.push_back(AddOption("CurveXYZTexture", "Textures", "Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), -1, -1));
+ add_options.push_back(AddOption("CurveXYZTexture", "Textures", "Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup.")));
texture2d_node_option_idx = add_options.size();
- add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), -1, -1));
+ add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup.")));
texture2d_array_node_option_idx = add_options.size();
- add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), -1, -1, -1, -1, -1));
+ add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup.")));
texture3d_node_option_idx = add_options.size();
- add_options.push_back(AddOption("Texture3D", "Textures", "Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), -1, -1));
- add_options.push_back(AddOption("UVPanning", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), VisualShaderNodeUVFunc::FUNC_PANNING, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("UVScaling", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), VisualShaderNodeUVFunc::FUNC_SCALING, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Texture3D", "Textures", "Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup.")));
+ add_options.push_back(AddOption("UVPanning", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_PANNING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("UVScaling", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_SCALING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup."), -1, -1));
- add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, -1));
- add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Texture2DArrayUniform", "Textures", "Variables", "VisualShaderNodeTexture2DArrayUniform", TTR("2D array of textures uniform lookup."), -1, -1, -1, -1, -1));
- add_options.push_back(AddOption("Texture3DUniform", "Textures", "Variables", "VisualShaderNodeTexture3DUniform", TTR("3D texture uniform lookup."), -1, -1, -1, -1, -1));
+ add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup.")));
+ add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup.")));
+ add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Texture2DArrayUniform", "Textures", "Variables", "VisualShaderNodeTexture2DArrayUniform", TTR("2D array of textures uniform lookup.")));
+ add_options.push_back(AddOption("Texture3DUniform", "Textures", "Variables", "VisualShaderNodeTexture3DUniform", TTR("3D texture uniform lookup.")));
// TRANSFORM
- add_options.push_back(AddOption("TransformFunc", "Transform", "Common", "VisualShaderNodeTransformFunc", TTR("Transform function."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("TransformOp", "Transform", "Common", "VisualShaderNodeTransformOp", TTR("Transform operator."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformFunc", "Transform", "Common", "VisualShaderNodeTransformFunc", TTR("Transform function."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformOp", "Transform", "Common", "VisualShaderNodeTransformOp", TTR("Transform operator."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("OuterProduct", "Transform", "Composition", "VisualShaderNodeOuterProduct", TTR("Calculate the outer product of a pair of vectors.\n\nOuterProduct treats the first parameter 'c' as a column vector (matrix with one column) and the second parameter 'r' as a row vector (matrix with one row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix whose number of rows is the number of components in 'c' and whose number of columns is the number of components in 'r'."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("TransformCompose", "Transform", "Composition", "VisualShaderNodeTransformCompose", TTR("Composes transform from four vectors."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("OuterProduct", "Transform", "Composition", "VisualShaderNodeOuterProduct", TTR("Calculate the outer product of a pair of vectors.\n\nOuterProduct treats the first parameter 'c' as a column vector (matrix with one column) and the second parameter 'r' as a row vector (matrix with one row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix whose number of rows is the number of components in 'c' and whose number of columns is the number of components in 'r'."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformCompose", "Transform", "Composition", "VisualShaderNodeTransformCompose", TTR("Composes transform from four vectors."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
add_options.push_back(AddOption("TransformDecompose", "Transform", "Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));
- add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("GetBillboardMatrix", "Transform", "Functions", "VisualShaderNodeBillboard", TTR("Calculates how the object should face the camera to be applied on Model View Matrix output port for 3D objects."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), VisualShaderNodeTransformFunc::FUNC_TRANSPOSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("GetBillboardMatrix", "Transform", "Functions", "VisualShaderNodeBillboard", TTR("Calculates how the object should face the camera to be applied on Model View Matrix output port for 3D objects."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), { VisualShaderNodeTransformFunc::FUNC_INVERSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), { VisualShaderNodeTransformFunc::FUNC_TRANSPOSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Add", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Sums two transforms."), VisualShaderNodeTransformOp::OP_ADD, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Divide", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Divides two transforms."), VisualShaderNodeTransformOp::OP_A_DIV_B, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Multiply", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Multiplies two transforms."), VisualShaderNodeTransformOp::OP_AxB, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("MultiplyComp", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Performs per-component multiplication of two transforms."), VisualShaderNodeTransformOp::OP_AxB_COMP, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Subtract", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Subtracts two transforms."), VisualShaderNodeTransformOp::OP_A_MINUS_B, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("TransformVectorMult", "Transform", "Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("Add", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Sums two transforms."), { VisualShaderNodeTransformOp::OP_ADD }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Divide", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Divides two transforms."), { VisualShaderNodeTransformOp::OP_A_DIV_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Multiply", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Multiplies two transforms."), { VisualShaderNodeTransformOp::OP_AxB }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("MultiplyComp", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Performs per-component multiplication of two transforms."), { VisualShaderNodeTransformOp::OP_AxB_COMP }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Subtract", "Transform", "Operators", "VisualShaderNodeTransformOp", TTR("Subtracts two transforms."), { VisualShaderNodeTransformOp::OP_A_MINUS_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformVectorMult", "Transform", "Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("TransformConstant", "Transform", "Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("TransformUniform", "Transform", "Variables", "VisualShaderNodeTransformUniform", TTR("Transform uniform."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformConstant", "Transform", "Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformUniform", "Transform", "Variables", "VisualShaderNodeTransformUniform", TTR("Transform uniform."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
// VECTOR
- add_options.push_back(AddOption("VectorFunc", "Vector", "Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("VectorOp", "Vector", "Common", "VisualShaderNodeVectorOp", TTR("Vector operator."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
-
- add_options.push_back(AddOption("VectorCompose", "Vector", "Composition", "VisualShaderNodeVectorCompose", TTR("Composes vector from three scalars."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("VectorDecompose", "Vector", "Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes vector to three scalars.")));
-
- add_options.push_back(AddOption("Abs", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ACos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ACosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ASin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ASinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ATan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ATan2", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("ATanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Ceil", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), VisualShaderNodeClamp::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Cos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("CosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Cross", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Calculates the cross product of two vectors."), VisualShaderNodeVectorOp::OP_CROSS, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Degrees", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Distance", "Vector", "Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Dot", "Vector", "Functions", "VisualShaderNodeDotProduct", TTR("Calculates the dot product of two vectors."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Exp", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Exp2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("FaceForward", "Vector", "Functions", "VisualShaderNodeFaceForward", TTR("Returns the vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Length", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Log", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Log2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), VisualShaderNodeVectorOp::OP_MAX, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), VisualShaderNodeVectorOp::OP_MIN, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), VisualShaderNodeMix::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), VisualShaderNodeMix::OP_TYPE_VECTOR_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeVectorOp::OP_POW, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Reflect", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("RoundEven", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest even integer to the parameter."), VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Saturate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Sign", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), VisualShaderNodeSmoothStep::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeStep::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeStep::OP_TYPE_VECTOR_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_VECTOR));
-
- add_options.push_back(AddOption("Add", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Adds vector to vector."), VisualShaderNodeVectorOp::OP_ADD, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Divide", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Divides vector by vector."), VisualShaderNodeVectorOp::OP_DIV, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Multiply", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Multiplies vector by vector."), VisualShaderNodeVectorOp::OP_MUL, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Remainder", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two vectors."), VisualShaderNodeVectorOp::OP_MOD, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts vector from vector."), VisualShaderNodeVectorOp::OP_SUB, VisualShaderNode::PORT_TYPE_VECTOR));
-
- add_options.push_back(AddOption("VectorConstant", "Vector", "Variables", "VisualShaderNodeVec3Constant", TTR("Vector constant."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
- add_options.push_back(AddOption("VectorUniform", "Vector", "Variables", "VisualShaderNodeVec3Uniform", TTR("Vector uniform."), -1, VisualShaderNode::PORT_TYPE_VECTOR));
+ add_options.push_back(AddOption("VectorFunc", "Vector", "Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("VectorOp", "Vector", "Common", "VisualShaderNodeVectorOp", TTR("Vector operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("VectorCompose", "Vector", "Common", "VisualShaderNodeVectorCompose", TTR("Composes vector from scalars.")));
+ add_options.push_back(AddOption("VectorDecompose", "Vector", "Common", "VisualShaderNodeVectorDecompose", TTR("Decomposes vector to scalars.")));
+
+ add_options.push_back(AddOption("Vector2Compose", "Vector", "Composition", "VisualShaderNodeVectorCompose", TTR("Composes 2D vector from two scalars."), { VisualShaderNodeVectorCompose::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Vector2Decompose", "Vector", "Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 2D vector to two scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_2D }));
+ add_options.push_back(AddOption("Vector3Compose", "Vector", "Composition", "VisualShaderNodeVectorCompose", TTR("Composes 3D vector from three scalars."), { VisualShaderNodeVectorCompose::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Vector3Decompose", "Vector", "Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 3D vector to three scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_3D }));
+ add_options.push_back(AddOption("Vector4Compose", "Vector", "Composition", "VisualShaderNodeVectorCompose", TTR("Composes 4D vector from four scalars."), { VisualShaderNodeVectorCompose::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Vector4Decompose", "Vector", "Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 4D vector to four scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_4D }));
+
+ add_options.push_back(AddOption("Abs", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Abs", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Abs", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ABS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ACos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("ACos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ACos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ACosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("ACosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ACosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ACOSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ASin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("ASin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ASin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ASinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("ASinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ASinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ASINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ATan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("ATan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ATan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ATan2", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("ATan2", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ATan2", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ATanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("ATanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("ATanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Ceil", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Ceil", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Ceil", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), { VisualShaderNodeClamp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Cos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Cos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Cos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("CosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("CosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("CosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Cross", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Calculates the cross product of two vectors."), { VisualShaderNodeVectorOp::OP_CROSS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Degrees", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Degrees", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Degrees", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeVectorFunc::FUNC_DEGREES, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("DFdX", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("DFdX", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("DFdX", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_X, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("DFdY", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("DFdY", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("DFdY", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), { VisualShaderNodeDerivativeFunc::FUNC_Y, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Distance2D", "Vector", "Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Distance3D", "Vector", "Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Distance4D", "Vector", "Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Dot", "Vector", "Functions", "VisualShaderNodeDotProduct", TTR("Calculates the dot product of two vectors."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Exp", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Exp", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Exp", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-e Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Exp2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Exp2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Exp2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 Exponential."), { VisualShaderNodeVectorFunc::FUNC_EXP2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("FaceForward", "Vector", "Functions", "VisualShaderNodeFaceForward", TTR("Returns the vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), { VisualShaderNodeFaceForward::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("FaceForward", "Vector", "Functions", "VisualShaderNodeFaceForward", TTR("Returns the vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), { VisualShaderNodeFaceForward::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("FaceForward", "Vector", "Functions", "VisualShaderNodeFaceForward", TTR("Returns the vector that points in the same direction as a reference vector. The function has three vector parameters : N, the vector to orient, I, the incident vector, and Nref, the reference vector. If the dot product of I and Nref is smaller than zero the return value is N. Otherwise -N is returned."), { VisualShaderNodeFaceForward::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Floor", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer less than or equal to the parameter."), { VisualShaderNodeVectorFunc::FUNC_FLOOR, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Fract", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeVectorFunc::FUNC_FRAC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Fresnel", "Vector", "Functions", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("InverseSqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse of the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_INVERSE_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Length", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Length", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Length", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Log", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Log", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Log", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Log2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Log2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Log2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), { VisualShaderNodeVectorOp::OP_MAX, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), { VisualShaderNodeVectorOp::OP_MAX, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), { VisualShaderNodeVectorOp::OP_MAX, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), { VisualShaderNodeVectorOp::OP_MIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), { VisualShaderNodeVectorOp::OP_MIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), { VisualShaderNodeVectorOp::OP_MIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Pow", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Radians", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Reflect", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), { VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("RoundEven", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("RoundEven", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("RoundEven", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUNDEVEN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Saturate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Saturate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Saturate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeVectorFunc::FUNC_SATURATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Sign", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Sign", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Sign", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIGN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), { VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Sum", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Sum", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Sum", "Vector", "Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+
+ add_options.push_back(AddOption("Add", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Adds 2D vector to 2D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Add", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Adds 3D vector to 3D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Add", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Adds 4D vector to 4D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Divide", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Divides 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Divide", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Divides 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Divide", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Divides 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Multiply", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Multiply", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Multiply", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Remainder", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 2D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Remainder", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 3D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Remainder", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 4D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 2D vector from 2D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 3D vector from 3D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Subtract", "Vector", "Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 4D vector from 4D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+
+ add_options.push_back(AddOption("Vector2Constant", "Vector", "Variables", "VisualShaderNodeVec2Constant", TTR("2D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Vector2Uniform", "Vector", "Variables", "VisualShaderNodeVec2Uniform", TTR("2D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Vector3Constant", "Vector", "Variables", "VisualShaderNodeVec3Constant", TTR("3D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Vector3Uniform", "Vector", "Variables", "VisualShaderNodeVec3Uniform", TTR("3D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Vector4Constant", "Vector", "Variables", "VisualShaderNodeVec4Constant", TTR("4D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Vector4Uniform", "Vector", "Variables", "VisualShaderNodeVec4Uniform", TTR("4D vector uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
// SPECIAL
add_options.push_back(AddOption("Comment", "Special", "", "VisualShaderNodeComment", TTR("A rectangular area with a description string for better graph organization.")));
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 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("UniformRef", "Special", "", "VisualShaderNodeUniformRef", TTR("A reference to an existing uniform.")));
+ add_options.push_back(AddOption("VaryingGetter", "Special", "", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("VaryingSetter", "Special", "", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("VaryingGetter", "Special", "", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("VaryingSetter", "Special", "", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_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, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
-
- add_options.push_back(AddOption("DdX", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("DdXS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("DdY", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("DdYS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("Sum", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeVectorDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("SumS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeScalarDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
custom_node_option_idx = add_options.size();
/////////////////////////////////////////////////////////////////////
@@ -4788,13 +5653,13 @@ void VisualShaderEditorPlugin::make_visible(bool p_visible) {
//editor->hide_animation_player_editors();
//editor->animation_panel_make_visible(true);
button->show();
- editor->make_bottom_panel_item_visible(visual_shader_editor);
- visual_shader_editor->update_custom_nodes();
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(visual_shader_editor);
+ visual_shader_editor->update_nodes();
visual_shader_editor->set_process_input(true);
//visual_shader_editor->set_process(true);
} else {
if (visual_shader_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
+ EditorNode::get_singleton()->hide_bottom_panel();
}
button->hide();
visual_shader_editor->set_process_input(false);
@@ -4802,12 +5667,11 @@ void VisualShaderEditorPlugin::make_visible(bool p_visible) {
}
}
-VisualShaderEditorPlugin::VisualShaderEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+VisualShaderEditorPlugin::VisualShaderEditorPlugin() {
visual_shader_editor = memnew(VisualShaderEditor);
visual_shader_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
- button = editor->add_bottom_panel_item(TTR("VisualShader"), visual_shader_editor);
+ button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("VisualShader"), visual_shader_editor);
button->hide();
}
@@ -4823,21 +5687,28 @@ class VisualShaderNodePluginInputEditor : public OptionButton {
public:
void _notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- connect("item_selected", callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected));
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ connect("item_selected", callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected));
+ } break;
}
}
void _item_selected(int p_item) {
- VisualShaderEditor::get_singleton()->call_deferred(SNAME("_input_select_item"), input, get_item_text(p_item));
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (editor) {
+ editor->call_deferred(SNAME("_input_select_item"), input, get_item_text(p_item));
+ }
}
void setup(const Ref<VisualShaderNodeInput> &p_input) {
input = p_input;
- Ref<Texture2D> type_icon[6] = {
+ Ref<Texture2D> type_icon[] = {
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ImageTexture"), SNAME("EditorIcons")),
@@ -4860,6 +5731,83 @@ public:
////////////////
+class VisualShaderNodePluginVaryingEditor : public OptionButton {
+ GDCLASS(VisualShaderNodePluginVaryingEditor, OptionButton);
+
+ Ref<VisualShaderNodeVarying> varying;
+
+public:
+ void _notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ connect("item_selected", callable_mp(this, &VisualShaderNodePluginVaryingEditor::_item_selected));
+ }
+ }
+
+ void _item_selected(int p_item) {
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (editor) {
+ editor->call_deferred(SNAME("_varying_select_item"), varying, get_item_text(p_item));
+ }
+ }
+
+ void setup(const Ref<VisualShaderNodeVarying> &p_varying, VisualShader::Type p_type) {
+ varying = p_varying;
+
+ Ref<Texture2D> type_icon[] = {
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Color"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),
+ };
+
+ bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
+
+ add_item("[None]");
+
+ int to_select = -1;
+ for (int i = 0, j = 0; i < varying->get_varyings_count(); i++) {
+ VisualShader::VaryingMode mode = varying->get_varying_mode_by_index(i);
+ if (is_getter) {
+ if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {
+ if (p_type != VisualShader::TYPE_LIGHT) {
+ j++;
+ continue;
+ }
+ } else {
+ if (p_type != VisualShader::TYPE_FRAGMENT && p_type != VisualShader::TYPE_LIGHT) {
+ j++;
+ continue;
+ }
+ }
+ } else {
+ if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {
+ if (p_type != VisualShader::TYPE_FRAGMENT) {
+ j++;
+ continue;
+ }
+ } else {
+ if (p_type != VisualShader::TYPE_VERTEX) {
+ j++;
+ continue;
+ }
+ }
+ }
+ if (varying->get_varying_name() == varying->get_varying_name_by_index(i)) {
+ to_select = i - j + 1;
+ }
+ add_icon_item(type_icon[varying->get_varying_type_by_index(i)], varying->get_varying_name_by_index(i));
+ }
+
+ if (to_select >= 0) {
+ select(to_select);
+ }
+ }
+};
+
+////////////////
+
class VisualShaderNodePluginUniformRefEditor : public OptionButton {
GDCLASS(VisualShaderNodePluginUniformRefEditor, OptionButton);
@@ -4867,23 +5815,30 @@ class VisualShaderNodePluginUniformRefEditor : public OptionButton {
public:
void _notification(int p_what) {
- if (p_what == NOTIFICATION_READY) {
- connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected));
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected));
+ } break;
}
}
void _item_selected(int p_item) {
- VisualShaderEditor::get_singleton()->call_deferred(SNAME("_uniform_select_item"), uniform_ref, get_item_text(p_item));
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (editor) {
+ editor->call_deferred(SNAME("_uniform_select_item"), uniform_ref, get_item_text(p_item));
+ }
}
void setup(const Ref<VisualShaderNodeUniformRef> &p_uniform_ref) {
uniform_ref = p_uniform_ref;
- Ref<Texture2D> type_icon[7] = {
+ Ref<Texture2D> type_icon[] = {
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Color"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ImageTexture"), SNAME("EditorIcons")),
@@ -4909,7 +5864,7 @@ public:
class VisualShaderNodePluginDefaultEditor : public VBoxContainer {
GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer);
Ref<Resource> parent_resource;
- int node_id;
+ int node_id = 0;
VisualShader::Type shader_type;
public:
@@ -4926,23 +5881,29 @@ public:
undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property));
if (p_value.get_type() == Variant::OBJECT) {
- RES prev_res = node->get(p_property);
- RES curr_res = p_value;
+ Ref<Resource> prev_res = node->get(p_property);
+ Ref<Resource> curr_res = p_value;
if (curr_res.is_null()) {
- undo_redo->add_do_method(this, "_open_inspector", (RES)parent_resource.ptr());
+ undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());
} else {
- undo_redo->add_do_method(this, "_open_inspector", (RES)curr_res.ptr());
+ undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)curr_res.ptr());
}
if (!prev_res.is_null()) {
- undo_redo->add_undo_method(this, "_open_inspector", (RES)prev_res.ptr());
+ undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)prev_res.ptr());
} else {
- undo_redo->add_undo_method(this, "_open_inspector", (RES)parent_resource.ptr());
+ undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());
}
}
if (p_property != "constant") {
- undo_redo->add_do_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_node_deferred", shader_type, node_id);
- undo_redo->add_undo_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_node_deferred", shader_type, node_id);
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (editor) {
+ VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();
+ if (graph_plugin) {
+ undo_redo->add_do_method(graph_plugin, "update_node_deferred", shader_type, node_id);
+ undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);
+ }
+ }
}
undo_redo->commit_action();
@@ -4958,15 +5919,15 @@ public:
}
}
- void _resource_selected(const String &p_path, RES p_resource) {
+ void _resource_selected(const String &p_path, Ref<Resource> p_resource) {
_open_inspector(p_resource);
}
- void _open_inspector(RES p_resource) {
- EditorNode::get_singleton()->get_inspector()->edit(p_resource.ptr());
+ void _open_inspector(Ref<Resource> p_resource) {
+ InspectorDock::get_inspector_singleton()->edit(p_resource.ptr());
}
- bool updating;
+ bool updating = false;
Ref<VisualShaderNode> node;
Vector<EditorProperty *> properties;
Vector<Label *> prop_names;
@@ -4977,7 +5938,7 @@ public:
}
}
- void setup(Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, Ref<VisualShaderNode> p_node) {
+ void setup(Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, const Map<StringName, String> &p_overrided_names, Ref<VisualShaderNode> p_node) {
parent_resource = p_parent_resource;
updating = false;
node = p_node;
@@ -4993,7 +5954,11 @@ public:
Label *prop_name = memnew(Label);
String prop_name_str = p_names[i];
- prop_name_str = prop_name_str.capitalize() + ":";
+ if (p_overrided_names.has(p_names[i])) {
+ prop_name_str = p_overrided_names[p_names[i]] + ":";
+ } else {
+ prop_name_str = prop_name_str.capitalize() + ":";
+ }
prop_name->set_text(prop_name_str);
prop_name->set_visible(false);
hbox->add_child(prop_name);
@@ -5022,18 +5987,24 @@ public:
};
Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {
+ Ref<VisualShader> p_shader = Ref<VisualShader>(p_parent_resource.ptr());
+
+ if (p_shader.is_valid() && (p_node->is_class("VisualShaderNodeVaryingGetter") || p_node->is_class("VisualShaderNodeVaryingSetter"))) {
+ VisualShaderNodePluginVaryingEditor *editor = memnew(VisualShaderNodePluginVaryingEditor);
+ editor->setup(p_node, p_shader->get_shader_type());
+ return editor;
+ }
+
if (p_node->is_class("VisualShaderNodeUniformRef")) {
- //create input
- VisualShaderNodePluginUniformRefEditor *uniform_editor = memnew(VisualShaderNodePluginUniformRefEditor);
- uniform_editor->setup(p_node);
- return uniform_editor;
+ VisualShaderNodePluginUniformRefEditor *editor = memnew(VisualShaderNodePluginUniformRefEditor);
+ editor->setup(p_node);
+ return editor;
}
if (p_node->is_class("VisualShaderNodeInput")) {
- //create input
- VisualShaderNodePluginInputEditor *input_editor = memnew(VisualShaderNodePluginInputEditor);
- input_editor->setup(p_node);
- return input_editor;
+ VisualShaderNodePluginInputEditor *editor = memnew(VisualShaderNodePluginInputEditor);
+ editor->setup(p_node);
+ return editor;
}
Vector<StringName> properties = p_node->get_editable_properties();
@@ -5074,6 +6045,8 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
} else if (Object::cast_to<EditorPropertyTransform3D>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) {
prop->set_custom_minimum_size(Size2(250 * EDSCALE, 0));
+ } else if (Object::cast_to<EditorPropertyQuaternion>(prop)) {
+ prop->set_custom_minimum_size(Size2(320 * EDSCALE, 0));
} else if (Object::cast_to<EditorPropertyFloat>(prop)) {
prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
} else if (Object::cast_to<EditorPropertyEnum>(prop)) {
@@ -5085,11 +6058,16 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
properties.push_back(pinfo[i].name);
}
VisualShaderNodePluginDefaultEditor *editor = memnew(VisualShaderNodePluginDefaultEditor);
- editor->setup(p_parent_resource, editors, properties, p_node);
+ editor->setup(p_parent_resource, editors, properties, p_node->get_editable_properties_names(), p_node);
return editor;
}
void EditorPropertyShaderMode::_option_selected(int p_which) {
+ VisualShaderEditor *editor = VisualShaderEditor::get_singleton();
+ if (!editor) {
+ return;
+ }
+
//will not use this, instead will do all the logic setting manually
//emit_signal(SNAME("property_changed"), get_edited_property(), p_which);
@@ -5105,8 +6083,8 @@ void EditorPropertyShaderMode::_option_selected(int p_which) {
undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);
undo_redo->add_undo_method(visual_shader.ptr(), "set_mode", visual_shader->get_mode());
- undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_set_mode", p_which);
- undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_set_mode", visual_shader->get_mode());
+ undo_redo->add_do_method(editor, "_set_mode", p_which);
+ undo_redo->add_undo_method(editor, "_set_mode", visual_shader->get_mode());
//now undo is hell
@@ -5145,12 +6123,27 @@ void EditorPropertyShaderMode::_option_selected(int p_which) {
}
}
- undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_options_menu");
- undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_options_menu");
+ //4. delete varyings (if needed)
+ if (p_which == VisualShader::MODE_PARTICLES || p_which == VisualShader::MODE_SKY || p_which == VisualShader::MODE_FOG) {
+ int var_count = visual_shader->get_varyings_count();
+
+ if (var_count > 0) {
+ for (int i = 0; i < var_count; i++) {
+ const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);
+ undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", var->name);
+ undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", var->name, var->mode, var->type);
+ }
+
+ undo_redo->add_do_method(editor, "_update_varyings");
+ undo_redo->add_undo_method(editor, "_update_varyings");
+ }
+ }
- //update graph
- undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph");
- undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph");
+ undo_redo->add_do_method(editor, "_update_nodes");
+ undo_redo->add_undo_method(editor, "_update_nodes");
+
+ undo_redo->add_do_method(editor, "_update_graph");
+ undo_redo->add_undo_method(editor, "_update_graph");
undo_redo->commit_action();
}
@@ -5182,11 +6175,7 @@ EditorPropertyShaderMode::EditorPropertyShaderMode() {
}
bool EditorInspectorShaderModePlugin::can_handle(Object *p_object) {
- return true; //can handle everything
-}
-
-void EditorInspectorShaderModePlugin::parse_begin(Object *p_object) {
- //do none
+ return true; // Can handle everything.
}
bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
@@ -5199,11 +6188,7 @@ bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, const Var
return true;
}
- return false; //can be overridden, although it will most likely be last anyway
-}
-
-void EditorInspectorShaderModePlugin::parse_end() {
- //do none
+ return false;
}
//////////////////////////////////
@@ -5220,7 +6205,9 @@ void VisualShaderNodePortPreview::_shader_changed() {
preview_shader.instantiate();
preview_shader->set_code(shader_code);
for (int i = 0; i < default_textures.size(); i++) {
- preview_shader->set_default_texture_param(default_textures[i].name, default_textures[i].param);
+ for (int j = 0; j < default_textures[i].params.size(); j++) {
+ preview_shader->set_default_texture_param(default_textures[i].name, default_textures[i].params[j], j);
+ }
}
Ref<ShaderMaterial> material;
@@ -5229,8 +6216,8 @@ void VisualShaderNodePortPreview::_shader_changed() {
//find if a material is also being edited and copy parameters to this one
- for (int i = EditorNode::get_singleton()->get_editor_history()->get_path_size() - 1; i >= 0; i--) {
- Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_history()->get_path_object(i));
+ for (int i = EditorNode::get_singleton()->get_editor_selection_history()->get_path_size() - 1; i >= 0; i--) {
+ Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_path_object(i));
ShaderMaterial *src_mat;
if (!object) {
continue;
@@ -5269,24 +6256,31 @@ Size2 VisualShaderNodePortPreview::get_minimum_size() const {
}
void VisualShaderNodePortPreview::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
- Vector<Vector2> points;
- Vector<Vector2> uvs;
- Vector<Color> colors;
- points.push_back(Vector2());
- uvs.push_back(Vector2(0, 0));
- colors.push_back(Color(1, 1, 1, 1));
- points.push_back(Vector2(get_size().width, 0));
- uvs.push_back(Vector2(1, 0));
- colors.push_back(Color(1, 1, 1, 1));
- points.push_back(get_size());
- uvs.push_back(Vector2(1, 1));
- colors.push_back(Color(1, 1, 1, 1));
- points.push_back(Vector2(0, get_size().height));
- uvs.push_back(Vector2(0, 1));
- colors.push_back(Color(1, 1, 1, 1));
-
- draw_primitive(points, colors, uvs);
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
+ Vector<Vector2> points = {
+ Vector2(),
+ Vector2(get_size().width, 0),
+ get_size(),
+ Vector2(0, get_size().height)
+ };
+
+ Vector<Vector2> uvs = {
+ Vector2(0, 0),
+ Vector2(1, 0),
+ Vector2(1, 1),
+ Vector2(0, 1)
+ };
+
+ Vector<Color> colors = {
+ Color(1, 1, 1, 1),
+ Color(1, 1, 1, 1),
+ Color(1, 1, 1, 1),
+ Color(1, 1, 1, 1)
+ };
+
+ draw_primitive(points, colors, uvs);
+ } break;
}
}
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index c4a392469b..540cb709b3 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,13 +31,14 @@
#ifndef VISUAL_SHADER_EDITOR_PLUGIN_H
#define VISUAL_SHADER_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/gui/button.h"
+#include "scene/gui/code_edit.h"
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
+#include "scene/gui/rich_text_label.h"
#include "scene/gui/tree.h"
#include "scene/resources/visual_shader.h"
@@ -47,7 +48,7 @@ class VisualShaderNodePlugin : public RefCounted {
protected:
static void _bind_methods();
- GDVIRTUAL2RC(Object *, _create_editor, RES, Ref<VisualShaderNode>)
+ GDVIRTUAL2RC(Object *, _create_editor, Ref<Resource>, Ref<VisualShaderNode>)
public:
virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node);
@@ -84,14 +85,14 @@ private:
List<VisualShader::Connection> connections;
bool dirty = false;
- Color vector_expanded_color[3];
+ Color vector_expanded_color[4];
protected:
static void _bind_methods();
public:
void register_shader(VisualShader *p_visual_shader);
- void set_connections(List<VisualShader::Connection> &p_connections);
+ void set_connections(const List<VisualShader::Connection> &p_connections);
void register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node);
void register_output_port(int p_id, int p_port, TextureButton *p_button);
void register_uniform_name(int p_id, LineEdit *p_uniform_name);
@@ -131,42 +132,53 @@ class VisualShaderEditor : public VBoxContainer {
GDCLASS(VisualShaderEditor, VBoxContainer);
friend class VisualShaderGraphPlugin;
- CustomPropertyEditor *property_editor;
- int editing_node;
- int editing_port;
+ CustomPropertyEditor *property_editor = nullptr;
+ int editing_node = -1;
+ int editing_port = -1;
Ref<VisualShader> visual_shader;
- GraphEdit *graph;
- Button *add_node;
- Button *preview_shader;
+ GraphEdit *graph = nullptr;
+ Button *add_node = nullptr;
+ Button *varying_button = nullptr;
+ PopupMenu *varying_options = nullptr;
+ Button *preview_shader = nullptr;
OptionButton *edit_type = nullptr;
- OptionButton *edit_type_standard;
- OptionButton *edit_type_particles;
- OptionButton *edit_type_sky;
- OptionButton *edit_type_fog;
- CheckBox *custom_mode_box;
+ OptionButton *edit_type_standard = nullptr;
+ OptionButton *edit_type_particles = nullptr;
+ OptionButton *edit_type_sky = nullptr;
+ OptionButton *edit_type_fog = nullptr;
+ CheckBox *custom_mode_box = nullptr;
bool custom_mode_enabled = false;
- bool pending_update_preview;
- bool shader_error;
- Window *preview_window;
- VBoxContainer *preview_vbox;
- CodeEdit *preview_text;
- Ref<CodeHighlighter> syntax_highlighter;
- PanelContainer *error_panel;
- Label *error_label;
+ bool pending_update_preview = false;
+ bool shader_error = false;
+ Window *preview_window = nullptr;
+ VBoxContainer *preview_vbox = nullptr;
+ CodeEdit *preview_text = nullptr;
+ Ref<CodeHighlighter> syntax_highlighter = nullptr;
+ PanelContainer *error_panel = nullptr;
+ Label *error_label = nullptr;
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
Point2 saved_node_pos;
- bool saved_node_pos_dirty;
+ bool saved_node_pos_dirty = false;
- ConfirmationDialog *members_dialog;
+ ConfirmationDialog *members_dialog = nullptr;
VisualShaderNode::PortType members_input_port_type = VisualShaderNode::PORT_TYPE_MAX;
VisualShaderNode::PortType members_output_port_type = VisualShaderNode::PORT_TYPE_MAX;
- PopupMenu *popup_menu;
+ PopupMenu *popup_menu = nullptr;
PopupMenu *constants_submenu = nullptr;
- MenuButton *tools;
+ MenuButton *tools = nullptr;
+
+ ConfirmationDialog *add_varying_dialog = nullptr;
+ OptionButton *varying_type = nullptr;
+ LineEdit *varying_name = nullptr;
+ OptionButton *varying_mode = nullptr;
+ Label *varying_error_label = nullptr;
+
+ ConfirmationDialog *remove_varying_dialog = nullptr;
+ Tree *varyings = nullptr;
PopupPanel *comment_title_change_popup = nullptr;
LineEdit *comment_title_change_edit = nullptr;
@@ -231,15 +243,26 @@ class VisualShaderEditor : public VBoxContainer {
SET_COMMENT_DESCRIPTION,
};
- Tree *members;
- AcceptDialog *alert;
- LineEdit *node_filter;
- RichTextLabel *node_desc;
- Label *highend_label;
+ enum class VaryingMenuOptions {
+ ADD,
+ REMOVE,
+ };
+
+ Tree *members = nullptr;
+ AcceptDialog *alert = nullptr;
+ LineEdit *node_filter = nullptr;
+ RichTextLabel *node_desc = nullptr;
+ Label *highend_label = nullptr;
void _tools_menu_option(int p_idx);
void _show_members_dialog(bool at_mouse_pos, VisualShaderNode::PortType p_input_port_type = VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PortType p_output_port_type = VisualShaderNode::PORT_TYPE_MAX);
+ void _show_varying_menu();
+ void _varying_menu_id_pressed(int p_idx);
+ void _show_add_varying_dialog();
+ void _show_remove_varying_dialog();
+
+ void _update_nodes();
void _update_graph();
struct AddOption {
@@ -247,44 +270,25 @@ class VisualShaderEditor : public VBoxContainer {
String category;
String type;
String description;
- int sub_func = 0;
- String sub_func_str;
+ Vector<Variant> ops;
Ref<Script> script;
int mode = 0;
int return_type = 0;
int func = 0;
- float value = 0;
bool highend = false;
bool is_custom = false;
int temp_idx = 0;
- AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) {
+ AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), const Vector<Variant> &p_ops = Vector<Variant>(), int p_return_type = -1, int p_mode = -1, int p_func = -1, bool p_highend = false) {
name = p_name;
type = p_type;
category = p_category + "/" + p_sub_category;
description = p_description;
- sub_func = p_sub_func;
+ ops = p_ops;
return_type = p_return_type;
mode = p_mode;
func = p_func;
- value = p_value;
highend = p_highend;
- is_custom = false;
- }
-
- AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) {
- name = p_name;
- type = p_type;
- category = p_category + "/" + p_sub_category;
- description = p_description;
- sub_func = 0;
- sub_func_str = p_sub_func;
- return_type = p_return_type;
- mode = p_mode;
- func = p_func;
- value = p_value;
- highend = p_highend;
- is_custom = false;
}
};
struct _OptionComparator {
@@ -307,8 +311,10 @@ class VisualShaderEditor : public VBoxContainer {
void _draw_color_over_button(Object *obj, Color p_color);
- void _setup_node(VisualShaderNode *p_node, int p_op_idx);
- void _add_node(int p_idx, int p_op_idx = -1, String p_resource_path = "", int p_node_idx = -1);
+ void _setup_node(VisualShaderNode *p_node, const Vector<Variant> &p_ops);
+ void _add_node(int p_idx, const Vector<Variant> &p_ops, String p_resource_path = "", int p_node_idx = -1);
+ void _add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type);
+ void _remove_varying(const String &p_name);
void _update_options_menu();
void _set_mode(int p_which);
@@ -330,7 +336,7 @@ class VisualShaderEditor : public VBoxContainer {
bool drag_dirty = false;
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node);
void _nodes_dragged();
- bool updating;
+ bool updating = false;
void _connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index);
void _disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index);
@@ -347,10 +353,10 @@ class VisualShaderEditor : public VBoxContainer {
void _edit_port_default_input(Object *p_button, int p_node, int p_port);
void _port_edited();
- int to_node;
- int to_slot;
- int from_node;
- int from_slot;
+ int to_node = -1;
+ int to_slot = -1;
+ int from_node = -1;
+ int from_slot = -1;
Set<int> selected_constants;
Set<int> selected_uniforms;
@@ -389,6 +395,7 @@ class VisualShaderEditor : public VBoxContainer {
String group_inputs;
String group_outputs;
String expression;
+ bool disabled = false;
};
void _dup_copy_nodes(int p_type, List<CopyItem> &r_nodes, List<VisualShader::Connection> &r_connections);
@@ -412,6 +419,7 @@ class VisualShaderEditor : public VBoxContainer {
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name);
+ void _varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name);
void _float_constant_selected(int p_which);
@@ -443,6 +451,13 @@ class VisualShaderEditor : public VBoxContainer {
void _member_create();
void _member_cancel();
+ void _varying_create();
+ void _varying_name_changed(const String &p_text);
+ void _varying_deleted();
+ void _varying_selected();
+ void _varying_unselected();
+ void _update_varying_tree();
+
Vector2 menu_point;
void _node_menu_id_pressed(int p_idx);
@@ -454,6 +469,7 @@ class VisualShaderEditor : public VBoxContainer {
void _update_created_node(GraphNode *node);
void _update_uniforms(bool p_update_refs);
void _update_uniform_refs(Set<String> &p_names);
+ void _update_varyings();
void _visibility_changed();
@@ -462,7 +478,7 @@ protected:
static void _bind_methods();
public:
- void update_custom_nodes();
+ void update_nodes();
void add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin);
void remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin);
@@ -480,9 +496,8 @@ public:
class VisualShaderEditorPlugin : public EditorPlugin {
GDCLASS(VisualShaderEditorPlugin, EditorPlugin);
- VisualShaderEditor *visual_shader_editor;
- EditorNode *editor;
- Button *button;
+ VisualShaderEditor *visual_shader_editor = nullptr;
+ Button *button = nullptr;
public:
virtual String get_name() const override { return "VisualShader"; }
@@ -491,7 +506,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- VisualShaderEditorPlugin(EditorNode *p_node);
+ VisualShaderEditorPlugin();
~VisualShaderEditorPlugin();
};
@@ -504,7 +519,7 @@ public:
class EditorPropertyShaderMode : public EditorProperty {
GDCLASS(EditorPropertyShaderMode, EditorProperty);
- OptionButton *options;
+ OptionButton *options = nullptr;
void _option_selected(int p_which);
@@ -523,9 +538,7 @@ class EditorInspectorShaderModePlugin : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual void parse_begin(Object *p_object) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
- virtual void parse_end() override;
};
class VisualShaderNodePortPreview : public Control {
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index 9a44d40dcb..6fc6c1ad39 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -30,11 +30,14 @@
#include "voxel_gi_editor_plugin.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+
void VoxelGIEditorPlugin::_bake() {
if (voxel_gi) {
if (voxel_gi->get_probe_data().is_null()) {
String path = get_tree()->get_edited_scene_root()->get_scene_file_path();
- if (path == String()) {
+ if (path.is_empty()) {
path = "res://" + voxel_gi->get_name() + "_data.res";
} else {
String ext = path.get_extension();
@@ -62,36 +65,43 @@ bool VoxelGIEditorPlugin::handles(Object *p_object) const {
}
void VoxelGIEditorPlugin::_notification(int p_what) {
- if (p_what == NOTIFICATION_PROCESS) {
- if (!voxel_gi) {
- return;
- }
+ switch (p_what) {
+ case NOTIFICATION_PROCESS: {
+ if (!voxel_gi) {
+ return;
+ }
- const Vector3i size = voxel_gi->get_estimated_cell_size();
- String text = vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z);
- const int data_size = 4;
- const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0);
- text += " - " + vformat(TTR("VRAM Size: %s MB"), String::num(size_mb, 2));
+ // Set information tooltip on the Bake button. This information is useful
+ // to optimize performance (video RAM size) and reduce light leaking (individual cell size).
- if (bake_info->get_text() == text) {
- return;
- }
+ const Vector3i size = voxel_gi->get_estimated_cell_size();
- // Color the label depending on the estimated performance level.
- Color color;
- if (size_mb <= 16.0 + CMP_EPSILON) {
- // Fast.
- color = bake_info->get_theme_color(SNAME("success_color"), SNAME("Editor"));
- } else if (size_mb <= 64.0 + CMP_EPSILON) {
- // Medium.
- color = bake_info->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- } else {
- // Slow.
- color = bake_info->get_theme_color(SNAME("error_color"), SNAME("Editor"));
- }
- bake_info->add_theme_color_override("font_color", color);
+ const Vector3 extents = voxel_gi->get_extents();
+
+ const int data_size = 4;
+ const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0);
+ // Add a qualitative measurement to help the user assess whether a VoxelGI node is using a lot of VRAM.
+ String size_quality;
+ if (size_mb < 16.0) {
+ size_quality = TTR("Low");
+ } else if (size_mb < 64.0) {
+ size_quality = TTR("Moderate");
+ } else {
+ size_quality = TTR("High");
+ }
+
+ String text;
+ text += vformat(TTR("Subdivisions: %s"), vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z)) + "\n";
+ text += vformat(TTR("Cell size: %s"), vformat(String::utf8("%.3f × %.3f × %.3f"), extents.x / size.x, extents.y / size.y, extents.z / size.z)) + "\n";
+ text += vformat(TTR("Video RAM size: %s MB (%s)"), String::num(size_mb, 2), size_quality);
+
+ // Only update the tooltip when needed to avoid constant redrawing.
+ if (bake->get_tooltip(Point2()) == text) {
+ return;
+ }
- bake_info->set_text(text);
+ bake->set_tooltip(text);
+ } break;
}
}
@@ -110,7 +120,7 @@ EditorProgress *VoxelGIEditorPlugin::tmp_progress = nullptr;
void VoxelGIEditorPlugin::bake_func_begin(int p_steps) {
ERR_FAIL_COND(tmp_progress != nullptr);
- tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake GI Probe"), p_steps));
+ tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake VoxelGI"), p_steps));
}
void VoxelGIEditorPlugin::bake_func_step(int p_step, const String &p_description) {
@@ -136,21 +146,16 @@ void VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake(const String &p_path) {
void VoxelGIEditorPlugin::_bind_methods() {
}
-VoxelGIEditorPlugin::VoxelGIEditorPlugin(EditorNode *p_node) {
- editor = p_node;
+VoxelGIEditorPlugin::VoxelGIEditorPlugin() {
bake_hb = memnew(HBoxContainer);
bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bake_hb->hide();
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(editor->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
- bake->set_text(TTR("Bake GI Probe"));
+ bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
+ bake->set_text(TTR("Bake VoxelGI"));
bake->connect("pressed", callable_mp(this, &VoxelGIEditorPlugin::_bake));
bake_hb->add_child(bake);
- bake_info = memnew(Label);
- bake_info->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- bake_info->set_clip_text(true);
- bake_hb->add_child(bake_info);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb);
voxel_gi = nullptr;
diff --git a/editor/plugins/voxel_gi_editor_plugin.h b/editor/plugins/voxel_gi_editor_plugin.h
index 4d3cfe90f6..621e98beef 100644
--- a/editor/plugins/voxel_gi_editor_plugin.h
+++ b/editor/plugins/voxel_gi_editor_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -31,22 +31,22 @@
#ifndef VOXEL_GIEDITORPLUGIN_H
#define VOXEL_GIEDITORPLUGIN_H
-#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/voxel_gi.h"
#include "scene/resources/material.h"
+class EditorFileDialog;
+struct EditorProgress;
+
class VoxelGIEditorPlugin : public EditorPlugin {
GDCLASS(VoxelGIEditorPlugin, EditorPlugin);
- VoxelGI *voxel_gi;
+ VoxelGI *voxel_gi = nullptr;
- HBoxContainer *bake_hb;
- Label *bake_info;
- Button *bake;
- EditorNode *editor;
+ HBoxContainer *bake_hb = nullptr;
+ Button *bake = nullptr;
- EditorFileDialog *probe_file;
+ EditorFileDialog *probe_file = nullptr;
static EditorProgress *tmp_progress;
static void bake_func_begin(int p_steps);
@@ -67,7 +67,7 @@ public:
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
- VoxelGIEditorPlugin(EditorNode *p_node);
+ VoxelGIEditorPlugin();
~VoxelGIEditorPlugin();
};