summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/action_map_editor.cpp87
-rw-r--r--editor/action_map_editor.h14
-rw-r--r--editor/animation_bezier_editor.cpp630
-rw-r--r--editor/animation_bezier_editor.h46
-rw-r--r--editor/animation_track_editor.cpp1070
-rw-r--r--editor/animation_track_editor.h54
-rw-r--r--editor/animation_track_editor_plugins.cpp13
-rw-r--r--editor/array_property_edit.cpp7
-rw-r--r--editor/code_editor.cpp39
-rw-r--r--editor/connections_dialog.cpp63
-rw-r--r--editor/connections_dialog.h15
-rw-r--r--editor/create_dialog.cpp22
-rw-r--r--editor/create_dialog.h2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp2
-rw-r--r--editor/debugger/editor_debugger_inspector.cpp1
-rw-r--r--editor/debugger/editor_debugger_inspector.h1
-rw-r--r--editor/debugger/editor_debugger_node.cpp8
-rw-r--r--editor/debugger/editor_debugger_node.h2
-rw-r--r--editor/debugger/editor_debugger_tree.cpp2
-rw-r--r--editor/debugger/editor_performance_profiler.cpp14
-rw-r--r--editor/debugger/editor_profiler.cpp14
-rw-r--r--editor/debugger/editor_visual_profiler.cpp10
-rw-r--r--editor/debugger/script_editor_debugger.cpp27
-rw-r--r--editor/dictionary_property_edit.cpp5
-rw-r--r--editor/doc_tools.cpp21
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_asset_installer.cpp4
-rw-r--r--editor/editor_atlas_packer.cpp4
-rw-r--r--editor/editor_audio_buses.cpp71
-rw-r--r--editor/editor_autoload_settings.cpp17
-rw-r--r--editor/editor_data.cpp110
-rw-r--r--editor/editor_data.h25
-rw-r--r--editor/editor_dir_dialog.cpp4
-rw-r--r--editor/editor_feature_profile.cpp18
-rw-r--r--editor/editor_file_dialog.cpp298
-rw-r--r--editor/editor_file_dialog.h30
-rw-r--r--editor/editor_file_system.cpp35
-rw-r--r--editor/editor_folding.cpp10
-rw-r--r--editor/editor_fonts.cpp82
-rw-r--r--editor/editor_help.cpp72
-rw-r--r--editor/editor_help.h1
-rw-r--r--editor/editor_help_search.cpp76
-rw-r--r--editor/editor_help_search.h9
-rw-r--r--editor/editor_inspector.cpp221
-rw-r--r--editor/editor_inspector.h22
-rw-r--r--editor/editor_locale_dialog.cpp9
-rw-r--r--editor/editor_locale_dialog.h4
-rw-r--r--editor/editor_log.cpp41
-rw-r--r--editor/editor_log.h15
-rw-r--r--editor/editor_node.cpp912
-rw-r--r--editor/editor_node.h49
-rw-r--r--editor/editor_path.cpp39
-rw-r--r--editor/editor_paths.cpp28
-rw-r--r--editor/editor_plugin.cpp37
-rw-r--r--editor/editor_plugin.h16
-rw-r--r--editor/editor_plugin_settings.cpp6
-rw-r--r--editor/editor_properties.cpp302
-rw-r--r--editor/editor_properties.h22
-rw-r--r--editor/editor_properties_array_dict.cpp8
-rw-r--r--editor/editor_properties_array_dict.h2
-rw-r--r--editor/editor_property_name_processor.cpp7
-rw-r--r--editor/editor_resource_picker.cpp134
-rw-r--r--editor/editor_resource_picker.h2
-rw-r--r--editor/editor_resource_preview.cpp2
-rw-r--r--editor/editor_run.cpp14
-rw-r--r--editor/editor_run_native.cpp4
-rw-r--r--editor/editor_sectioned_inspector.cpp17
-rw-r--r--editor/editor_settings.cpp77
-rw-r--r--editor/editor_settings.h8
-rw-r--r--editor/editor_settings_dialog.cpp16
-rw-r--r--editor/editor_settings_dialog.h4
-rw-r--r--editor/editor_spin_slider.cpp44
-rw-r--r--editor/editor_spin_slider.h2
-rw-r--r--editor/editor_themes.cpp534
-rw-r--r--editor/editor_themes.h16
-rw-r--r--editor/editor_title_bar.cpp86
-rw-r--r--editor/editor_title_bar.h53
-rw-r--r--editor/editor_toaster.cpp33
-rw-r--r--editor/editor_translation_parser.cpp4
-rw-r--r--editor/editor_translation_parser.h3
-rw-r--r--editor/editor_undo_redo_manager.cpp442
-rw-r--r--editor/editor_undo_redo_manager.h134
-rw-r--r--editor/editor_vcs_interface.cpp389
-rw-r--r--editor/editor_vcs_interface.h141
-rw-r--r--editor/editor_zoom_widget.cpp4
-rw-r--r--editor/export/editor_export.cpp4
-rw-r--r--editor/export/editor_export_platform.cpp600
-rw-r--r--editor/export/editor_export_platform.h41
-rw-r--r--editor/export/editor_export_platform_pc.cpp10
-rw-r--r--editor/export/editor_export_platform_pc.h3
-rw-r--r--editor/export/editor_export_plugin.cpp96
-rw-r--r--editor/export/editor_export_plugin.h35
-rw-r--r--editor/export/editor_export_preset.cpp5
-rw-r--r--editor/export/editor_export_preset.h1
-rw-r--r--editor/export/export_template_manager.cpp50
-rw-r--r--editor/export/project_export.cpp13
-rw-r--r--editor/filesystem_dock.cpp56
-rw-r--r--editor/find_in_files.cpp6
-rw-r--r--editor/groups_editor.cpp11
-rw-r--r--editor/groups_editor.h11
-rw-r--r--editor/icons/BezierHandlesBalanced.svg2
-rw-r--r--editor/icons/BezierHandlesFree.svg2
-rw-r--r--editor/icons/BezierHandlesLinear.svg1
-rw-r--r--editor/icons/BezierHandlesMirror.svg2
-rw-r--r--editor/icons/BoxContainer.svg1
-rw-r--r--editor/icons/CameraAttributes.svg (renamed from editor/icons/CameraEffects.svg)0
-rw-r--r--editor/icons/ContainerLayout.svg1
-rw-r--r--editor/icons/ControlLayout.svg2
-rw-r--r--editor/icons/CurveIn.svg2
-rw-r--r--editor/icons/CurveInOut.svg2
-rw-r--r--editor/icons/CurveLinear.svg2
-rw-r--r--editor/icons/CurveOut.svg2
-rw-r--r--editor/icons/CurveOutIn.svg2
-rw-r--r--editor/icons/DefaultProjectIcon.svg2
-rw-r--r--editor/icons/FlowContainer.svg1
-rw-r--r--editor/icons/InterpCubicAngle.svg1
-rw-r--r--editor/icons/InterpLinearAngle.svg1
-rw-r--r--editor/icons/Marker2D.svg (renamed from editor/icons/Position2D.svg)0
-rw-r--r--editor/icons/Marker3D.svg (renamed from editor/icons/Position3D.svg)0
-rw-r--r--editor/icons/MemberAnnotation.svg1
-rw-r--r--editor/icons/MenuBar.svg1
-rw-r--r--editor/icons/NavigationLink2D.svg4
-rw-r--r--editor/icons/NavigationLink3D.svg4
-rw-r--r--editor/icons/NodeInfo.svg1
-rw-r--r--editor/icons/ParticleProcessMaterial.svg (renamed from editor/icons/ParticlesMaterial.svg)0
-rw-r--r--editor/icons/RigidBody2D.svg (renamed from editor/icons/RigidDynamicBody2D.svg)0
-rw-r--r--editor/icons/RigidBody3D.svg (renamed from editor/icons/RigidDynamicBody3D.svg)0
-rw-r--r--editor/icons/SceneUniqueName.svg3
-rw-r--r--editor/icons/SoftBody3D.svg (renamed from editor/icons/SoftDynamicBody3D.svg)0
-rw-r--r--editor/icons/SplitContainer.svg1
-rw-r--r--editor/icons/VcsBranches.svg1
-rw-r--r--editor/import/audio_stream_import_settings.cpp64
-rw-r--r--editor/import/collada.cpp6
-rw-r--r--editor/import/dynamic_font_import_settings.cpp26
-rw-r--r--editor/import/editor_import_plugin.cpp4
-rw-r--r--editor/import/editor_import_plugin.h5
-rw-r--r--editor/import/post_import_plugin_skeleton_renamer.cpp2
-rw-r--r--editor/import/post_import_plugin_skeleton_rest_fixer.cpp458
-rw-r--r--editor/import/resource_importer_bitmask.cpp2
-rw-r--r--editor/import/resource_importer_dynamic_font.cpp6
-rw-r--r--editor/import/resource_importer_imagefont.cpp2
-rw-r--r--editor/import/resource_importer_layered_texture.cpp9
-rw-r--r--editor/import/resource_importer_obj.cpp10
-rw-r--r--editor/import/resource_importer_scene.cpp221
-rw-r--r--editor/import/resource_importer_scene.h2
-rw-r--r--editor/import/resource_importer_shader_file.cpp2
-rw-r--r--editor/import/resource_importer_texture.cpp29
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp1
-rw-r--r--editor/import/resource_importer_wav.cpp2
-rw-r--r--editor/import/scene_import_settings.cpp36
-rw-r--r--editor/import/scene_import_settings.h3
-rw-r--r--editor/import_dock.cpp7
-rw-r--r--editor/inspector_dock.cpp90
-rw-r--r--editor/inspector_dock.h9
-rw-r--r--editor/localization_editor.cpp21
-rw-r--r--editor/localization_editor.h2
-rw-r--r--editor/multi_node_edit.cpp151
-rw-r--r--editor/multi_node_edit.h10
-rw-r--r--editor/node_dock.cpp2
-rw-r--r--editor/plugin_config_dialog.cpp18
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp13
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h3
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp201
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h5
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp220
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h5
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp90
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h8
-rw-r--r--editor/plugins/animation_library_editor.cpp172
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp85
-rw-r--r--editor/plugins/animation_player_editor_plugin.h5
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp193
-rw-r--r--editor/plugins/animation_state_machine_editor.h10
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp8
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp40
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.cpp5
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp931
-rw-r--r--editor/plugins/bone_map_editor_plugin.h85
-rw-r--r--editor/plugins/camera_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp409
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h7
-rw-r--r--editor/plugins/cast_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/cast_2d_editor_plugin.h5
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h3
-rw-r--r--editor/plugins/control_editor_plugin.cpp855
-rw-r--r--editor/plugins/control_editor_plugin.h172
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.h3
-rw-r--r--editor/plugins/cpu_particles_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp70
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp73
-rw-r--r--editor/plugins/debugger_editor_plugin.h4
-rw-r--r--editor/plugins/editor_preview_plugins.cpp24
-rw-r--r--editor/plugins/editor_preview_plugins.h2
-rw-r--r--editor/plugins/font_config_plugin.cpp22
-rw-r--r--editor/plugins/font_config_plugin.h6
-rw-r--r--editor/plugins/gdextension_export_plugin.h1
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.h3
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp19
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp2
-rw-r--r--editor/plugins/gradient_editor.cpp492
-rw-r--r--editor/plugins/gradient_editor.h96
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp59
-rw-r--r--editor/plugins/gradient_editor_plugin.h21
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp15
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.h6
-rw-r--r--editor/plugins/material_editor_plugin.cpp152
-rw-r--r--editor/plugins/material_editor_plugin.h26
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp40
-rw-r--r--editor/plugins/mesh_editor_plugin.h12
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp17
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp2
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.cpp191
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.h83
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp332
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h29
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp288
-rw-r--r--editor/plugins/node_3d_editor_plugin.h12
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp2
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/path_2d_editor_plugin.h3
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp21
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp120
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp1
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.h3
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp10
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.h5
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp167
-rw-r--r--editor/plugins/script_editor_plugin.h12
-rw-r--r--editor/plugins/script_text_editor.cpp78
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/shader_editor_plugin.cpp256
-rw-r--r--editor/plugins/shader_editor_plugin.h29
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp7
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp138
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h10
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp21
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp51
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h5
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp4
-rw-r--r--editor/plugins/sub_viewport_preview_editor_plugin.cpp2
-rw-r--r--editor/plugins/text_editor.cpp12
-rw-r--r--editor/plugins/text_editor.h2
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp18
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp47
-rw-r--r--editor/plugins/texture_region_editor_plugin.h3
-rw-r--r--editor/plugins/theme_editor_plugin.cpp170
-rw-r--r--editor/plugins/theme_editor_preview.cpp13
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp1
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.h3
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp68
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h6
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp109
-rw-r--r--editor/plugins/tiles/tile_data_editors.h14
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp161
-rw-r--r--editor/plugins/tiles/tile_map_editor.h8
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp1
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.h2
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp204
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h2
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp11
-rw-r--r--editor/plugins/tiles/tile_set_editor.h4
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.h2
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp6
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp1630
-rw-r--r--editor/plugins/version_control_editor_plugin.h190
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp1489
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h47
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp2
-rw-r--r--editor/progress_dialog.cpp4
-rw-r--r--editor/project_converter_3_to_4.cpp2468
-rw-r--r--editor/project_converter_3_to_4.h52
-rw-r--r--editor/project_manager.cpp117
-rw-r--r--editor/project_settings_editor.cpp9
-rw-r--r--editor/project_settings_editor.h4
-rw-r--r--editor/rename_dialog.cpp35
-rw-r--r--editor/rename_dialog.h7
-rw-r--r--editor/scene_create_dialog.cpp4
-rw-r--r--editor/scene_tree_dock.cpp540
-rw-r--r--editor/scene_tree_dock.h4
-rw-r--r--editor/scene_tree_editor.cpp49
-rw-r--r--editor/scene_tree_editor.h7
-rw-r--r--editor/script_create_dialog.cpp21
-rw-r--r--editor/shader_create_dialog.cpp11
-rw-r--r--editor/shader_create_dialog.h7
-rw-r--r--editor/shader_globals_editor.cpp41
-rw-r--r--editor/shader_globals_editor.h1
-rwxr-xr-xeditor/translations/extract.py2
294 files changed, 15479 insertions, 7881 deletions
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 462f314471..b6348c5952 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -66,6 +66,14 @@ String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_ev
String text = p_event->as_text();
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid() && key->is_command_or_control_autoremap()) {
+#ifdef MACOS_ENABLED
+ text = text.replace("Command", "Command/Ctrl");
+#else
+ text = text.replace("Ctrl", "Command/Ctrl");
+#endif
+ }
Ref<InputEventMouse> mouse = p_event;
Ref<InputEventJoypadMotion> jp_motion = p_event;
Ref<InputEventJoypadButton> jp_button = p_event;
@@ -108,11 +116,10 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b
show_mods = true;
mod_checkboxes[MOD_ALT]->set_pressed(mod->is_alt_pressed());
mod_checkboxes[MOD_SHIFT]->set_pressed(mod->is_shift_pressed());
- mod_checkboxes[MOD_COMMAND]->set_pressed(mod->is_command_pressed());
mod_checkboxes[MOD_CTRL]->set_pressed(mod->is_ctrl_pressed());
mod_checkboxes[MOD_META]->set_pressed(mod->is_meta_pressed());
- store_command_checkbox->set_pressed(mod->is_storing_command());
+ autoremap_command_or_control_checkbox->set_pressed(mod->is_command_or_control_autoremap());
}
if (k.is_valid()) {
@@ -287,8 +294,6 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> &
Ref<InputEventWithModifiers> mod = received_event;
if (mod.is_valid()) {
- // Maintain store command option state
- mod->set_store_command(store_command_checkbox->is_pressed());
mod->set_window_id(0);
}
@@ -419,41 +424,31 @@ void InputEventConfigurationDialog::_mod_toggled(bool p_checked, int p_index) {
} else if (p_index == 1) {
ie->set_shift_pressed(p_checked);
} else if (p_index == 2) {
- ie->set_command_pressed(p_checked);
+ if (!autoremap_command_or_control_checkbox->is_pressed()) {
+ ie->set_ctrl_pressed(p_checked);
+ }
} else if (p_index == 3) {
- ie->set_ctrl_pressed(p_checked);
- } else if (p_index == 4) {
- ie->set_meta_pressed(p_checked);
+ if (!autoremap_command_or_control_checkbox->is_pressed()) {
+ ie->set_meta_pressed(p_checked);
+ }
}
_set_event(ie);
}
-void InputEventConfigurationDialog::_store_command_toggled(bool p_checked) {
+void InputEventConfigurationDialog::_autoremap_command_or_control_toggled(bool p_checked) {
Ref<InputEventWithModifiers> ie = event;
if (ie.is_valid()) {
- ie->set_store_command(p_checked);
+ ie->set_command_or_control_autoremap(p_checked);
_set_event(ie);
}
if (p_checked) {
- // If storing Command, show it's checkbox and hide Control (Win/Lin) or Meta (Mac)
-#ifdef APPLE_STYLE_KEYS
mod_checkboxes[MOD_META]->hide();
-
- mod_checkboxes[MOD_COMMAND]->show();
- mod_checkboxes[MOD_COMMAND]->set_text("Meta (Command)");
-#else
mod_checkboxes[MOD_CTRL]->hide();
-
- mod_checkboxes[MOD_COMMAND]->show();
- mod_checkboxes[MOD_COMMAND]->set_text("Control (Command)");
-#endif
} else {
- // If not, hide Command, show Control and Meta.
- mod_checkboxes[MOD_COMMAND]->hide();
- mod_checkboxes[MOD_CTRL]->show();
mod_checkboxes[MOD_META]->show();
+ mod_checkboxes[MOD_CTRL]->show();
}
}
@@ -502,10 +497,12 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
// Maintain modifier state from checkboxes
k->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
k->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
- k->set_command_pressed(mod_checkboxes[MOD_COMMAND]->is_pressed());
- k->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
- k->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
- k->set_store_command(store_command_checkbox->is_pressed());
+ if (autoremap_command_or_control_checkbox->is_pressed()) {
+ k->set_command_or_control_autoremap(true);
+ } else {
+ k->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
+ k->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
+ }
_set_event(k, false);
} break;
@@ -517,10 +514,12 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
// Maintain modifier state from checkboxes
mb->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
mb->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
- mb->set_command_pressed(mod_checkboxes[MOD_COMMAND]->is_pressed());
- mb->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
- mb->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
- mb->set_store_command(store_command_checkbox->is_pressed());
+ if (autoremap_command_or_control_checkbox->is_pressed()) {
+ mb->set_command_or_control_autoremap(true);
+ } else {
+ mb->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
+ mb->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
+ }
// Maintain selected device
mb->set_device(_get_current_device());
@@ -611,7 +610,7 @@ void InputEventConfigurationDialog::popup_and_configure(const Ref<InputEvent> &p
// This is especially important for WASD movement layouts.
physical_key_checkbox->set_pressed(true);
- store_command_checkbox->set_pressed(true);
+ autoremap_command_or_control_checkbox->set_pressed(false);
_set_current_device(0);
// Switch to "Listen" tab
@@ -722,21 +721,18 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
mod_checkboxes[i] = memnew(CheckBox);
mod_checkboxes[i]->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_mod_toggled).bind(i));
mod_checkboxes[i]->set_text(name);
+ mod_checkboxes[i]->set_tooltip_text(TTR(mods_tip[i]));
mod_container->add_child(mod_checkboxes[i]);
}
mod_container->add_child(memnew(VSeparator));
- store_command_checkbox = memnew(CheckBox);
- store_command_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_store_command_toggled));
- store_command_checkbox->set_pressed(true);
- store_command_checkbox->set_text(TTR("Store Command"));
-#ifdef APPLE_STYLE_KEYS
- store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'meta'. Used for compatibility with Windows/Linux style keyboard."));
-#else
- store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'control'. Used for compatibility with Apple Style keyboards."));
-#endif
- mod_container->add_child(store_command_checkbox);
+ autoremap_command_or_control_checkbox = memnew(CheckBox);
+ autoremap_command_or_control_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_autoremap_command_or_control_toggled));
+ autoremap_command_or_control_checkbox->set_pressed(false);
+ autoremap_command_or_control_checkbox->set_text(TTR("Command / Control (auto)"));
+ autoremap_command_or_control_checkbox->set_tooltip_text(TTR("Automatically remaps between 'Meta' ('Command') and 'Control' depending on current platform."));
+ mod_container->add_child(autoremap_command_or_control_checkbox);
mod_container->hide();
additional_options_container->add_child(mod_container);
@@ -745,7 +741,7 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
physical_key_checkbox = memnew(CheckBox);
physical_key_checkbox->set_text(TTR("Use Physical Keycode"));
- physical_key_checkbox->set_tooltip(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications."));
+ physical_key_checkbox->set_tooltip_text(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications."));
physical_key_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_physical_keycode_toggled));
physical_key_checkbox->hide();
additional_options_container->add_child(physical_key_checkbox);
@@ -805,7 +801,7 @@ String ActionMapEditor::_check_new_action_name(const String &p_name) {
void ActionMapEditor::_add_edit_text_changed(const String &p_name) {
String error = _check_new_action_name(p_name);
- add_button->set_tooltip(error);
+ add_button->set_tooltip_text(error);
add_button->set_disabled(!error.is_empty());
}
@@ -1061,6 +1057,9 @@ void ActionMapEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
action_list_search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ if (!actions_cache.is_empty()) {
+ update_action_list();
+ }
} break;
}
}
diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h
index 1ca3c5bac0..36d21fe258 100644
--- a/editor/action_map_editor.h
+++ b/editor/action_map_editor.h
@@ -85,15 +85,21 @@ private:
enum ModCheckbox {
MOD_ALT,
MOD_SHIFT,
- MOD_COMMAND,
MOD_CTRL,
MOD_META,
MOD_MAX
};
- String mods[MOD_MAX] = { "Alt", "Shift", "Command", "Ctrl", "Metakey" };
+#if defined(MACOS_ENABLED)
+ String mods[MOD_MAX] = { "Option", "Shift", "Ctrl", "Command" };
+#elif defined(WINDOWS_ENABLED)
+ String mods[MOD_MAX] = { "Alt", "Shift", "Ctrl", "Windows" };
+#else
+ String mods[MOD_MAX] = { "Alt", "Shift", "Ctrl", "Meta" };
+#endif
+ String mods_tip[MOD_MAX] = { "Alt or Option key", "Shift key", "Control key", "Meta/Windows or Command key" };
CheckBox *mod_checkboxes[MOD_MAX];
- CheckBox *store_command_checkbox = nullptr;
+ CheckBox *autoremap_command_or_control_checkbox = nullptr;
CheckBox *physical_key_checkbox = nullptr;
@@ -107,7 +113,7 @@ private:
void _input_list_item_selected();
void _mod_toggled(bool p_checked, int p_index);
- void _store_command_toggled(bool p_checked);
+ void _autoremap_command_or_control_toggled(bool p_checked);
void _physical_keycode_toggled(bool p_checked);
void _device_selection_changed(int p_option_button_index);
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index ab9afda803..219f3fdbe1 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/view_panner.h"
#include "scene/resources/text_line.h"
@@ -40,7 +41,7 @@
float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) {
float h = p_h;
h = (h - v_scroll) / v_zoom;
- h = (get_size().height / 2) - h;
+ h = (get_size().height / 2.0) - h;
return h;
}
@@ -51,10 +52,10 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
int right_limit = get_size().width;
//selection may have altered the order of keys
- RBMap<float, int> key_order;
+ RBMap<real_t, int> key_order;
for (int i = 0; i < animation->track_get_key_count(p_track); i++) {
- float ofs = animation->track_get_key_time(p_track, i);
+ real_t ofs = animation->track_get_key_time(p_track, i);
if (moving_selection && selection.has(IntPair(p_track, i))) {
ofs += moving_selection_offset.x;
}
@@ -62,7 +63,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
key_order[ofs] = i;
}
- for (RBMap<float, int>::Element *E = key_order.front(); E; E = E->next()) {
+ for (RBMap<real_t, int>::Element *E = key_order.front(); E; E = E->next()) {
int i = E->get();
if (!E->next()) {
@@ -74,7 +75,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
float offset = animation->track_get_key_time(p_track, i);
float height = animation->bezier_track_get_key_value(p_track, i);
Vector2 out_handle = animation->bezier_track_get_key_out_handle(p_track, i);
- if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i) {
+ if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i) {
out_handle = moving_handle_right;
}
@@ -88,7 +89,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
float offset_n = animation->track_get_key_time(p_track, i_n);
float height_n = animation->bezier_track_get_key_value(p_track, i_n);
Vector2 in_handle = animation->bezier_track_get_key_in_handle(p_track, i_n);
- if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i_n) {
+ if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i_n) {
in_handle = moving_handle_left;
}
@@ -138,7 +139,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
//narrow high and low as much as possible
for (int k = 0; k < iterations; k++) {
- float middle = (low + high) / 2;
+ float middle = (low + high) / 2.0;
Vector2 interp = start.bezier_interpolate(out_handle, in_handle, end, middle);
@@ -315,7 +316,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
int h = MAX(text_buf.get_size().y, icon->get_height());
- draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2));
+ draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2.0));
ofs += icon->get_width();
margin = icon->get_width();
@@ -328,6 +329,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
}
+ Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
+
Ref<Texture2D> remove = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
float remove_hpos = limit - hsep - remove->get_width();
@@ -400,25 +403,29 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
Vector2 string_pos = Point2(margin, vofs);
text_buf.draw(get_canvas_item(), string_pos, cc);
- float icon_start_height = vofs + rect.size.y / 2;
- Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2, remove->get_width(), remove->get_height());
- draw_texture(remove, remove_rect.position);
+ float icon_start_height = vofs + rect.size.y / 2.0;
+ Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2.0, remove->get_width(), remove->get_height());
+ if (read_only) {
+ draw_texture(remove, remove_rect.position, dc);
+ } else {
+ draw_texture(remove, remove_rect.position);
+ }
- Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2, lock->get_width(), lock->get_height());
+ Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2.0, lock->get_width(), lock->get_height());
if (locked_tracks.has(current_track)) {
draw_texture(lock, lock_rect.position);
} else {
draw_texture(unlock, lock_rect.position);
}
- Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2, visible->get_width(), visible->get_height());
+ Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2.0, visible->get_width(), visible->get_height());
if (hidden_tracks.has(current_track)) {
draw_texture(hidden, visible_rect.position);
} else {
draw_texture(visible, visible_rect.position);
}
- Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2, solo->get_width(), solo->get_height());
+ Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2.0, solo->get_width(), solo->get_height());
draw_texture(solo, solo_rect.position);
RBMap<int, Rect2> track_icons;
@@ -449,7 +456,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
bool first = true;
int prev_iv = 0;
for (int i = font->get_height(font_size); i < get_size().height; i++) {
- float ofs = get_size().height / 2 - i;
+ float ofs = get_size().height / 2.0 - i;
ofs *= v_zoom;
ofs += v_scroll;
@@ -488,7 +495,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
if (pos.x >= limit && pos.x <= right_limit) {
- draw_texture(point, pos - point->get_size() / 2, E.value);
+ draw_texture(point, pos - point->get_size() / 2.0, E.value);
}
}
}
@@ -540,14 +547,15 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
- if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) {
+
+ if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
in_vec = moving_handle_left;
}
Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);
- if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) {
+ if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
out_vec = moving_handle_right;
}
@@ -562,7 +570,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
ep.track = i;
ep.key = j;
if (pos.x >= limit && pos.x <= right_limit) {
- ep.point_rect.position = (pos - bezier_icon->get_size() / 2).floor();
+ ep.point_rect.position = (pos - bezier_icon->get_size() / 2.0).floor();
ep.point_rect.size = bezier_icon->get_size();
if (selection.has(IntPair(i, j))) {
draw_texture(selected_icon, ep.point_rect.position);
@@ -577,18 +585,22 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
}
+ ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
+
if (i == selected_track || selection.has(IntPair(i, j))) {
- if (pos_in.x >= limit && pos_in.x <= right_limit) {
- ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2).floor();
- ep.in_rect.size = bezier_handle_icon->get_size();
- draw_texture(bezier_handle_icon, ep.in_rect.position);
- ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5);
- }
- if (pos_out.x >= limit && pos_out.x <= right_limit) {
- ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2).floor();
- ep.out_rect.size = bezier_handle_icon->get_size();
- draw_texture(bezier_handle_icon, ep.out_rect.position);
- ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5);
+ if (animation->bezier_track_get_key_handle_mode(i, j) != Animation::HANDLE_MODE_LINEAR) {
+ if (pos_in.x >= limit && pos_in.x <= right_limit) {
+ ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2.0).floor();
+ ep.in_rect.size = bezier_handle_icon->get_size();
+ draw_texture(bezier_handle_icon, ep.in_rect.position);
+ ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5);
+ }
+ if (pos_out.x >= limit && pos_out.x <= right_limit) {
+ ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2.0).floor();
+ ep.out_rect.size = bezier_handle_icon->get_size();
+ draw_texture(bezier_handle_icon, ep.out_rect.position);
+ ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5);
+ }
}
}
if (!locked_tracks.has(i)) {
@@ -632,17 +644,18 @@ Ref<Animation> AnimationBezierTrackEdit::get_animation() const {
return animation;
}
-void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) {
+void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only) {
animation = p_animation;
+ read_only = p_read_only;
selected_track = p_track;
- update();
+ queue_redraw();
}
Size2 AnimationBezierTrackEdit::get_minimum_size() const {
return Vector2(1, 1);
}
-void AnimationBezierTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
+void AnimationBezierTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -656,7 +669,6 @@ void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) {
editor = p_editor;
connect("clear_selection", Callable(editor, "_clear_selection").bind(false));
connect("select_key", Callable(editor, "_key_selected"), CONNECT_DEFERRED);
- connect("deselect_key", Callable(editor, "_key_deselected"), CONNECT_DEFERRED);
}
void AnimationBezierTrackEdit::_play_position_draw() {
@@ -677,13 +689,13 @@ void AnimationBezierTrackEdit::_play_position_draw() {
}
}
-void AnimationBezierTrackEdit::set_play_position(float p_pos) {
+void AnimationBezierTrackEdit::set_play_position(real_t p_pos) {
play_position_pos = p_pos;
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationBezierTrackEdit::update_play_position() {
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationBezierTrackEdit::set_root(Node *p_root) {
@@ -715,19 +727,19 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
continue; // Skip track due to not selected.
}
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
}
}
}
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::_zoom_changed() {
- update();
- play_position->update();
+ queue_redraw();
+ play_position->queue_redraw();
}
void AnimationBezierTrackEdit::_update_locked_tracks_after(int p_track) {
@@ -775,16 +787,17 @@ String AnimationBezierTrackEdit::get_tooltip(const Point2 &p_pos) const {
void AnimationBezierTrackEdit::_clear_selection() {
selection.clear();
emit_signal(SNAME("clear_selection"));
- update();
+ queue_redraw();
}
-void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode) {
+void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) {
undo_redo->create_action(TTR("Update Selected Key Handles"));
- double ratio = timeline->get_zoom_scale() * v_zoom;
- for (const IntPair &E : selection) {
- const IntPair track_key_pair = E;
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), ratio);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, p_mode, ratio);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ const IntPair track_key_pair = E->get();
+ undo_redo->add_undo_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), Animation::HANDLE_SET_MODE_NONE);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_in_handle(track_key_pair.first, track_key_pair.second));
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_out_handle(track_key_pair.first, track_key_pair.second));
+ undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, p_mode, p_auto ? Animation::HANDLE_SET_MODE_AUTO : Animation::HANDLE_SET_MODE_RESET);
}
undo_redo->commit_action();
}
@@ -796,7 +809,7 @@ void AnimationBezierTrackEdit::_clear_selection_for_anim(const Ref<Animation> &p
_clear_selection();
}
-void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos) {
+void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos) {
if (!(animation == p_anim)) {
return;
}
@@ -805,8 +818,8 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
ERR_FAIL_COND(idx < 0);
selection.insert(IntPair(p_track, idx));
- emit_signal(SNAME("select_key"), p_track, idx, true);
- update();
+ emit_signal(SNAME("select_key"), idx, true, p_track);
+ queue_redraw();
}
void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
@@ -819,12 +832,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) {
- duplicate_selection();
+ if (!read_only) {
+ duplicate_selection();
+ }
accept_event();
}
if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) {
- delete_selection();
+ if (!read_only) {
+ delete_selection();
+ }
accept_event();
}
}
@@ -857,16 +874,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- float minimum_time = INFINITY;
- float maximum_time = -INFINITY;
- float minimum_value = INFINITY;
- float maximum_value = -INFINITY;
+ real_t minimum_time = INFINITY;
+ real_t maximum_time = -INFINITY;
+ real_t minimum_value = INFINITY;
+ real_t maximum_value = -INFINITY;
for (const IntPair &E : selection) {
IntPair key_pair = E;
- float time = animation->track_get_key_time(key_pair.first, key_pair.second);
- float value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second);
+ real_t time = animation->track_get_key_time(key_pair.first, key_pair.second);
+ real_t value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second);
minimum_time = MIN(time, minimum_time);
maximum_time = MAX(time, maximum_time);
@@ -876,8 +893,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
float width = get_size().width - timeline->get_name_limit() - timeline->get_buttons_width();
float padding = width * 0.1;
- float desired_scale = (width - padding / 2) / (maximum_time - minimum_time);
- minimum_time = MAX(0, minimum_time - (padding / 2) / desired_scale);
+ float desired_scale = (width - padding / 2.0) / (maximum_time - minimum_time);
+ minimum_time = MAX(0, minimum_time - (padding / 2.0) / desired_scale);
float zv = Math::pow(100 / desired_scale, 0.125f);
if (zv < 1) {
@@ -892,7 +909,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
v_scroll = (maximum_value + minimum_value) / 2.0;
v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9);
- update();
+ queue_redraw();
accept_event();
return;
} else if (ED_GET_SHORTCUT("animation_bezier_editor/select_all_keys")->matches_event(p_event)) {
@@ -900,13 +917,13 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
}
- update();
+ queue_redraw();
accept_event();
return;
} else if (ED_GET_SHORTCUT("animation_bezier_editor/deselect_all_keys")->matches_event(p_event)) {
selection.clear();
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -917,26 +934,33 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
menu_insert_key = mb->get_position();
if (menu_insert_key.x >= limit && menu_insert_key.x <= get_size().width) {
- Vector2 popup_pos = get_screen_position() + mb->get_position();
+ if (!read_only) {
+ Vector2 popup_pos = get_screen_position() + mb->get_position();
- menu->clear();
- if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) {
- menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
- }
- if (selection.size()) {
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE);
- menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
- }
+ menu->clear();
+ if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) {
+ menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
+ }
+ if (selection.size()) {
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesLinear"), SNAME("EditorIcons")), TTR("Make Handles Linear"), MENU_KEY_SET_HANDLE_LINEAR);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored"), MENU_KEY_SET_HANDLE_MIRRORED);
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_BALANCED);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_MIRRORED);
+ }
- if (menu->get_item_count()) {
- menu->reset_size();
- menu->set_position(popup_pos);
- menu->popup();
+ if (menu->get_item_count()) {
+ menu->reset_size();
+ menu->set_position(popup_pos);
+ menu->popup();
+ }
}
}
}
@@ -945,7 +969,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (const KeyValue<int, Rect2> &E : subtracks) {
if (E.value.has_point(mb->get_position())) {
if (!locked_tracks.has(E.key) && !hidden_tracks.has(E.key)) {
- set_animation_and_track(animation, E.key);
+ set_animation_and_track(animation, E.key, read_only);
_clear_selection();
}
return;
@@ -958,30 +982,33 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (const KeyValue<int, Rect2> &I : track_icons) {
if (I.value.has_point(mb->get_position())) {
if (I.key == REMOVE_ICON) {
- undo_redo->create_action("Remove Bezier Track");
-
- undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
- undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
-
- undo_redo->add_do_method(animation.ptr(), "remove_track", track);
+ if (!read_only) {
+ undo_redo->create_action("Remove Bezier Track");
+
+ undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
+ undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
+
+ undo_redo->add_do_method(animation.ptr(), "remove_track", track);
+
+ undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
+
+ for (int i = 0; i < animation->track_get_key_count(track); ++i) {
+ undo_redo->add_undo_method(
+ this,
+ "_bezier_track_insert_key",
+ track,
+ animation->track_get_key_time(track, i),
+ animation->bezier_track_get_key_value(track, i),
+ animation->bezier_track_get_key_in_handle(track, i),
+ animation->bezier_track_get_key_out_handle(track, i),
+ animation->bezier_track_get_key_handle_mode(track, i));
+ }
- undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track);
- undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
+ undo_redo->commit_action();
- for (int i = 0; i < animation->track_get_key_count(track); ++i) {
- undo_redo->add_undo_method(
- animation.ptr(),
- "bezier_track_insert_key",
- track, animation->track_get_key_time(track, i),
- animation->bezier_track_get_key_value(track, i),
- animation->bezier_track_get_key_in_handle(track, i),
- animation->bezier_track_get_key_out_handle(track, i),
- animation->bezier_track_get_key_handle_mode(track, i));
+ selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1);
}
-
- undo_redo->commit_action();
-
- selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1);
return;
} else if (I.key == LOCK_ICON) {
if (locked_tracks.has(track)) {
@@ -991,13 +1018,13 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (selected_track == track) {
for (int i = 0; i < animation->get_track_count(); ++i) {
if (!locked_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
}
}
- update();
+ queue_redraw();
return;
} else if (I.key == VISIBILITY_ICON) {
if (hidden_tracks.has(track)) {
@@ -1007,7 +1034,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (selected_track == track) {
for (int i = 0; i < animation->get_track_count(); ++i) {
if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
@@ -1027,7 +1054,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
solo_track = -1;
}
- update();
+ queue_redraw();
return;
} else if (I.key == SOLO_ICON) {
if (solo_track == track) {
@@ -1046,10 +1073,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
- set_animation_and_track(animation, track);
+ set_animation_and_track(animation, track, read_only);
solo_track = track;
}
- update();
+ queue_redraw();
return;
}
return;
@@ -1061,7 +1088,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
//first check point
//command makes it ignore the main point, so control point editors can be force-edited
//path 2D editing in the 3D and 2D editors works the same way
- if (!mb->is_command_pressed()) {
+ if (!mb->is_command_or_control_pressed()) {
if (edit_points[i].point_rect.has_point(mb->get_position())) {
IntPair pair = IntPair(edit_points[i].track, edit_points[i].key);
if (mb->is_shift_pressed()) {
@@ -1071,73 +1098,79 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
} else {
selection.insert(pair);
}
- update();
+ queue_redraw();
select_single_attempt = IntPair(-1, -1);
} else if (selection.has(pair)) {
moving_selection_attempt = true;
moving_selection = false;
moving_selection_from_key = pair.second;
moving_selection_from_track = pair.first;
+ moving_handle_track = pair.first;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second);
moving_selection_offset = Vector2();
select_single_attempt = pair;
- update();
+ queue_redraw();
} else {
moving_selection_attempt = true;
moving_selection = true;
moving_selection_from_key = pair.second;
moving_selection_from_track = pair.first;
moving_selection_offset = Vector2();
- set_animation_and_track(animation, pair.first);
+ moving_handle_track = pair.first;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second);
selection.clear();
selection.insert(pair);
- update();
+ set_animation_and_track(animation, pair.first, read_only);
}
return;
}
}
- if (edit_points[i].in_rect.has_point(mb->get_position())) {
- moving_handle = -1;
- moving_handle_key = edit_points[i].key;
- moving_handle_track = edit_points[i].track;
- moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
- moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
- update();
- return;
- }
+ if (!read_only) {
+ if (edit_points[i].in_rect.has_point(mb->get_position())) {
+ moving_handle = -1;
+ moving_handle_key = edit_points[i].key;
+ moving_handle_track = edit_points[i].track;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
+ queue_redraw();
+ return;
+ }
- if (edit_points[i].out_rect.has_point(mb->get_position())) {
- moving_handle = 1;
- moving_handle_key = edit_points[i].key;
- moving_handle_track = edit_points[i].track;
- moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
- moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
- update();
- return;
+ if (edit_points[i].out_rect.has_point(mb->get_position())) {
+ moving_handle = 1;
+ moving_handle_key = edit_points[i].key;
+ moving_handle_track = edit_points[i].track;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
+ queue_redraw();
+ return;
+ }
}
}
//insert new point
- if (mb->get_position().x >= limit && mb->get_position().x < get_size().width && mb->is_command_pressed()) {
+ if (mb->get_position().x >= limit && mb->get_position().x < get_size().width && mb->is_command_or_control_pressed()) {
Array new_point;
- new_point.resize(6);
+ new_point.resize(5);
- float h = (get_size().height / 2 - mb->get_position().y) * v_zoom + v_scroll;
+ float h = (get_size().height / 2.0 - mb->get_position().y) * v_zoom + v_scroll;
new_point[0] = h;
new_point[1] = -0.25;
new_point[2] = 0;
new_point[3] = 0.25;
new_point[4] = 0;
- new_point[5] = 0;
- float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+ real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(selected_track, time, true) != -1) {
time += 0.001;
}
undo_redo->create_action(TTR("Add Bezier Point"));
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
undo_redo->commit_action();
@@ -1153,7 +1186,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection_from_track = selected_track;
moving_selection_offset = Vector2();
select_single_attempt = IntPair(-1, -1);
- update();
+ queue_redraw();
return;
}
@@ -1191,7 +1224,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
if (!track_set) {
track_set = true;
- set_animation_and_track(animation, edit_points[i].track);
+ set_animation_and_track(animation, edit_points[i].track, read_only);
}
}
}
@@ -1201,10 +1234,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
//select by clicking on curve
int track_count = animation->get_track_count();
- float animation_length = animation->get_length();
+ real_t animation_length = animation->get_length();
animation->set_length(real_t(INT_MAX)); //bezier_track_interpolate doesn't find keys if they exist beyond anim length
- float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+ real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
for (int i = 0; i < track_count; ++i) {
if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i) || locked_tracks.has(i)) {
@@ -1215,7 +1248,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
float track_height = _bezier_h_to_pixel(track_h);
if (abs(mb->get_position().y - track_height) < 10) {
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
@@ -1225,106 +1258,126 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
box_selecting_attempt = false;
box_selecting = false;
- update();
+ queue_redraw();
}
- if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- undo_redo->create_action(TTR("Move Bezier Points"));
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, moving_handle_right);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_in_handle(selected_track, moving_handle_key));
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_out_handle(selected_track, moving_handle_key));
- undo_redo->commit_action();
+ if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
+ if (!read_only) {
+ if (moving_selection) {
+ //combit it
- moving_handle = 0;
- update();
- }
+ undo_redo->create_action(TTR("Move Bezier Points"));
- if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- if (moving_selection) {
- //combit it
+ List<AnimMoveRestore> to_restore;
+ List<Animation::HandleMode> to_restore_handle_modes;
+ // 1-remove the keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
+ }
+ // 2- remove overlapped keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- undo_redo->create_action(TTR("Move Bezier Points"));
+ int idx = animation->track_find_key(E->get().first, newtime, true);
+ if (idx == -1) {
+ continue;
+ }
- List<AnimMoveRestore> to_restore;
- // 1-remove the keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
- }
- // 2- remove overlapped keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
+ if (selection.has(IntPair(E->get().first, idx))) {
+ continue; //already in selection, don't save
+ }
- int idx = animation->track_find_key(E->get().first, newtime, true);
- if (idx == -1) {
- continue;
- }
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime);
+ AnimMoveRestore amr;
- if (selection.has(IntPair(E->get().first, idx))) {
- continue; //already in selection, don't save
- }
+ amr.key = animation->track_get_key_value(E->get().first, idx);
+ amr.track = E->get().first;
+ amr.time = newtime;
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime);
- AnimMoveRestore amr;
+ to_restore.push_back(amr);
+ to_restore_handle_modes.push_back(animation->bezier_track_get_key_handle_mode(E->get().first, idx));
+ }
- amr.key = animation->track_get_key_value(E->get().first, idx);
- amr.track = E->get().first;
- amr.time = newtime;
+ // 3-move the keys (re insert them)
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
+ Array key = animation->track_get_key_value(E->get().first, E->get().second);
+ real_t h = key[0];
+ h += moving_selection_offset.y;
+ key[0] = h;
+ undo_redo->add_do_method(
+ this,
+ "_bezier_track_insert_key",
+ E->get().first,
+ newpos,
+ key[0],
+ Vector2(key[1], key[2]),
+ Vector2(key[3], key[4]),
+ animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
+ }
- to_restore.push_back(amr);
- }
+ // 4-(undo) remove inserted keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
+ }
- // 3-move the keys (re insert them)
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- Array key = animation->track_get_key_value(E->get().first, E->get().second);
- float h = key[0];
- h += moving_selection_offset.y;
- key[0] = h;
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, newpos, key, 1);
- }
+ // 5-(undo) reinsert keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
+ Array key = animation->track_get_key_value(E->get().first, E->get().second);
+ undo_redo->add_undo_method(
+ this,
+ "_bezier_track_insert_key",
+ E->get().first,
+ oldpos,
+ key[0],
+ Vector2(key[1], key[2]),
+ Vector2(key[3], key[4]),
+ animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
+ }
- // 4-(undo) remove inserted keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
- }
+ // 6-(undo) reinsert overlapped keys
+ for (int i = 0; i < to_restore.size(); i++) {
+ const AnimMoveRestore &amr = to_restore[i];
+ Array key = amr.key;
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1);
+ undo_redo->add_undo_method(
+ this,
+ "_bezier_track_insert_key",
+ amr.track,
+ amr.time,
+ key[0],
+ Vector2(key[1], key[2]),
+ Vector2(key[3], key[4]),
+ to_restore_handle_modes[i]);
+ }
- // 5-(undo) reinsert keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float oldpos = animation->track_get_key_time(E->get().first, E->get().second);
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, oldpos, animation->track_get_key_value(E->get().first, E->get().second), 1);
- }
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
- // 6-(undo) reinsert overlapped keys
- for (const AnimMoveRestore &amr : to_restore) {
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1);
- }
+ // 7-reselect
- undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
- undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
+ real_t newpos = editor->snap_time(oldpos + moving_selection_offset.x);
- // 7-reselect
+ undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos);
+ undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos);
+ }
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float oldpos = animation->track_get_key_time(E->get().first, E->get().second);
- float newpos = editor->snap_time(oldpos + moving_selection_offset.x);
+ undo_redo->commit_action();
- undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos);
- undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos);
+ moving_selection = false;
+ } else if (select_single_attempt != IntPair(-1, -1)) {
+ selection.clear();
+ selection.insert(select_single_attempt);
+ set_animation_and_track(animation, select_single_attempt.first, read_only);
}
- undo_redo->commit_action();
-
- moving_selection = false;
- } else if (select_single_attempt != IntPair(-1, -1)) {
- selection.clear();
- selection.insert(select_single_attempt);
- set_animation_and_track(animation, select_single_attempt.first);
+ moving_selection_attempt = false;
+ queue_redraw();
}
-
- moving_selection_attempt = false;
- update();
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -1334,11 +1387,17 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
select_single_attempt = IntPair(-1, -1);
}
- float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
+ float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll;
float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value());
- moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key));
- update();
+ if (!read_only) {
+ moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key));
+ }
+
+ additional_moving_handle_lefts.clear();
+ additional_moving_handle_rights.clear();
+
+ queue_redraw();
}
if (box_selecting_attempt && mm.is_valid()) {
@@ -1353,11 +1412,11 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
//avoid cursor from going too above, so it does not lose focus with viewport
warp_mouse(Vector2(get_local_mouse_position().x, 0));
}
- update();
+ queue_redraw();
}
- if (moving_handle != 0 && mm.is_valid()) {
- float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
+ if ((moving_handle == 1 || moving_handle == -1) && mm.is_valid()) {
+ float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll;
float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
Vector2 key_pos = Vector2(animation->track_get_key_time(selected_track, moving_handle_key), animation->bezier_track_get_key_value(selected_track, moving_handle_key));
@@ -1370,8 +1429,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (moving_handle == -1) {
moving_handle_left = moving_handle_value;
- if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
+ Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key);
+
+ if (handle_mode == Animation::HANDLE_MODE_BALANCED) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / ratio));
@@ -1379,12 +1440,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
Vector2 vec_in = xform.xform(moving_handle_left);
moving_handle_right = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length());
+ } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) {
+ moving_handle_right = -moving_handle_left;
}
} else if (moving_handle == 1) {
moving_handle_right = moving_handle_value;
- if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
+ Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key);
+
+ if (handle_mode == Animation::HANDLE_MODE_BALANCED) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / ratio));
@@ -1392,27 +1457,29 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
Vector2 vec_out = xform.xform(moving_handle_right);
moving_handle_left = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
+ } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) {
+ moving_handle_left = -moving_handle_right;
}
}
- update();
+ queue_redraw();
}
- bool is_finishing_key_handle_drag = moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT;
- if (is_finishing_key_handle_drag) {
- undo_redo->create_action(TTR("Move Bezier Points"));
- if (moving_handle == -1) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio);
- } else if (moving_handle == 1) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
+ if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
+ if (!read_only) {
+ undo_redo->create_action(TTR("Move Bezier Points"));
+ if (moving_handle == -1) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio);
+ } else if (moving_handle == 1) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
+ }
+ undo_redo->commit_action();
+ moving_handle = 0;
+ queue_redraw();
}
- undo_redo->commit_action();
-
- moving_handle = 0;
- update();
}
}
@@ -1424,7 +1491,7 @@ void AnimationBezierTrackEdit::_pan_callback(Vector2 p_scroll_vec) {
v_scroll += p_scroll_vec.y * v_zoom;
v_scroll = CLAMP(v_scroll, -100000, 100000);
timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale());
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
@@ -1443,8 +1510,8 @@ void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_or
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
}
}
- v_scroll = v_scroll + (p_origin.y - get_size().y / 2) * (v_zoom - v_zoom_orig);
- update();
+ v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig);
+ queue_redraw();
}
void AnimationBezierTrackEdit::_menu_selected(int p_index) {
@@ -1452,20 +1519,19 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
case MENU_KEY_INSERT: {
if (animation->get_track_count() > 0) {
Array new_point;
- new_point.resize(6);
+ new_point.resize(5);
- float h = (get_size().height / 2 - menu_insert_key.y) * v_zoom + v_scroll;
+ float h = (get_size().height / 2.0 - menu_insert_key.y) * v_zoom + v_scroll;
new_point[0] = h;
new_point[1] = -0.25;
new_point[2] = 0;
new_point[3] = 0.25;
new_point[4] = 0;
- new_point[5] = Animation::HANDLE_MODE_BALANCED;
int limit = timeline->get_name_limit();
- float time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+ real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(selected_track, time, true) != -1) {
time += 0.001;
@@ -1475,8 +1541,8 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
undo_redo->commit_action();
+ queue_redraw();
}
-
} break;
case MENU_KEY_DUPLICATE: {
duplicate_selection();
@@ -1487,9 +1553,21 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
case MENU_KEY_SET_HANDLE_FREE: {
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE);
} break;
+ case MENU_KEY_SET_HANDLE_LINEAR: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_LINEAR);
+ } break;
case MENU_KEY_SET_HANDLE_BALANCED: {
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED);
} break;
+ case MENU_KEY_SET_HANDLE_MIRRORED: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED);
+ } break;
+ case MENU_KEY_SET_HANDLE_AUTO_BALANCED: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED, true);
+ } break;
+ case MENU_KEY_SET_HANDLE_AUTO_MIRRORED: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED, true);
+ } break;
}
}
@@ -1498,9 +1576,9 @@ void AnimationBezierTrackEdit::duplicate_selection() {
return;
}
- float top_time = 1e10;
+ real_t top_time = 1e10;
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float t = animation->track_get_key_time(E->get().first, E->get().second);
+ real_t t = animation->track_get_key_time(E->get().first, E->get().second);
if (t < top_time) {
top_time = t;
}
@@ -1508,17 +1586,17 @@ void AnimationBezierTrackEdit::duplicate_selection() {
undo_redo->create_action(TTR("Anim Duplicate Keys"));
- List<Pair<int, float>> new_selection_values;
+ List<Pair<int, real_t>> new_selection_values;
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float t = animation->track_get_key_time(E->get().first, E->get().second);
- float dst_time = t + (timeline->get_play_position() - top_time);
+ real_t t = animation->track_get_key_time(E->get().first, E->get().second);
+ real_t dst_time = t + (timeline->get_play_position() - top_time);
int existing_idx = animation->track_find_key(E->get().first, dst_time, true);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second));
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time);
- Pair<int, float> p;
+ Pair<int, real_t> p;
p.first = E->get().first;
p.second = dst_time;
new_selection_values.push_back(p);
@@ -1533,9 +1611,9 @@ void AnimationBezierTrackEdit::duplicate_selection() {
//reselect duplicated
selection.clear();
- for (const Pair<int, float> &E : new_selection_values) {
+ for (const Pair<int, real_t> &E : new_selection_values) {
int track = E.first;
- float time = E.second;
+ real_t time = E.second;
int existing_idx = animation->track_find_key(track, time, true);
@@ -1546,7 +1624,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
selection.insert(IntPair(track, existing_idx));
}
- update();
+ queue_redraw();
}
void AnimationBezierTrackEdit::delete_selection() {
@@ -1565,18 +1643,24 @@ void AnimationBezierTrackEdit::delete_selection() {
}
}
+void AnimationBezierTrackEdit::_bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode) {
+ ERR_FAIL_COND(animation.is_null());
+ int idx = animation->bezier_track_insert_key(p_track, p_time, p_value, p_in_handle, p_out_handle);
+ animation->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode);
+}
+
void AnimationBezierTrackEdit::_bind_methods() {
- ClassDB::bind_method("_clear_selection", &AnimationBezierTrackEdit::_clear_selection);
- ClassDB::bind_method("_clear_selection_for_anim", &AnimationBezierTrackEdit::_clear_selection_for_anim);
- ClassDB::bind_method("_select_at_anim", &AnimationBezierTrackEdit::_select_at_anim);
- ClassDB::bind_method("_update_hidden_tracks_after", &AnimationBezierTrackEdit::_update_hidden_tracks_after);
- ClassDB::bind_method("_update_locked_tracks_after", &AnimationBezierTrackEdit::_update_locked_tracks_after);
+ ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationBezierTrackEdit::_clear_selection);
+ ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationBezierTrackEdit::_clear_selection_for_anim);
+ ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationBezierTrackEdit::_select_at_anim);
+ ClassDB::bind_method(D_METHOD("_update_hidden_tracks_after"), &AnimationBezierTrackEdit::_update_hidden_tracks_after);
+ ClassDB::bind_method(D_METHOD("_update_locked_tracks_after"), &AnimationBezierTrackEdit::_update_locked_tracks_after);
+ ClassDB::bind_method(D_METHOD("_bezier_track_insert_key"), &AnimationBezierTrackEdit::_bezier_track_insert_key);
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag")));
ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset")));
- ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
- ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index")));
+ ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single"), PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("clear_selection"));
ADD_SIGNAL(MethodInfo("close_request"));
@@ -1600,8 +1684,8 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
set_clip_contents(true);
ED_SHORTCUT("animation_bezier_editor/focus", TTR("Focus"), Key::F);
- ED_SHORTCUT("animation_bezier_editor/select_all_keys", TTR("Select All Keys"), KeyModifierMask::CMD | Key::A);
- ED_SHORTCUT("animation_bezier_editor/deselect_all_keys", TTR("Deselect All Keys"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::A);
+ ED_SHORTCUT("animation_bezier_editor/select_all_keys", TTR("Select All Keys"), KeyModifierMask::CMD_OR_CTRL | Key::A);
+ ED_SHORTCUT("animation_bezier_editor/deselect_all_keys", TTR("Deselect All Keys"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::A);
menu = memnew(PopupMenu);
add_child(menu);
diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h
index 22b58a6703..beb7a5e9c6 100644
--- a/editor/animation_bezier_editor.h
+++ b/editor/animation_bezier_editor.h
@@ -32,8 +32,9 @@
#define ANIMATION_BEZIER_EDITOR_H
#include "animation_track_editor.h"
-#include "core/templates/rb_set.h"
+#include "core/templates/hashfuncs.h"
+class EditorUndoRedoManager;
class ViewPanner;
class AnimationBezierTrackEdit : public Control {
@@ -44,16 +45,21 @@ class AnimationBezierTrackEdit : public Control {
MENU_KEY_DUPLICATE,
MENU_KEY_DELETE,
MENU_KEY_SET_HANDLE_FREE,
+ MENU_KEY_SET_HANDLE_LINEAR,
MENU_KEY_SET_HANDLE_BALANCED,
+ MENU_KEY_SET_HANDLE_MIRRORED,
+ MENU_KEY_SET_HANDLE_AUTO_BALANCED,
+ MENU_KEY_SET_HANDLE_AUTO_MIRRORED,
};
AnimationTimelineEdit *timeline = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Node *root = nullptr;
Control *play_position = nullptr; //separate control used to draw so updates for only position changed are much faster
- float play_position_pos = 0;
+ real_t play_position_pos = 0;
Ref<Animation> animation;
+ bool read_only = false;
int selected_track = 0;
Vector<Rect2> view_rects;
@@ -110,25 +116,37 @@ class AnimationBezierTrackEdit : public Control {
Vector2 box_selection_from;
Vector2 box_selection_to;
- int moving_handle = 0; //0 no move -1 or +1 out
+ int moving_handle = 0; //0 no move -1 or +1 out, 2 both (drawing only)
int moving_handle_key = 0;
int moving_handle_track = 0;
Vector2 moving_handle_left;
Vector2 moving_handle_right;
int moving_handle_mode = 0; // value from Animation::HandleMode
+ struct PairHasher {
+ static _FORCE_INLINE_ uint32_t hash(const Pair<int, int> &p_value) {
+ int32_t hash = 23;
+ hash = hash * 31 * hash_one_uint64(p_value.first);
+ hash = hash * 31 * hash_one_uint64(p_value.second);
+ return hash;
+ }
+ };
+
+ HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_lefts;
+ HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_rights;
+
void _clear_selection();
void _clear_selection_for_anim(const Ref<Animation> &p_anim);
- void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos);
- void _change_selected_keys_handle_mode(Animation::HandleMode p_mode);
+ void _select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos);
+ void _change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto = false);
Vector2 menu_insert_key;
struct AnimMoveRestore {
int track = 0;
- float time = 0;
+ double time = 0;
Variant key;
- float transition = 0;
+ real_t transition = 0;
};
AnimationTrackEditor *editor = nullptr;
@@ -143,7 +161,7 @@ class AnimationBezierTrackEdit : public Control {
Vector<EditPoint> edit_points;
- struct SelectionCompare {
+ struct PairCompare {
bool operator()(const IntPair &lh, const IntPair &rh) {
if (lh.first == rh.first) {
return lh.second < rh.second;
@@ -153,7 +171,7 @@ class AnimationBezierTrackEdit : public Control {
}
};
- typedef RBSet<IntPair, SelectionCompare> SelectionSet;
+ typedef RBSet<IntPair, PairCompare> SelectionSet;
SelectionSet selection;
@@ -176,21 +194,23 @@ public:
Ref<Animation> get_animation() const;
- void set_animation_and_track(const Ref<Animation> &p_animation, int p_track);
+ void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only);
virtual Size2 get_minimum_size() const override;
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_timeline(AnimationTimelineEdit *p_timeline);
void set_editor(AnimationTrackEditor *p_editor);
void set_root(Node *p_root);
void set_filtered(bool p_filtered);
- void set_play_position(float p_pos);
+ void set_play_position(real_t p_pos);
void update_play_position();
void duplicate_selection();
void delete_selection();
+ void _bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode);
+
AnimationBezierTrackEdit();
};
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 83047caf98..70b5501692 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -35,8 +35,10 @@
#include "editor/animation_bezier_editor.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "scene/animation/animation_player.h"
+#include "scene/animation/tween.h"
#include "scene/gui/separator.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
@@ -48,21 +50,24 @@ class AnimationTrackKeyEdit : public Object {
public:
bool setting = false;
+ bool animation_read_only = false;
- bool _hide_script_from_inspector() {
- return true;
- }
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+ bool _dont_undo_redo() { return true; }
- bool _dont_undo_redo() {
- return true;
+ bool _is_read_only() {
+ return animation_read_only;
}
static void _bind_methods() {
- ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj);
- ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed);
- ClassDB::bind_method("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector);
- ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path);
- ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
+ ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed);
+ ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector);
+ ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationTrackKeyEdit::_hide_metadata_from_inspector);
+ ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path);
+ ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only);
}
void _fix_node_path(Variant &value) {
@@ -343,8 +348,8 @@ public:
setting = true;
undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
int prev = animation->bezier_track_get_key_handle_mode(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
undo_redo->add_do_method(this, "_update_obj", animation);
undo_redo->add_undo_method(this, "_update_obj", animation);
undo_redo->commit_action();
@@ -629,10 +634,16 @@ public:
} break;
case Animation::TYPE_BEZIER: {
+ Animation::HandleMode hm = animation->bezier_track_get_key_handle_mode(track, key);
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle")));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle")));
- p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Balanced"));
+ if (hm == Animation::HANDLE_MODE_LINEAR) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ } else {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle")));
+ }
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
} break;
case Animation::TYPE_AUDIO: {
@@ -674,7 +685,7 @@ public:
}
}
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<Animation> animation;
int track = -1;
float key_ofs = 0;
@@ -703,21 +714,24 @@ class AnimationMultiTrackKeyEdit : public Object {
public:
bool setting = false;
+ bool animation_read_only = false;
- bool _hide_script_from_inspector() {
- return true;
- }
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+ bool _dont_undo_redo() { return true; }
- bool _dont_undo_redo() {
- return true;
+ bool _is_read_only() {
+ return animation_read_only;
}
static void _bind_methods() {
- ClassDB::bind_method("_update_obj", &AnimationMultiTrackKeyEdit::_update_obj);
- ClassDB::bind_method("_key_ofs_changed", &AnimationMultiTrackKeyEdit::_key_ofs_changed);
- ClassDB::bind_method("_hide_script_from_inspector", &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
- ClassDB::bind_method("get_root_path", &AnimationMultiTrackKeyEdit::get_root_path);
- ClassDB::bind_method("_dont_undo_redo", &AnimationMultiTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj);
+ ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed);
+ ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
+ ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_metadata_from_inspector);
+ ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path);
+ ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only);
}
void _fix_node_path(Variant &value, NodePath &base) {
@@ -958,8 +972,8 @@ public:
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
Vector2 prev = animation->bezier_track_get_key_in_handle(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev);
update_obj = true;
} else if (name == "out_handle") {
const Variant &value = p_value;
@@ -969,8 +983,8 @@ public:
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
Vector2 prev = animation->bezier_track_get_key_out_handle(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_out_handle", track, key, prev);
update_obj = true;
} else if (name == "handle_mode") {
const Variant &value = p_value;
@@ -980,8 +994,8 @@ public:
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
int prev = animation->bezier_track_get_key_handle_mode(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
update_obj = true;
}
} break;
@@ -1312,7 +1326,7 @@ public:
p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
- p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Balanced"));
+ p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
} break;
case Animation::TYPE_AUDIO: {
p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
@@ -1362,7 +1376,7 @@ public:
bool use_fps = false;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void notify_change() {
notify_property_list_changed();
@@ -1379,8 +1393,8 @@ public:
};
void AnimationTimelineEdit::_zoom_changed(double) {
- update();
- play_position->update();
+ queue_redraw();
+ play_position->queue_redraw();
emit_signal(SNAME("zoom_changed"));
}
@@ -1410,28 +1424,38 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length());
undo_redo->commit_action();
editing = false;
- update();
+ queue_redraw();
emit_signal(SNAME("length_changed"), p_new_len);
}
void AnimationTimelineEdit::_anim_loop_pressed() {
- undo_redo->create_action(TTR("Change Animation Loop"));
- switch (animation->get_loop_mode()) {
- case Animation::LOOP_NONE: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR);
- } break;
- case Animation::LOOP_LINEAR: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG);
- } break;
- case Animation::LOOP_PINGPONG: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE);
- } break;
- default:
- break;
+ if (!read_only) {
+ undo_redo->create_action(TTR("Change Animation Loop"));
+ switch (animation->get_loop_mode()) {
+ case Animation::LOOP_NONE: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR);
+ } break;
+ case Animation::LOOP_LINEAR: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG);
+ } break;
+ case Animation::LOOP_PINGPONG: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE);
+ } break;
+ default:
+ break;
+ }
+ undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
+ undo_redo->commit_action();
+ } else {
+ String base_path = animation->get_path();
+ if (FileAccess::exists(base_path + ".import")) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation instanced from imported scene."));
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation embedded in another scene."));
+ }
+ update_values();
}
- undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
- undo_redo->commit_action();
}
int AnimationTimelineEdit::get_buttons_width() const {
@@ -1656,18 +1680,24 @@ void AnimationTimelineEdit::_notification(int p_what) {
}
}
-void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation) {
+void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, bool p_read_only) {
animation = p_animation;
+ read_only = p_read_only;
+
if (animation.is_valid()) {
len_hb->show();
- add_track->show();
+ if (read_only) {
+ add_track->hide();
+ } else {
+ add_track->show();
+ }
play_position->show();
} else {
len_hb->hide();
add_track->hide();
play_position->hide();
}
- update();
+ queue_redraw();
update_values();
}
@@ -1680,7 +1710,7 @@ Size2 AnimationTimelineEdit::get_minimum_size() const {
return ms;
}
-void AnimationTimelineEdit::set_undo_redo(UndoRedo *p_undo_redo) {
+void AnimationTimelineEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -1695,7 +1725,7 @@ void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) {
void AnimationTimelineEdit::set_play_position(float p_pos) {
play_position_pos = p_pos;
- play_position->update();
+ play_position->queue_redraw();
}
float AnimationTimelineEdit::get_play_position() const {
@@ -1703,7 +1733,7 @@ float AnimationTimelineEdit::get_play_position() const {
}
void AnimationTimelineEdit::update_play_position() {
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationTimelineEdit::update_values() {
@@ -1715,13 +1745,13 @@ void AnimationTimelineEdit::update_values() {
if (use_fps && animation->get_step() > 0) {
length->set_value(animation->get_length() / animation->get_step());
length->set_step(1);
- length->set_tooltip(TTR("Animation length (frames)"));
- time_icon->set_tooltip(TTR("Animation length (frames)"));
+ length->set_tooltip_text(TTR("Animation length (frames)"));
+ time_icon->set_tooltip_text(TTR("Animation length (frames)"));
} else {
length->set_value(animation->get_length());
length->set_step(0.001);
- length->set_tooltip(TTR("Animation length (seconds)"));
- time_icon->set_tooltip(TTR("Animation length (seconds)"));
+ length->set_tooltip_text(TTR("Animation length (seconds)"));
+ time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
}
switch (animation->get_loop_mode()) {
@@ -1817,9 +1847,9 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (dragging_hsize) {
int ofs = mm->get_position().x - dragging_hsize_from;
name_limit = dragging_hsize_at + ofs;
- update();
+ queue_redraw();
emit_signal(SNAME("name_limit_changed"));
- play_position->update();
+ play_position->queue_redraw();
}
if (dragging_timeline) {
int x = mm->get_position().x - get_name_limit();
@@ -1862,7 +1892,7 @@ void AnimationTimelineEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origi
void AnimationTimelineEdit::set_use_fps(bool p_use_fps) {
use_fps = p_use_fps;
update_values();
- update();
+ queue_redraw();
}
bool AnimationTimelineEdit::is_using_fps() const {
@@ -1906,7 +1936,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
len_hb->add_child(expander);
time_icon = memnew(TextureRect);
time_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
- time_icon->set_tooltip(TTR("Animation length (seconds)"));
+ time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
len_hb->add_child(time_icon);
length = memnew(EditorSpinSlider);
length->set_min(0.001);
@@ -1915,12 +1945,12 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
length->set_allow_greater(true);
length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
length->set_hide_slider(true);
- length->set_tooltip(TTR("Animation length (seconds)"));
+ length->set_tooltip_text(TTR("Animation length (seconds)"));
length->connect("value_changed", callable_mp(this, &AnimationTimelineEdit::_anim_length_changed));
len_hb->add_child(length);
loop = memnew(Button);
loop->set_flat(true);
- loop->set_tooltip(TTR("Animation Looping"));
+ loop->set_tooltip_text(TTR("Animation Looping"));
loop->connect("pressed", callable_mp(this, &AnimationTimelineEdit::_anim_loop_pressed));
loop->set_toggle_mode(true);
len_hb->add_child(loop);
@@ -1982,6 +2012,8 @@ void AnimationTrackEdit::_notification(int p_what) {
Color linecolor = color;
linecolor.a = 0.2;
+ Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
+
// NAMES AND ICONS //
{
@@ -2084,11 +2116,12 @@ void AnimationTrackEdit::_notification(int p_what) {
get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")),
get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")),
};
-
- Ref<Texture2D> interp_icon[3] = {
+ Ref<Texture2D> interp_icon[5] = {
get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")),
get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons"))
+ get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")),
};
Ref<Texture2D> cont_icon[4] = {
get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")),
@@ -2131,14 +2164,18 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += update_icon->get_width() + hsep / 2;
update_mode_rect.size.x += hsep / 2;
- if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
- draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
- update_mode_rect.size.x += down_icon->get_width();
- } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
- Ref<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons"));
- update_mode_rect.size.x += down_icon->get_width();
+ if (!read_only) {
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
+ draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
+ update_mode_rect.size.x += down_icon->get_width();
+ } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
+ Ref<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons"));
+ update_mode_rect.size.x += down_icon->get_width();
- update_mode_rect = Rect2();
+ update_mode_rect = Rect2();
+ } else {
+ update_mode_rect = Rect2();
+ }
} else {
update_mode_rect = Rect2();
}
@@ -2169,7 +2206,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep / 2;
interp_mode_rect.size.x += hsep / 2;
- if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
+ if (!read_only && !animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
interp_mode_rect.size.x += down_icon->get_width();
} else {
@@ -2202,7 +2239,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep / 2;
loop_wrap_rect.size.x += hsep / 2;
- if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
+ if (!read_only && !animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
loop_wrap_rect.size.x += down_icon->get_width();
} else {
@@ -2223,7 +2260,11 @@ void AnimationTrackEdit::_notification(int p_what) {
remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
remove_rect.size = icon->get_size();
- draw_texture(icon, remove_rect.position);
+ if (read_only) {
+ draw_texture(icon, remove_rect.position, dc);
+ } else {
+ draw_texture(icon, remove_rect.position);
+ }
}
}
@@ -2245,13 +2286,13 @@ void AnimationTrackEdit::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER:
hovered = true;
- update();
+ queue_redraw();
break;
case NOTIFICATION_MOUSE_EXIT:
hovered = false;
// When the mouse cursor exits the track, we're no longer hovering any keyframe.
hovering_key_idx = -1;
- update();
+ queue_redraw();
[[fallthrough]];
case NOTIFICATION_DRAG_END: {
cancel_drop();
@@ -2370,7 +2411,7 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
draw_texture(
icon_to_draw,
ofs,
- p_index == hovering_key_idx ? get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")) : Color(1, 1, 1));
+ p_index == hovering_key_idx ? get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")) : Color(1, 1, 1));
}
// Helper.
@@ -2439,10 +2480,12 @@ Ref<Animation> AnimationTrackEdit::get_animation() const {
return animation;
}
-void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) {
+void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only) {
animation = p_animation;
+ read_only = p_read_only;
+
track = p_track;
- update();
+ queue_redraw();
ERR_FAIL_INDEX(track, animation->get_track_count());
@@ -2467,10 +2510,14 @@ Size2 AnimationTrackEdit::get_minimum_size() const {
return Vector2(1, max_h + separation);
}
-void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
+void AnimationTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
+Ref<EditorUndoRedoManager> AnimationTrackEdit::get_undo_redo() const {
+ return undo_redo;
+}
+
void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
timeline = p_timeline;
timeline->set_track_edit(this);
@@ -2500,11 +2547,11 @@ void AnimationTrackEdit::_play_position_draw() {
void AnimationTrackEdit::set_play_position(float p_pos) {
play_position_pos = p_pos;
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationTrackEdit::update_play_position() {
- play_position->update();
+ play_position->queue_redraw();
}
void AnimationTrackEdit::set_root(Node *p_root) {
@@ -2512,8 +2559,8 @@ void AnimationTrackEdit::set_root(Node *p_root) {
}
void AnimationTrackEdit::_zoom_changed() {
- update();
- play_position->update();
+ queue_redraw();
+ play_position->queue_redraw();
}
void AnimationTrackEdit::_path_submitted(const String &p_text) {
@@ -2680,9 +2727,15 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
case Animation::HANDLE_MODE_FREE: {
text += TTR("Handle mode: Free\n");
} break;
+ case Animation::HANDLE_MODE_LINEAR: {
+ text += TTR("Handle mode: Linear\n");
+ } break;
case Animation::HANDLE_MODE_BALANCED: {
text += TTR("Handle mode: Balanced\n");
} break;
+ case Animation::HANDLE_MODE_MIRRORED: {
+ text += TTR("Handle mode: Mirrored\n");
+ } break;
}
} break;
case Animation::TYPE_AUDIO: {
@@ -2721,17 +2774,23 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) {
- emit_signal(SNAME("duplicate_request"));
+ if (!read_only) {
+ emit_signal(SNAME("duplicate_request"));
+ }
accept_event();
}
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection_transposed")->matches_event(p_event)) {
- emit_signal(SNAME("duplicate_transpose_request"));
+ if (!read_only) {
+ emit_signal(SNAME("duplicate_transpose_request"));
+ }
accept_event();
}
if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) {
- emit_signal(SNAME("delete_request"));
+ if (!read_only) {
+ emit_signal(SNAME("delete_request"));
+ }
accept_event();
}
}
@@ -2740,79 +2799,98 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Point2 pos = mb->get_position();
- if (check_rect.has_point(pos)) {
- undo_redo->create_action(TTR("Toggle Track Enabled"));
- undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
- undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
- undo_redo->commit_action();
- update();
- accept_event();
- }
+ if (!read_only) {
+ if (check_rect.has_point(pos)) {
+ undo_redo->create_action(TTR("Toggle Track Enabled"));
+ undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
+ undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
+ undo_redo->commit_action();
+ queue_redraw();
+ accept_event();
+ }
- // Don't overlap track keys if they start at 0.
- if (path_rect.has_point(pos + Size2(type_icon->get_width(), 0))) {
- clicking_on_name = true;
- accept_event();
- }
+ // Don't overlap track keys if they start at 0.
+ if (path_rect.has_point(pos + Size2(type_icon->get_width(), 0))) {
+ clicking_on_name = true;
+ accept_event();
+ }
- if (update_mode_rect.has_point(pos)) {
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ if (update_mode_rect.has_point(pos)) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS);
+ menu->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), TTR("Discrete"), MENU_CALL_MODE_DISCRETE);
+ menu->add_icon_item(get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")), TTR("Trigger"), MENU_CALL_MODE_TRIGGER);
+ menu->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), TTR("Capture"), MENU_CALL_MODE_CAPTURE);
+ menu->reset_size();
+
+ Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
+ menu->set_position(popup_pos);
+ menu->popup();
+ accept_event();
}
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS);
- menu->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), TTR("Discrete"), MENU_CALL_MODE_DISCRETE);
- menu->add_icon_item(get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")), TTR("Trigger"), MENU_CALL_MODE_TRIGGER);
- menu->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), TTR("Capture"), MENU_CALL_MODE_CAPTURE);
- menu->reset_size();
-
- Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
- menu->set_position(popup_pos);
- menu->popup();
- accept_event();
- }
- if (interp_mode_rect.has_point(pos)) {
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ if (interp_mode_rect.has_point(pos)) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
+ // Check is angle property.
+ AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
+ if (ape) {
+ AnimationPlayer *ap = ape->get_player();
+ if (ap) {
+ NodePath path = animation->track_get_path(track);
+ Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(path.get_concatenated_names()));
+ StringName prop = path.get_concatenated_subnames();
+ PropertyInfo prop_info;
+ ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
+ bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
+ if (is_angle) {
+ menu->add_icon_item(get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE);
+ }
+ }
+ }
+ menu->reset_size();
+
+ Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
+ menu->set_position(popup_pos);
+ menu->popup();
+ accept_event();
}
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
- menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
- menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
- menu->reset_size();
-
- Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
- menu->set_position(popup_pos);
- menu->popup();
- accept_event();
- }
- if (loop_wrap_rect.has_point(pos)) {
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ if (loop_wrap_rect.has_point(pos)) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
+ menu->reset_size();
+
+ Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height);
+ menu->set_position(popup_pos);
+ menu->popup();
+ accept_event();
}
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP);
- menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
- menu->reset_size();
-
- Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height);
- menu->set_position(popup_pos);
- menu->popup();
- accept_event();
- }
- if (remove_rect.has_point(pos)) {
- emit_signal(SNAME("remove_request"), track);
- accept_event();
- return;
+ if (remove_rect.has_point(pos)) {
+ emit_signal(SNAME("remove_request"), track);
+ accept_event();
+ return;
+ }
}
// Check keyframes.
@@ -2852,7 +2930,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
if (key_idx != -1) {
- if (mb->is_command_pressed() || mb->is_shift_pressed()) {
+ if (mb->is_command_or_control_pressed() || mb->is_shift_pressed()) {
if (editor->is_key_selected(track, key_idx)) {
emit_signal(SNAME("deselect_key"), key_idx);
} else {
@@ -2872,6 +2950,11 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection_attempt = true;
moving_selection_from_ofs = (mb->get_position().x - limit) / timeline->get_zoom_scale();
}
+
+ if (read_only) {
+ moving_selection_attempt = false;
+ moving_selection_from_ofs = 0.0f;
+ }
accept_event();
}
}
@@ -2883,33 +2966,35 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) {
// Can do something with menu too! show insert key.
float offset = (pos.x - timeline->get_name_limit()) / timeline->get_zoom_scale();
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
- }
+ if (!read_only) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")), TTR("Insert Key"), MENU_KEY_INSERT);
- if (editor->is_selection_active()) {
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE);
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")), TTR("Insert Key"), MENU_KEY_INSERT);
+ if (editor->is_selection_active()) {
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE);
- AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
- if (!player->has_animation(SceneStringNames::get_singleton()->RESET) || animation != player->get_animation(SceneStringNames::get_singleton()->RESET)) {
- menu->add_icon_item(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Add RESET Value(s)"), MENU_KEY_ADD_RESET);
- }
+ AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
+ if (!player->has_animation(SceneStringNames::get_singleton()->RESET) || animation != player->get_animation(SceneStringNames::get_singleton()->RESET)) {
+ menu->add_icon_item(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Add RESET Value(s)"), MENU_KEY_ADD_RESET);
+ }
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Key(s)"), MENU_KEY_DELETE);
- }
- menu->reset_size();
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Key(s)"), MENU_KEY_DELETE);
+ }
+ menu->reset_size();
- menu->set_position(get_screen_position() + get_local_mouse_position());
- menu->popup();
+ menu->set_position(get_screen_position() + get_local_mouse_position());
+ menu->popup();
- insert_at_pos = offset + timeline->get_value();
- accept_event();
+ insert_at_pos = offset + timeline->get_value();
+ accept_event();
+ }
}
}
@@ -2999,7 +3084,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (hovering_key_idx != previous_hovering_key_idx) {
// Required to draw keyframe hover feedback on the correct keyframe.
- update();
+ queue_redraw();
}
}
}
@@ -3065,7 +3150,7 @@ bool AnimationTrackEdit::can_drop_data(const Point2 &p_point, const Variant &p_d
dropping_at = 1;
}
- const_cast<AnimationTrackEdit *>(this)->update();
+ const_cast<AnimationTrackEdit *>(this)->queue_redraw();
const_cast<AnimationTrackEdit *>(this)->emit_signal(SNAME("drop_attempted"), track);
return true;
@@ -3111,18 +3196,20 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", track, update_mode);
undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", track, animation->value_track_get_update_mode(track));
undo_redo->commit_action();
- update();
+ queue_redraw();
} break;
case MENU_INTERPOLATION_NEAREST:
case MENU_INTERPOLATION_LINEAR:
- case MENU_INTERPOLATION_CUBIC: {
+ case MENU_INTERPOLATION_CUBIC:
+ case MENU_INTERPOLATION_LINEAR_ANGLE:
+ case MENU_INTERPOLATION_CUBIC_ANGLE: {
Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST);
undo_redo->create_action(TTR("Change Animation Interpolation Mode"));
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", track, animation->track_get_interpolation_type(track));
undo_redo->commit_action();
- update();
+ queue_redraw();
} break;
case MENU_LOOP_WRAP:
case MENU_LOOP_CLAMP: {
@@ -3131,7 +3218,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, loop_wrap);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, animation->track_get_interpolation_loop_wrap(track));
undo_redo->commit_action();
- update();
+ queue_redraw();
} break;
case MENU_KEY_INSERT: {
@@ -3154,13 +3241,13 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
void AnimationTrackEdit::cancel_drop() {
if (dropping_at != 0) {
dropping_at = 0;
- update();
+ queue_redraw();
}
}
void AnimationTrackEdit::set_in_group(bool p_enable) {
in_group = p_enable;
- update();
+ queue_redraw();
}
void AnimationTrackEdit::append_to_selection(const Rect2 &p_box, bool p_deselection) {
@@ -3196,7 +3283,6 @@ void AnimationTrackEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset")));
ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "index")));
- ADD_SIGNAL(MethodInfo("bezier_edit"));
ADD_SIGNAL(MethodInfo("move_selection_begin"));
ADD_SIGNAL(MethodInfo("move_selection", PropertyInfo(Variant::FLOAT, "offset")));
@@ -3307,7 +3393,7 @@ void AnimationTrackEditGroup::set_type_and_name(const Ref<Texture2D> &p_type, co
icon = p_type;
node_name = p_name;
node = p_node;
- update();
+ queue_redraw();
update_minimum_size();
}
@@ -3327,11 +3413,11 @@ void AnimationTrackEditGroup::set_timeline(AnimationTimelineEdit *p_timeline) {
void AnimationTrackEditGroup::set_root(Node *p_root) {
root = p_root;
- update();
+ queue_redraw();
}
void AnimationTrackEditGroup::_zoom_changed() {
- update();
+ queue_redraw();
}
void AnimationTrackEditGroup::_bind_methods() {
@@ -3354,25 +3440,28 @@ void AnimationTrackEditor::remove_track_edit_plugin(const Ref<AnimationTrackEdit
track_edit_plugins.erase(p_plugin);
}
-void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
+void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_read_only) {
if (animation != p_anim && _get_track_selected() >= 0) {
track_edits[_get_track_selected()]->release_focus();
}
if (animation.is_valid()) {
- animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->disconnect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change));
_clear_selection();
}
animation = p_anim;
- timeline->set_animation(p_anim);
+ read_only = p_read_only;
+ timeline->set_animation(p_anim, read_only);
_cancel_bezier_edit();
_update_tracks();
if (animation.is_valid()) {
- animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->connect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed), CONNECT_DEFERRED);
+ animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change), CONNECT_DEFERRED);
hscroll->show();
- edit->set_disabled(false);
+ edit->set_disabled(read_only);
step->set_block_signals(true);
_update_step_spinbox();
@@ -3429,7 +3518,7 @@ void AnimationTrackEditor::set_root(Node *p_root) {
root = p_root;
if (root) {
- root->connect("tree_exiting", callable_mp(this, &AnimationTrackEditor::_root_removed), CONNECT_ONESHOT);
+ root->connect("tree_exiting", callable_mp(this, &AnimationTrackEditor::_root_removed), CONNECT_ONE_SHOT);
}
_update_tracks();
@@ -3501,13 +3590,11 @@ void AnimationTrackEditor::set_state(const Dictionary &p_state) {
}
void AnimationTrackEditor::cleanup() {
- set_animation(Ref<Animation>());
+ set_animation(Ref<Animation>(), read_only);
}
void AnimationTrackEditor::_name_limit_changed() {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only) {
@@ -3602,9 +3689,7 @@ void AnimationTrackEditor::set_anim_pos(float p_pos) {
for (int i = 0; i < track_edits.size(); i++) {
track_edits[i]->set_play_position(p_pos);
}
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_groups();
bezier_edit->set_play_position(p_pos);
}
@@ -4284,13 +4369,12 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
} break;
case Animation::TYPE_BEZIER: {
Array array;
- array.resize(6);
+ array.resize(5);
array[0] = p_id.value;
array[1] = -0.25;
array[2] = 0;
array[3] = 0.25;
array[4] = 0;
- array[5] = Animation::HANDLE_MODE_BALANCED;
value = array;
bezier_edit_icon->set_disabled(false);
@@ -4378,6 +4462,27 @@ void AnimationTrackEditor::_update_tracks() {
return;
}
+ bool read_only = false;
+ if (!animation->get_path().is_resource_file()) {
+ int srpos = animation->get_path().find("::");
+ if (srpos != -1) {
+ String base = animation->get_path().substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ read_only = true;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ read_only = true;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(animation->get_path() + ".import")) {
+ read_only = true;
+ }
+ }
+
RBMap<String, VBoxContainer *> group_sort;
bool use_grouping = !view_group->is_pressed();
@@ -4485,7 +4590,7 @@ void AnimationTrackEditor::_update_tracks() {
g->set_type_and_name(icon, name, animation->track_get_path(i));
g->set_root(root);
- g->set_tooltip(tooltip);
+ g->set_tooltip_text(tooltip);
g->set_timeline(timeline);
groups.push_back(g);
VBoxContainer *vb = memnew(VBoxContainer);
@@ -4506,7 +4611,7 @@ void AnimationTrackEditor::_update_tracks() {
track_edit->set_undo_redo(undo_redo);
track_edit->set_timeline(timeline);
track_edit->set_root(root);
- track_edit->set_animation_and_track(animation, i);
+ track_edit->set_animation_and_track(animation, i, read_only);
track_edit->set_play_position(timeline->get_play_position());
track_edit->set_editor(this);
@@ -4532,18 +4637,38 @@ void AnimationTrackEditor::_update_tracks() {
}
}
+void AnimationTrackEditor::_redraw_tracks() {
+ for (int i = 0; i < track_edits.size(); i++) {
+ track_edits[i]->queue_redraw();
+ }
+}
+
+void AnimationTrackEditor::_redraw_groups() {
+ for (int i = 0; i < groups.size(); i++) {
+ groups[i]->queue_redraw();
+ }
+}
+
+void AnimationTrackEditor::_sync_animation_change() {
+ bezier_edit->queue_redraw();
+}
+
void AnimationTrackEditor::_animation_changed() {
if (animation_changing_awaiting_update) {
return; // All will be updated, don't bother with anything.
}
+ if (key_edit) {
+ _update_key_edit();
+ }
+
if (key_edit && key_edit->setting) {
- // If editing a key, just update the edited track, makes refresh less costly.
+ // If editing a key, just redraw the edited track, makes refresh less costly.
if (key_edit->track < track_edits.size()) {
if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER) {
- bezier_edit->update();
+ bezier_edit->queue_redraw();
} else {
- track_edits[key_edit->track]->update();
+ track_edits[key_edit->track]->queue_redraw();
}
}
return;
@@ -4582,7 +4707,7 @@ void AnimationTrackEditor::_update_step_spinbox() {
}
void AnimationTrackEditor::_animation_update() {
- timeline->update();
+ timeline->queue_redraw();
timeline->update_values();
bool same = true;
@@ -4605,17 +4730,13 @@ void AnimationTrackEditor::_animation_update() {
}
if (same) {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_tracks();
+ _redraw_groups();
} else {
_update_tracks();
}
- bezier_edit->update();
+ bezier_edit->queue_redraw();
_update_step_spinbox();
emit_signal(SNAME("animation_step_changed"), animation->get_step());
@@ -4645,7 +4766,7 @@ void AnimationTrackEditor::_notification(int p_what) {
view_group->set_icon(get_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"), SNAME("EditorIcons")));
selected_filter->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
imported_anim_warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
- main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
} break;
@@ -4660,12 +4781,8 @@ void AnimationTrackEditor::_notification(int p_what) {
}
void AnimationTrackEditor::_update_scroll(double) {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_tracks();
+ _redraw_groups();
}
void AnimationTrackEditor::_update_step(double p_new_step) {
@@ -4693,7 +4810,7 @@ void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) {
return;
}
- _clear_selection();
+ _clear_selection(true);
undo_redo->create_action(TTR("Rearrange Tracks"));
undo_redo->add_do_method(animation.ptr(), "track_move_to", p_from_track, p_to_track);
// Take into account that the position of the tracks that come after the one removed will change.
@@ -4871,16 +4988,13 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) {
void AnimationTrackEditor::_timeline_value_changed(double) {
timeline->update_play_position();
+ _redraw_tracks();
for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
track_edits[i]->update_play_position();
}
+ _redraw_groups();
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
-
- bezier_edit->update();
+ bezier_edit->queue_redraw();
bezier_edit->update_play_position();
}
@@ -4996,13 +5110,12 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
Variant value;
_find_hint_for_track(p_track, bp, &value);
Array arr;
- arr.resize(6);
+ arr.resize(5);
arr[0] = value;
arr[1] = -0.25;
arr[2] = 0;
arr[3] = 0.25;
arr[4] = 0;
- arr[5] = 0;
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr);
@@ -5090,10 +5203,7 @@ void AnimationTrackEditor::_key_selected(int p_key, bool p_single, int p_track)
ki.pos = animation->track_get_key_time(p_track, p_key);
selection[sk] = ki;
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
+ _redraw_tracks();
_update_key_edit();
}
@@ -5107,10 +5217,7 @@ void AnimationTrackEditor::_key_deselected(int p_key, int p_track) {
selection.erase(sk);
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
+ _redraw_tracks();
_update_key_edit();
}
@@ -5121,10 +5228,7 @@ void AnimationTrackEditor::_move_selection_begin() {
void AnimationTrackEditor::_move_selection(float p_offset) {
moving_selection_offset = p_offset;
-
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
struct _AnimMoveRestore {
@@ -5161,9 +5265,7 @@ void AnimationTrackEditor::_clear_selection(bool p_update) {
selection.clear();
if (p_update) {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
_clear_key_edit();
@@ -5178,6 +5280,7 @@ void AnimationTrackEditor::_update_key_edit() {
if (selection.size() == 1) {
key_edit = memnew(AnimationTrackKeyEdit);
key_edit->animation = animation;
+ key_edit->animation_read_only = read_only;
key_edit->track = selection.front()->key().track;
key_edit->use_fps = timeline->is_using_fps();
@@ -5194,6 +5297,7 @@ void AnimationTrackEditor::_update_key_edit() {
} else if (selection.size() > 1) {
multi_key_edit = memnew(AnimationMultiTrackKeyEdit);
multi_key_edit->animation = animation;
+ multi_key_edit->animation_read_only = read_only;
RBMap<int, List<float>> key_ofs_map;
RBMap<int, NodePath> base_map;
@@ -5319,21 +5423,16 @@ void AnimationTrackEditor::_move_selection_commit() {
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
}
- undo_redo->commit_action();
-
moving_selection = false;
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
_update_key_edit();
}
void AnimationTrackEditor::_move_selection_cancel() {
moving_selection = false;
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
bool AnimationTrackEditor::is_moving_selection() const {
@@ -5369,14 +5468,14 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
for (int i = 0; i < track_edits.size(); i++) {
Rect2 local_rect = box_select_rect;
local_rect.position -= track_edits[i]->get_global_position();
- track_edits[i]->append_to_selection(local_rect, mb->is_command_pressed());
+ track_edits[i]->append_to_selection(local_rect, mb->is_command_or_control_pressed());
}
if (_get_track_selected() == -1 && track_edits.size() > 0) { // Minimal hack to make shortcuts work.
track_edits[track_edits.size() - 1]->grab_focus();
}
} else {
- _clear_selection(); // Clear it.
+ _clear_selection(true); // Clear it.
}
box_selection->hide();
@@ -5395,8 +5494,8 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
}
if (!box_selection->is_visible_in_tree()) {
- if (!mm->is_command_pressed() && !mm->is_shift_pressed()) {
- _clear_selection();
+ if (!mm->is_command_or_control_pressed() && !mm->is_shift_pressed()) {
+ _clear_selection(true);
}
box_selection->show();
}
@@ -5473,12 +5572,19 @@ void AnimationTrackEditor::_cancel_bezier_edit() {
void AnimationTrackEditor::_bezier_edit(int p_for_track) {
_clear_selection(); // Bezier probably wants to use a separate selection mode.
bezier_edit->set_root(root);
- bezier_edit->set_animation_and_track(animation, p_for_track);
+ bezier_edit->set_animation_and_track(animation, p_for_track, read_only);
scroll->hide();
bezier_edit->show();
// Search everything within the track and curve - edit it.
}
+void AnimationTrackEditor::_bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode) {
+ if (!p_anim) {
+ return;
+ }
+ p_anim->bezier_track_set_key_handle_mode(p_track, p_index, p_mode, p_set_mode);
+}
+
void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
// Duplicait!
if (selection.size() && animation.is_valid() && (!transpose || (_get_track_selected() >= 0 && _get_track_selected() < animation->get_track_count()))) {
@@ -5536,32 +5642,21 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
}
}
- undo_redo->commit_action();
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
// Reselect duplicated.
-
RBMap<SelectedKey, KeyInfo> new_selection;
for (const Pair<int, float> &E : new_selection_values) {
- int track = E.first;
- float time = E.second;
-
- int existing_idx = animation->track_find_key(track, time, true);
-
- if (existing_idx == -1) {
- continue;
- }
- SelectedKey sk2;
- sk2.track = track;
- sk2.key = existing_idx;
-
- KeyInfo ki;
- ki.pos = time;
-
- new_selection[sk2] = ki;
+ undo_redo->add_do_method(this, "_select_at_anim", animation, E.first, E.second);
+ }
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, E->get().pos);
}
- selection = new_selection;
- _update_tracks();
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
_update_key_edit();
}
}
@@ -5882,8 +5977,110 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
}
#undef NEW_POS
+
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
undo_redo->commit_action();
+ _update_key_edit();
+
+ } break;
+
+ case EDIT_EASE_SELECTION: {
+ ease_dialog->popup_centered(Size2(200, 100) * EDSCALE);
} break;
+ case EDIT_EASE_CONFIRM: {
+ undo_redo->create_action(TTR("Make Easing Keys"));
+
+ Tween::TransitionType transition_type = static_cast<Tween::TransitionType>(transition_selection->get_selected_id());
+ Tween::EaseType ease_type = static_cast<Tween::EaseType>(ease_selection->get_selected_id());
+ float fps = ease_fps->get_value();
+ double dur_step = 1.0 / fps;
+
+ // Organize track and key.
+ HashMap<int, Vector<int>> keymap;
+ Vector<int> tracks;
+ for (const KeyValue<SelectedKey, KeyInfo> &E : selection) {
+ if (!tracks.has(E.key.track)) {
+ tracks.append(E.key.track);
+ }
+ }
+ for (int i = 0; i < tracks.size(); i++) {
+ switch (animation->track_get_type(tracks[i])) {
+ case Animation::TYPE_VALUE:
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D:
+ case Animation::TYPE_BLEND_SHAPE: {
+ Vector<int> keys;
+ for (const KeyValue<SelectedKey, KeyInfo> &E : selection) {
+ if (E.key.track == tracks[i]) {
+ keys.append(E.key.key);
+ }
+ }
+ keys.sort();
+ keymap.insert(tracks[i], keys);
+ } break;
+ default: {
+ } break;
+ }
+ }
+
+ // Make easing.
+ HashMap<int, Vector<int>>::Iterator E = keymap.begin();
+ while (E) {
+ int track = E->key;
+ Vector<int> keys = E->value;
+ int len = keys.size() - 1;
+
+ // Special case for angle interpolation.
+ bool is_using_angle = animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_LINEAR_ANGLE || animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_CUBIC_ANGLE;
+
+ // Make insert queue.
+ Vector<Pair<real_t, Variant>> insert_queue;
+ for (int i = 0; i < len; i++) {
+ // Check neighboring keys.
+ if (keys[i] + 1 == keys[i + 1]) {
+ double from_t = animation->track_get_key_time(track, keys[i]);
+ double to_t = animation->track_get_key_time(track, keys[i + 1]);
+ Variant from_v = animation->track_get_key_value(track, keys[i]);
+ Variant to_v = animation->track_get_key_value(track, keys[i + 1]);
+ if (is_using_angle) {
+ real_t a = from_v;
+ real_t b = to_v;
+ real_t to_diff = fmod(b - a, Math_TAU);
+ to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
+ }
+ Variant delta_v;
+ Variant::sub(to_v, from_v, delta_v);
+ double duration = to_t - from_t;
+ double fixed_duration = duration - 0.01; // Prevent to overwrap keys...
+ for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = from_t + delta_t;
+ keydata.second = Tween::interpolate_variant(from_v, delta_v, delta_t, duration, transition_type, ease_type);
+ insert_queue.append(keydata);
+ }
+ }
+ }
+
+ // Do insertion.
+ for (int i = 0; i < insert_queue.size(); i++) {
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, insert_queue[i].first, insert_queue[i].second);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, insert_queue[i].first);
+ }
+
+ ++E;
+ }
+
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
+ _update_key_edit();
+
+ } break;
+
case EDIT_DUPLICATE_SELECTION: {
if (bezier_edit->is_visible()) {
bezier_edit->duplicate_selection();
@@ -5900,6 +6097,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case EDIT_ADD_RESET_KEY: {
undo_redo->create_action(TTR("Anim Add RESET Keys"));
+
Ref<Animation> reset = _create_and_get_reset_animation();
int reset_tracks = reset->get_track_count();
HashSet<int> tracks_added;
@@ -5944,6 +6142,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
}
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
undo_redo->commit_action();
} break;
@@ -5962,6 +6164,8 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
undo_redo->commit_action();
_update_key_edit();
}
@@ -5973,18 +6177,137 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
case EDIT_GOTO_PREV_STEP: {
goto_prev_step(false);
} break;
+
case EDIT_APPLY_RESET: {
AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true);
+ } break;
+
+ case EDIT_BAKE_ANIMATION: {
+ bake_dialog->popup_centered(Size2(200, 100) * EDSCALE);
+ } break;
+ case EDIT_BAKE_ANIMATION_CONFIRM: {
+ undo_redo->create_action(TTR("Bake Animation as Linear keys."));
+
+ int track_len = animation->get_track_count();
+ bool b_trs = bake_trs->is_pressed();
+ bool b_bs = bake_blendshape->is_pressed();
+ bool b_v = bake_value->is_pressed();
+
+ double anim_len = animation->get_length() + CMP_EPSILON; // For end key.
+ float fps = bake_fps->get_value();
+ double dur_step = 1.0 / fps;
+
+ for (int i = 0; i < track_len; i++) {
+ bool do_bake = false;
+ Animation::TrackType type = animation->track_get_type(i);
+ do_bake |= b_trs && (type == Animation::TYPE_POSITION_3D || type == Animation::TYPE_ROTATION_3D || type == Animation::TYPE_SCALE_3D);
+ do_bake |= b_bs && type == Animation::TYPE_BLEND_SHAPE;
+ do_bake |= b_v && type == Animation::TYPE_VALUE;
+ if (do_bake && !animation->track_is_compressed(i)) {
+ Animation::InterpolationType it = animation->track_get_interpolation_type(i);
+ if (it == Animation::INTERPOLATION_NEAREST) {
+ continue; // Nearest and Angle interpolation cannot be baked.
+ }
+
+ // Special case for angle interpolation.
+ bool is_using_angle = it == Animation::INTERPOLATION_LINEAR_ANGLE || it == Animation::INTERPOLATION_CUBIC_ANGLE;
+
+ // Make insert queue.
+ Vector<Pair<real_t, Variant>> insert_queue;
+
+ switch (type) {
+ case Animation::TYPE_POSITION_3D: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ Vector3 v;
+ animation->position_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ Quaternion v;
+ animation->rotation_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ Vector3 v;
+ animation->scale_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_BLEND_SHAPE: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ float v;
+ animation->blend_shape_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_VALUE: {
+ for (double delta_t = 0.0; delta_t < anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ keydata.second = animation->value_track_interpolate(i, delta_t);
+ insert_queue.append(keydata);
+ }
+ } break;
+ default: {
+ } break;
+ }
+
+ // Cleanup keys.
+ int key_len = animation->track_get_key_count(i);
+ for (int j = key_len - 1; j >= 0; j--) {
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key", i, j);
+ }
+
+ // Insert keys.
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, is_using_angle ? Animation::INTERPOLATION_LINEAR_ANGLE : Animation::INTERPOLATION_LINEAR);
+ for (int j = insert_queue.size() - 1; j >= 0; j--) {
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", i, insert_queue[j].first, insert_queue[j].second);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", i, insert_queue[j].first);
+ }
+
+ // Undo methods.
+ undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", i, animation->track_get_interpolation_type(i));
+ for (int j = key_len - 1; j >= 0; j--) {
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", i, animation->track_get_key_time(i, j), animation->track_get_key_value(i, j), animation->track_get_key_transition(i, j));
+ }
+ }
+ }
+
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
+ _update_key_edit();
} break;
+
case EDIT_OPTIMIZE_ANIMATION: {
optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE);
} break;
case EDIT_OPTIMIZE_ANIMATION_CONFIRM: {
- animation->optimize(optimize_linear_error->get_value(), optimize_angular_error->get_value(), optimize_max_angle->get_value());
- _update_tracks();
- undo_redo->clear_history();
+ animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value());
+ _redraw_tracks();
+ _update_key_edit();
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
} break;
case EDIT_CLEAN_UP_ANIMATION: {
@@ -6052,7 +6375,8 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
}
}
- undo_redo->clear_history();
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
_update_tracks();
}
@@ -6074,13 +6398,8 @@ void AnimationTrackEditor::_selection_changed() {
if (selected_filter->is_pressed()) {
_update_tracks(); // Needs updatin.
} else {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_tracks();
+ _redraw_groups();
}
}
@@ -6139,15 +6458,18 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
}
void AnimationTrackEditor::_bind_methods() {
- ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
- ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
- ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks);
- ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
- ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim);
+ ClassDB::bind_method(D_METHOD("_animation_update"), &AnimationTrackEditor::_animation_update);
+ ClassDB::bind_method(D_METHOD("_track_grab_focus"), &AnimationTrackEditor::_track_grab_focus);
+ ClassDB::bind_method(D_METHOD("_update_tracks"), &AnimationTrackEditor::_update_tracks);
+ ClassDB::bind_method(D_METHOD("_redraw_tracks"), &AnimationTrackEditor::_redraw_tracks);
+ ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationTrackEditor::_clear_selection_for_anim);
+ ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationTrackEditor::_select_at_anim);
+
+ ClassDB::bind_method(D_METHOD("_key_selected"), &AnimationTrackEditor::_key_selected); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_key_deselected"), &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat.
- ClassDB::bind_method("_key_selected", &AnimationTrackEditor::_key_selected); // Still used by some connect_compat.
- ClassDB::bind_method("_key_deselected", &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat.
- ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode", "animation", "track_idx", "key_idx", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode, DEFVAL(Animation::HANDLE_SET_MODE_NONE));
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"), PropertyInfo(Variant::BOOL, "timeline_only")));
ADD_SIGNAL(MethodInfo("keying_changed"));
@@ -6222,7 +6544,7 @@ void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie)
}
AnimationTrackEditor::AnimationTrackEditor() {
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
main_panel = memnew(PanelContainer);
main_panel->set_focus_mode(FOCUS_ALL); // Allow panel to have focus so that shortcuts work as expected.
@@ -6299,7 +6621,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
imported_anim_warning = memnew(Button);
imported_anim_warning->hide();
imported_anim_warning->set_text(TTR("Imported Scene"));
- imported_anim_warning->set_tooltip(TTR("Warning: Editing imported animation"));
+ imported_anim_warning->set_tooltip_text(TTR("Warning: Editing imported animation"));
imported_anim_warning->connect("pressed", callable_mp(this, &AnimationTrackEditor::_show_imported_anim_warning));
bottom_hb->add_child(imported_anim_warning);
@@ -6310,7 +6632,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
bezier_edit_icon->set_disabled(true);
bezier_edit_icon->set_toggle_mode(true);
bezier_edit_icon->connect("pressed", callable_mp(this, &AnimationTrackEditor::_toggle_bezier_edit));
- bezier_edit_icon->set_tooltip(TTR("Toggle between the bezier curve editor and track editor."));
+ bezier_edit_icon->set_tooltip_text(TTR("Toggle between the bezier curve editor and track editor."));
bottom_hb->add_child(bezier_edit_icon);
@@ -6318,7 +6640,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
selected_filter->set_flat(true);
selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); // Same function works the same.
selected_filter->set_toggle_mode(true);
- selected_filter->set_tooltip(TTR("Only show tracks from nodes selected in tree."));
+ selected_filter->set_tooltip_text(TTR("Only show tracks from nodes selected in tree."));
bottom_hb->add_child(selected_filter);
@@ -6326,7 +6648,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
view_group->set_flat(true);
view_group->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle));
view_group->set_toggle_mode(true);
- view_group->set_tooltip(TTR("Group tracks by node or display them as plain list."));
+ view_group->set_tooltip_text(TTR("Group tracks by node or display them as plain list."));
bottom_hb->add_child(view_group);
bottom_hb->add_child(memnew(VSeparator));
@@ -6345,7 +6667,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
step->set_step(0.001);
step->set_hide_slider(true);
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
- step->set_tooltip(TTR("Animation step value."));
+ step->set_tooltip_text(TTR("Animation step value."));
bottom_hb->add_child(step);
step->connect("value_changed", callable_mp(this, &AnimationTrackEditor::_update_step));
step->set_read_only(true);
@@ -6377,27 +6699,30 @@ AnimationTrackEditor::AnimationTrackEditor() {
edit->set_text(TTR("Edit"));
edit->set_flat(false);
edit->set_disabled(true);
- edit->set_tooltip(TTR("Animation properties."));
+ edit->set_tooltip_text(TTR("Animation properties."));
edit->get_popup()->add_item(TTR("Copy Tracks"), EDIT_COPY_TRACKS);
edit->get_popup()->add_item(TTR("Paste Tracks"), EDIT_PASTE_TRACKS);
edit->get_popup()->add_separator();
edit->get_popup()->add_item(TTR("Scale Selection"), EDIT_SCALE_SELECTION);
edit->get_popup()->add_item(TTR("Scale From Cursor"), EDIT_SCALE_FROM_CURSOR);
edit->get_popup()->add_separator();
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_SELECTION);
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection_transposed", TTR("Duplicate Transposed"), KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_TRANSPOSED);
+ edit->get_popup()->add_item(TTR("Make Easing Selection"), EDIT_EASE_SELECTION);
+ edit->get_popup()->add_separator();
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::CMD_OR_CTRL | Key::D), EDIT_DUPLICATE_SELECTION);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection_transposed", TTR("Duplicate Transposed"), KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL | Key::D), EDIT_DUPLICATE_TRANSPOSED);
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/add_reset_value", TTR("Add RESET Value(s)")));
edit->get_popup()->add_separator();
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/delete_selection", TTR("Delete Selection"), Key::KEY_DELETE), EDIT_DELETE_SELECTION);
edit->get_popup()->add_separator();
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KeyModifierMask::CMD | Key::RIGHT), EDIT_GOTO_NEXT_STEP);
- edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KeyModifierMask::CMD | Key::LEFT), EDIT_GOTO_PREV_STEP);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KeyModifierMask::CMD_OR_CTRL | Key::RIGHT), EDIT_GOTO_NEXT_STEP);
+ edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KeyModifierMask::CMD_OR_CTRL | Key::LEFT), EDIT_GOTO_PREV_STEP);
edit->get_popup()->add_separator();
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET);
edit->get_popup()->add_separator();
- edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION);
- edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION);
+ edit->get_popup()->add_item(TTR("Bake Animation"), EDIT_BAKE_ANIMATION);
+ edit->get_popup()->add_item(TTR("Optimize Animation (no undo)"), EDIT_OPTIMIZE_ANIMATION);
+ edit->get_popup()->add_item(TTR("Clean-Up Animation (no undo)"), EDIT_CLEAN_UP_ANIMATION);
edit->get_popup()->connect("id_pressed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed));
edit->get_popup()->connect("about_to_popup", callable_mp(this, &AnimationTrackEditor::_edit_menu_about_to_popup));
@@ -6457,25 +6782,24 @@ AnimationTrackEditor::AnimationTrackEditor() {
VBoxContainer *optimize_vb = memnew(VBoxContainer);
optimize_dialog->add_child(optimize_vb);
- optimize_linear_error = memnew(SpinBox);
- optimize_linear_error->set_max(1.0);
- optimize_linear_error->set_min(0.001);
- optimize_linear_error->set_step(0.001);
- optimize_linear_error->set_value(0.05);
- optimize_vb->add_margin_child(TTR("Max. Linear Error:"), optimize_linear_error);
+ optimize_velocity_error = memnew(SpinBox);
+ optimize_velocity_error->set_max(1.0);
+ optimize_velocity_error->set_min(0.001);
+ optimize_velocity_error->set_step(0.001);
+ optimize_velocity_error->set_value(0.01);
+ optimize_vb->add_margin_child(TTR("Max. Velocity Error:"), optimize_velocity_error);
optimize_angular_error = memnew(SpinBox);
optimize_angular_error->set_max(1.0);
optimize_angular_error->set_min(0.001);
optimize_angular_error->set_step(0.001);
optimize_angular_error->set_value(0.01);
-
optimize_vb->add_margin_child(TTR("Max. Angular Error:"), optimize_angular_error);
- optimize_max_angle = memnew(SpinBox);
- optimize_vb->add_margin_child(TTR("Max Optimizable Angle:"), optimize_max_angle);
- optimize_max_angle->set_max(360.0);
- optimize_max_angle->set_min(0.0);
- optimize_max_angle->set_step(0.1);
- optimize_max_angle->set_value(22);
+ optimize_precision_error = memnew(SpinBox);
+ optimize_precision_error->set_max(6);
+ optimize_precision_error->set_min(1);
+ optimize_precision_error->set_step(1);
+ optimize_precision_error->set_value(3);
+ optimize_vb->add_margin_child(TTR("Max. Precision Error:"), optimize_precision_error);
optimize_dialog->set_ok_button_text(TTR("Optimize"));
optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_OPTIMIZE_ANIMATION_CONFIRM));
@@ -6519,6 +6843,88 @@ AnimationTrackEditor::AnimationTrackEditor() {
scale_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_SCALE_CONFIRM));
add_child(scale_dialog);
+ //
+ ease_dialog = memnew(ConfirmationDialog);
+ ease_dialog->set_title(TTR("Select Transition and Easing"));
+ ease_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_EASE_CONFIRM));
+ add_child(ease_dialog);
+ GridContainer *ease_grid = memnew(GridContainer);
+ ease_grid->set_columns(2);
+ ease_dialog->add_child(ease_grid);
+ transition_selection = memnew(OptionButton);
+ transition_selection->add_item("Linear", Tween::TRANS_LINEAR);
+ transition_selection->add_item("Sine", Tween::TRANS_SINE);
+ transition_selection->add_item("Quint", Tween::TRANS_QUINT);
+ transition_selection->add_item("Quart", Tween::TRANS_QUART);
+ transition_selection->add_item("Quad", Tween::TRANS_QUAD);
+ transition_selection->add_item("Expo", Tween::TRANS_EXPO);
+ transition_selection->add_item("Elastic", Tween::TRANS_ELASTIC);
+ transition_selection->add_item("Cubic", Tween::TRANS_CUBIC);
+ transition_selection->add_item("Circ", Tween::TRANS_CIRC);
+ transition_selection->add_item("Bounce", Tween::TRANS_BOUNCE);
+ transition_selection->add_item("Back", Tween::TRANS_BACK);
+ transition_selection->select(Tween::TRANS_LINEAR); // Default
+ ease_selection = memnew(OptionButton);
+ ease_selection->add_item("In", Tween::EASE_IN);
+ ease_selection->add_item("Out", Tween::EASE_OUT);
+ ease_selection->add_item("InOut", Tween::EASE_IN_OUT);
+ ease_selection->add_item("OutIn", Tween::EASE_OUT_IN);
+ ease_selection->select(Tween::EASE_IN_OUT); // Default
+ ease_fps = memnew(SpinBox);
+ ease_fps->set_min(1);
+ ease_fps->set_max(999);
+ ease_fps->set_step(1);
+ ease_fps->set_value(30); // Default
+ Label *ease_label1 = memnew(Label);
+ Label *ease_label2 = memnew(Label);
+ Label *ease_label3 = memnew(Label);
+ ease_label1->set_text("Transition Type:");
+ ease_label2->set_text("Ease Type:");
+ ease_label3->set_text("FPS:");
+ ease_grid->add_child(ease_label1);
+ ease_grid->add_child(transition_selection);
+ ease_grid->add_child(ease_label2);
+ ease_grid->add_child(ease_selection);
+ ease_grid->add_child(ease_label3);
+ ease_grid->add_child(ease_fps);
+
+ //
+ bake_dialog = memnew(ConfirmationDialog);
+ bake_dialog->set_title(TTR("Anim. Baker"));
+ bake_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_BAKE_ANIMATION_CONFIRM));
+ add_child(bake_dialog);
+ GridContainer *bake_grid = memnew(GridContainer);
+ bake_grid->set_columns(2);
+ bake_dialog->add_child(bake_grid);
+ bake_trs = memnew(CheckBox);
+ bake_trs->set_pressed(true);
+ bake_blendshape = memnew(CheckBox);
+ bake_blendshape->set_pressed(true);
+ bake_value = memnew(CheckBox);
+ bake_value->set_pressed(true);
+ bake_fps = memnew(SpinBox);
+ bake_fps->set_min(1);
+ bake_fps->set_max(999);
+ bake_fps->set_step(1);
+ bake_fps->set_value(30); // Default
+ Label *bake_label1 = memnew(Label);
+ Label *bake_label2 = memnew(Label);
+ Label *bake_label3 = memnew(Label);
+ Label *bake_label4 = memnew(Label);
+ bake_label1->set_text("Pos/Rot/Scl3D Track:");
+ bake_label2->set_text("Blendshape Track:");
+ bake_label3->set_text("Value Track:");
+ bake_label4->set_text("FPS:");
+ bake_grid->add_child(bake_label1);
+ bake_grid->add_child(bake_trs);
+ bake_grid->add_child(bake_label2);
+ bake_grid->add_child(bake_blendshape);
+ bake_grid->add_child(bake_label3);
+ bake_grid->add_child(bake_value);
+ bake_grid->add_child(bake_label4);
+ bake_grid->add_child(bake_fps);
+
+ //
track_copy_dialog = memnew(ConfirmationDialog);
add_child(track_copy_dialog);
track_copy_dialog->set_title(TTR("Select Tracks to Copy"));
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index cb7d3c7d96..ac69b88e99 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -32,6 +32,7 @@
#define ANIMATION_TRACK_EDITOR_H
#include "editor/editor_data.h"
+#include "editor/editor_properties.h"
#include "editor/editor_spin_slider.h"
#include "editor/property_selector.h"
@@ -56,6 +57,8 @@ class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range);
Ref<Animation> animation;
+ bool read_only = false;
+
AnimationTrackEdit *track_edit = nullptr;
int name_limit = 0;
Range *zoom = nullptr;
@@ -76,7 +79,7 @@ class AnimationTimelineEdit : public Range {
void _anim_loop_pressed();
void _play_position_draw();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Rect2 hsize_rect;
bool editing = false;
@@ -106,11 +109,11 @@ public:
float get_zoom_scale() const;
virtual Size2 get_minimum_size() const override;
- void set_animation(const Ref<Animation> &p_animation);
+ void set_animation(const Ref<Animation> &p_animation, bool p_read_only);
void set_track_edit(AnimationTrackEdit *p_track_edit);
void set_zoom(Range *p_zoom);
Range *get_zoom() const { return zoom; }
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_play_position(float p_pos);
float get_play_position() const;
@@ -141,6 +144,8 @@ class AnimationTrackEdit : public Control {
MENU_INTERPOLATION_NEAREST,
MENU_INTERPOLATION_LINEAR,
MENU_INTERPOLATION_CUBIC,
+ MENU_INTERPOLATION_LINEAR_ANGLE,
+ MENU_INTERPOLATION_CUBIC_ANGLE,
MENU_LOOP_WRAP,
MENU_LOOP_CLAMP,
MENU_KEY_INSERT,
@@ -150,7 +155,7 @@ class AnimationTrackEdit : public Control {
};
AnimationTimelineEdit *timeline = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Popup *path_popup = nullptr;
LineEdit *path = nullptr;
Node *root = nullptr;
@@ -159,6 +164,7 @@ class AnimationTrackEdit : public Control {
NodePath node_path;
Ref<Animation> animation;
+ bool read_only = false;
int track = 0;
Rect2 check_rect;
@@ -230,12 +236,12 @@ public:
Ref<Animation> get_animation() const;
AnimationTimelineEdit *get_timeline() const { return timeline; }
AnimationTrackEditor *get_editor() const { return editor; }
- UndoRedo *get_undo_redo() const { return undo_redo; }
+ Ref<EditorUndoRedoManager> get_undo_redo() const;
NodePath get_path() const;
- void set_animation_and_track(const Ref<Animation> &p_animation, int p_track);
+ void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only);
virtual Size2 get_minimum_size() const override;
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_timeline(AnimationTimelineEdit *p_timeline);
void set_editor(AnimationTrackEditor *p_editor);
void set_root(Node *p_root);
@@ -290,6 +296,7 @@ class AnimationTrackEditor : public VBoxContainer {
GDCLASS(AnimationTrackEditor, VBoxContainer);
Ref<Animation> animation;
+ bool read_only = false;
Node *root = nullptr;
MenuButton *edit = nullptr;
@@ -318,10 +325,13 @@ class AnimationTrackEditor : public VBoxContainer {
Vector<AnimationTrackEditGroup *> groups;
bool animation_changing_awaiting_update = false;
- void _animation_update();
+ void _animation_update(); // Updated by AnimationTrackEditor(this)
int _get_track_selected();
+ void _sync_animation_change();
void _animation_changed();
void _update_tracks();
+ void _redraw_tracks();
+ void _redraw_groups();
void _name_limit_changed();
void _timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only);
@@ -329,7 +339,7 @@ class AnimationTrackEditor : public VBoxContainer {
void _animation_track_remove_request(int p_track, Ref<Animation> p_from_animation);
void _track_grab_focus(int p_track);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _update_scroll(double);
void _update_step(double p_new_step);
@@ -443,13 +453,20 @@ class AnimationTrackEditor : public VBoxContainer {
void _toggle_bezier_edit();
void _cancel_bezier_edit();
void _bezier_edit(int p_for_track);
+ void _bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode = Animation::HANDLE_SET_MODE_NONE);
////////////// edit menu stuff
+ ConfirmationDialog *bake_dialog = nullptr;
+ CheckBox *bake_trs = nullptr;
+ CheckBox *bake_blendshape = nullptr;
+ CheckBox *bake_value = nullptr;
+ SpinBox *bake_fps = nullptr;
+
ConfirmationDialog *optimize_dialog = nullptr;
- SpinBox *optimize_linear_error = nullptr;
+ SpinBox *optimize_velocity_error = nullptr;
SpinBox *optimize_angular_error = nullptr;
- SpinBox *optimize_max_angle = nullptr;
+ SpinBox *optimize_precision_error = nullptr;
ConfirmationDialog *cleanup_dialog = nullptr;
CheckBox *cleanup_keys = nullptr;
@@ -459,6 +476,11 @@ class AnimationTrackEditor : public VBoxContainer {
ConfirmationDialog *scale_dialog = nullptr;
SpinBox *scale = nullptr;
+ ConfirmationDialog *ease_dialog = nullptr;
+ OptionButton *transition_selection = nullptr;
+ OptionButton *ease_selection = nullptr;
+ SpinBox *ease_fps = nullptr;
+
void _select_all_tracks_for_copy();
void _edit_menu_about_to_popup();
@@ -482,9 +504,9 @@ class AnimationTrackEditor : public VBoxContainer {
NodePath full_path;
NodePath base_path;
Animation::TrackType track_type = Animation::TYPE_ANIMATION;
- Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC;
+ Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_ANGLE;
Animation::UpdateMode update_mode = Animation::UPDATE_CAPTURE;
- Animation::LoopMode loop_mode = Animation::LOOP_LINEAR;
+ Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG;
bool loop_wrap = false;
bool enabled = false;
@@ -516,6 +538,8 @@ public:
EDIT_SCALE_SELECTION,
EDIT_SCALE_FROM_CURSOR,
EDIT_SCALE_CONFIRM,
+ EDIT_EASE_SELECTION,
+ EDIT_EASE_CONFIRM,
EDIT_DUPLICATE_SELECTION,
EDIT_DUPLICATE_TRANSPOSED,
EDIT_ADD_RESET_KEY,
@@ -524,6 +548,8 @@ public:
EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY, // Next step without updating animation.
EDIT_GOTO_PREV_STEP,
EDIT_APPLY_RESET,
+ EDIT_BAKE_ANIMATION,
+ EDIT_BAKE_ANIMATION_CONFIRM,
EDIT_OPTIMIZE_ANIMATION,
EDIT_OPTIMIZE_ANIMATION_CONFIRM,
EDIT_CLEAN_UP_ANIMATION,
@@ -533,7 +559,7 @@ public:
void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
- void set_animation(const Ref<Animation> &p_anim);
+ void set_animation(const Ref<Animation> &p_anim, bool p_read_only);
Ref<Animation> get_current_animation() const;
void set_root(Node *p_root);
Node *get_root() const;
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index cd40b53919..6499cf8df2 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -33,6 +33,7 @@
#include "editor/audio_stream_preview.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/animated_sprite_2d.h"
#include "scene/2d/sprite_2d.h"
#include "scene/3d/sprite_3d.h"
@@ -196,7 +197,7 @@ void AnimationTrackEditAudio::_preview_changed(ObjectID p_which) {
Ref<AudioStream> stream = object->call("get_stream");
if (stream.is_valid() && stream->get_instance_id() == p_which) {
- update();
+ queue_redraw();
}
}
@@ -798,7 +799,7 @@ void AnimationTrackEditTypeAudio::_preview_changed(ObjectID p_which) {
for (int i = 0; i < get_animation()->track_get_key_count(get_track()); i++) {
Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), i);
if (stream.is_valid() && stream->get_instance_id() == p_which) {
- update();
+ queue_redraw();
return;
}
}
@@ -1025,7 +1026,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
get_undo_redo()->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs);
get_undo_redo()->commit_action();
- update();
+ queue_redraw();
return;
}
}
@@ -1085,7 +1086,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
if (len_resizing && mm.is_valid()) {
len_resizing_rel += mm->get_relative().x;
len_resizing_start = mm->is_shift_pressed();
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -1096,7 +1097,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
len_resizing_start = mb->is_shift_pressed();
len_resizing_from_px = mb->get_position().x;
len_resizing_rel = 0;
- update();
+ queue_redraw();
accept_event();
return;
}
@@ -1119,7 +1120,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
}
len_resizing_index = -1;
- update();
+ queue_redraw();
accept_event();
return;
}
diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp
index 58527ee4d1..ab0e801c88 100644
--- a/editor/array_property_edit.cpp
+++ b/editor/array_property_edit.cpp
@@ -32,6 +32,7 @@
#include "core/io/marshalls.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#define ITEMS_PER_PAGE 100
@@ -87,7 +88,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Resize Array"));
ur->add_do_method(this, "_set_size", newsize);
ur->add_undo_method(this, "_set_size", size);
@@ -134,7 +135,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
Callable::CallError ce;
Variant new_value;
Variant::construct(Variant::Type(type), new_value, nullptr, 0, ce);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Array Value Type"));
ur->add_do_method(this, "_set_value", idx, new_value);
@@ -150,7 +151,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
Variant arr = get_array();
Variant value = arr.get(idx);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Array Value"));
ur->add_do_method(this, "_set_value", idx, p_value);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index b0eb384efc..11a6912aa5 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -800,7 +800,7 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->is_command_pressed()) {
+ if (mb->is_pressed() && mb->is_command_or_control_pressed()) {
if (mb->get_button_index() == MouseButton::WHEEL_UP) {
_zoom_in();
} else if (mb->get_button_index() == MouseButton::WHEEL_DOWN) {
@@ -1001,7 +1001,7 @@ void CodeTextEditor::update_editor_settings() {
// Appearance: Caret
text_editor->set_caret_type((TextEdit::CaretType)EditorSettings::get_singleton()->get("text_editor/appearance/caret/type").operator int());
text_editor->set_caret_blink_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink"));
- text_editor->set_caret_blink_speed(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink_speed"));
+ text_editor->set_caret_blink_interval(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink_interval"));
text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/appearance/caret/highlight_current_line"));
text_editor->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/appearance/caret/highlight_all_occurrences"));
@@ -1092,7 +1092,7 @@ void CodeTextEditor::trim_trailing_whitespace() {
if (trimed_whitespace) {
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1110,7 +1110,7 @@ void CodeTextEditor::insert_final_newline() {
text_editor->set_line(final_line, line);
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1154,7 +1154,7 @@ void CodeTextEditor::convert_indent_to_spaces() {
if (changed_indentation) {
text_editor->set_caret_column(cursor_column);
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1203,7 +1203,7 @@ void CodeTextEditor::convert_indent_to_tabs() {
if (changed_indentation) {
text_editor->set_caret_column(cursor_column);
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
}
@@ -1295,7 +1295,7 @@ void CodeTextEditor::move_lines_up() {
text_editor->set_caret_line(next_id);
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::move_lines_down() {
@@ -1341,7 +1341,7 @@ void CodeTextEditor::move_lines_down() {
text_editor->set_caret_line(next_id);
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::_delete_line(int p_line) {
@@ -1418,7 +1418,7 @@ void CodeTextEditor::duplicate_selection() {
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
@@ -1495,7 +1495,7 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
text_editor->set_caret_column(col);
}
text_editor->end_complex_operation();
- text_editor->update();
+ text_editor->queue_redraw();
}
void CodeTextEditor::goto_line(int p_line) {
@@ -1789,7 +1789,7 @@ void CodeTextEditor::toggle_bookmark() {
}
void CodeTextEditor::goto_next_bookmark() {
- Array bmarks = text_editor->get_bookmarked_lines();
+ PackedInt32Array bmarks = text_editor->get_bookmarked_lines();
if (bmarks.size() <= 0) {
return;
}
@@ -1813,7 +1813,7 @@ void CodeTextEditor::goto_next_bookmark() {
}
void CodeTextEditor::goto_prev_bookmark() {
- Array bmarks = text_editor->get_bookmarked_lines();
+ PackedInt32Array bmarks = text_editor->get_bookmarked_lines();
if (bmarks.size() <= 0) {
return;
}
@@ -1862,14 +1862,15 @@ void CodeTextEditor::update_toggle_scripts_button() {
} else {
toggle_scripts_button->set_icon(get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons")));
}
- toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
+ toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
}
CodeTextEditor::CodeTextEditor() {
code_complete_func = nullptr;
- ED_SHORTCUT("script_editor/zoom_in", TTR("Zoom In"), KeyModifierMask::CMD | Key::EQUAL);
- ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KeyModifierMask::CMD | Key::MINUS);
- ED_SHORTCUT("script_editor/reset_zoom", TTR("Reset Zoom"), KeyModifierMask::CMD | Key::KEY_0);
+ ED_SHORTCUT("script_editor/zoom_in", TTR("Zoom In"), KeyModifierMask::CMD_OR_CTRL | Key::EQUAL);
+ ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KeyModifierMask::CMD_OR_CTRL | Key::MINUS);
+ ED_SHORTCUT_ARRAY("script_editor/reset_zoom", TTR("Reset Zoom"),
+ { int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KEY_0), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KP_0) });
text_editor = memnew(CodeEdit);
add_child(text_editor);
@@ -1954,7 +1955,7 @@ CodeTextEditor::CodeTextEditor() {
error_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
error_button->set_default_cursor_shape(CURSOR_POINTING_HAND);
error_button->connect("pressed", callable_mp(this, &CodeTextEditor::_error_button_pressed));
- error_button->set_tooltip(TTR("Errors"));
+ error_button->set_tooltip_text(TTR("Errors"));
set_error_count(0);
// Warnings
@@ -1964,14 +1965,14 @@ CodeTextEditor::CodeTextEditor() {
warning_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
warning_button->set_default_cursor_shape(CURSOR_POINTING_HAND);
warning_button->connect("pressed", callable_mp(this, &CodeTextEditor::_warning_button_pressed));
- warning_button->set_tooltip(TTR("Warnings"));
+ warning_button->set_tooltip_text(TTR("Warnings"));
set_warning_count(0);
// Line and column
line_and_col_txt = memnew(Label);
status_bar->add_child(line_and_col_txt);
line_and_col_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
- line_and_col_txt->set_tooltip(TTR("Line and column numbers."));
+ line_and_col_txt->set_tooltip_text(TTR("Line and column numbers."));
line_and_col_txt->set_mouse_filter(MOUSE_FILTER_STOP);
text_editor->connect("gui_input", callable_mp(this, &CodeTextEditor::_text_editor_gui_input));
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 6fdd9563fb..861d05f17a 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -34,6 +34,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "plugins/script_editor_plugin.h"
@@ -288,8 +289,8 @@ bool ConnectDialog::get_deferred() const {
return deferred->is_pressed();
}
-bool ConnectDialog::get_oneshot() const {
- return oneshot->is_pressed();
+bool ConnectDialog::get_one_shot() const {
+ return one_shot->is_pressed();
}
/*
@@ -321,10 +322,10 @@ void ConnectDialog::init(ConnectionData p_cd, bool p_edit) {
_update_ok_enabled();
bool b_deferred = (p_cd.flags & CONNECT_DEFERRED) == CONNECT_DEFERRED;
- bool b_oneshot = (p_cd.flags & CONNECT_ONESHOT) == CONNECT_ONESHOT;
+ bool b_oneshot = (p_cd.flags & CONNECT_ONE_SHOT) == CONNECT_ONE_SHOT;
deferred->set_pressed(b_deferred);
- oneshot->set_pressed(b_oneshot);
+ one_shot->set_pressed(b_oneshot);
MethodInfo r_signal;
Ref<Script> source_script = source->get_script();
@@ -459,7 +460,7 @@ ConnectDialog::ConnectDialog() {
vbc_right->add_margin_child(TTR("Extra Call Arguments:"), bind_editor, true);
unbind_count = memnew(SpinBox);
- unbind_count->set_tooltip(TTR("Allows to drop arguments sent by signal emitter."));
+ unbind_count->set_tooltip_text(TTR("Allows to drop arguments sent by signal emitter."));
unbind_count->connect("value_changed", callable_mp(this, &ConnectDialog::_unbind_count_changed));
vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count);
@@ -480,14 +481,14 @@ ConnectDialog::ConnectDialog() {
deferred = memnew(CheckBox);
deferred->set_h_size_flags(0);
deferred->set_text(TTR("Deferred"));
- deferred->set_tooltip(TTR("Defers the signal, storing it in a queue and only firing it at idle time."));
+ deferred->set_tooltip_text(TTR("Defers the signal, storing it in a queue and only firing it at idle time."));
vbc_right->add_child(deferred);
- oneshot = memnew(CheckBox);
- oneshot->set_h_size_flags(0);
- oneshot->set_text(TTR("Oneshot"));
- oneshot->set_tooltip(TTR("Disconnects the signal after its first emission."));
- vbc_right->add_child(oneshot);
+ one_shot = memnew(CheckBox);
+ one_shot->set_h_size_flags(0);
+ one_shot->set_text(TTR("Oneshot"));
+ one_shot->set_tooltip_text(TTR("Disconnects the signal after its first emission."));
+ vbc_right->add_child(one_shot);
cdbinds = memnew(ConnectDialogBinds);
@@ -563,8 +564,8 @@ void ConnectionsDock::_make_or_edit_connection() {
cd.binds = connect_dialog->get_binds();
}
bool b_deferred = connect_dialog->get_deferred();
- bool b_oneshot = connect_dialog->get_oneshot();
- cd.flags = CONNECT_PERSIST | (b_deferred ? CONNECT_DEFERRED : 0) | (b_oneshot ? CONNECT_ONESHOT : 0);
+ bool b_oneshot = connect_dialog->get_one_shot();
+ cd.flags = CONNECT_PERSIST | (b_deferred ? CONNECT_DEFERRED : 0) | (b_oneshot ? CONNECT_ONE_SHOT : 0);
// Conditions to add function: must have a script and must not have the method already
// (in the class, the script itself, or inherited).
@@ -752,22 +753,12 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) {
}
Dictionary subst;
-
- String s = node_name.capitalize().replace(" ", "");
- subst["NodeName"] = s;
- if (!s.is_empty()) {
- s[0] = s.to_lower()[0];
- }
- subst["nodeName"] = s;
- subst["node_name"] = node_name.capitalize().replace(" ", "_").to_lower();
-
- s = signal_name.capitalize().replace(" ", "");
- subst["SignalName"] = s;
- if (!s.is_empty()) {
- s[0] = s.to_lower()[0];
- }
- subst["signalName"] = s;
- subst["signal_name"] = signal_name.capitalize().replace(" ", "_").to_lower();
+ subst["NodeName"] = node_name.to_pascal_case();
+ subst["nodeName"] = node_name.to_camel_case();
+ subst["node_name"] = node_name.to_snake_case();
+ subst["SignalName"] = signal_name.to_pascal_case();
+ subst["signalName"] = signal_name.to_camel_case();
+ subst["signal_name"] = signal_name.to_snake_case();
String dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst);
@@ -839,6 +830,9 @@ void ConnectionsDock::_handle_signal_menu_option(int p_option) {
disconnect_all_dialog->set_text(vformat(TTR("Are you sure you want to remove all connections from the \"%s\" signal?"), signal_name));
disconnect_all_dialog->popup_centered();
} break;
+ case COPY_NAME: {
+ DisplayServer::get_singleton()->clipboard_set(item->get_metadata(0).operator Dictionary()["name"]);
+ } break;
}
}
@@ -924,6 +918,10 @@ void ConnectionsDock::_bind_methods() {
ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree);
}
+void ConnectionsDock::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void ConnectionsDock::set_node(Node *p_node) {
selected_node = p_node;
update_tree();
@@ -1062,7 +1060,7 @@ void ConnectionsDock::update_tree() {
}
// "::" separators used in make_custom_tooltip for formatting.
- signal_item->set_tooltip(0, String(signal_name) + "::" + signaldesc + "::" + descr);
+ signal_item->set_tooltip_text(0, String(signal_name) + "::" + signaldesc + "::" + descr);
}
// List existing connections.
@@ -1085,8 +1083,8 @@ void ConnectionsDock::update_tree() {
if (cd.flags & CONNECT_DEFERRED) {
path += " (deferred)";
}
- if (cd.flags & CONNECT_ONESHOT) {
- path += " (oneshot)";
+ if (cd.flags & CONNECT_ONE_SHOT) {
+ path += " (one-shot)";
}
if (cd.unbinds > 0) {
path += " unbinds(" + itos(cd.unbinds) + ")";
@@ -1159,6 +1157,7 @@ ConnectionsDock::ConnectionsDock() {
signal_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_signal_menu_option));
signal_menu->add_item(TTR("Connect..."), CONNECT);
signal_menu->add_item(TTR("Disconnect All"), DISCONNECT_ALL);
+ signal_menu->add_item(TTR("Copy Name"), COPY_NAME);
slot_menu = memnew(PopupMenu);
add_child(slot_menu);
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index d141d1a880..e37246e7a0 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -31,7 +31,6 @@
#ifndef CONNECTIONS_DIALOG_H
#define CONNECTIONS_DIALOG_H
-#include "core/object/undo_redo.h"
#include "editor/editor_inspector.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/button.h"
@@ -48,6 +47,7 @@
#include "scene/gui/tree.h"
class ConnectDialogBinds;
+class EditorUndoRedoManager;
class ConnectDialog : public ConfirmationDialog {
GDCLASS(ConnectDialog, ConfirmationDialog);
@@ -121,7 +121,7 @@ private:
EditorInspector *bind_editor = nullptr;
OptionButton *type_list = nullptr;
CheckBox *deferred = nullptr;
- CheckBox *oneshot = nullptr;
+ CheckBox *one_shot = nullptr;
CheckButton *advanced = nullptr;
Vector<Control *> bind_controls;
@@ -153,7 +153,7 @@ public:
Vector<Variant> get_binds() const;
bool get_deferred() const;
- bool get_oneshot() const;
+ bool get_one_shot() const;
bool is_editing() const;
void init(ConnectionData p_cd, bool p_edit = false);
@@ -177,13 +177,14 @@ class ConnectionsDock : public VBoxContainer {
//Right-click Pop-up Menu Options.
enum SignalMenuOption {
CONNECT,
- DISCONNECT_ALL
+ DISCONNECT_ALL,
+ COPY_NAME,
};
enum SlotMenuOption {
EDIT,
GO_TO_SCRIPT,
- DISCONNECT
+ DISCONNECT,
};
Node *selected_node = nullptr;
@@ -194,7 +195,7 @@ class ConnectionsDock : public VBoxContainer {
Button *connect_button = nullptr;
PopupMenu *signal_menu = nullptr;
PopupMenu *slot_menu = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
LineEdit *search_box = nullptr;
HashMap<StringName, HashMap<StringName, String>> descr_cache;
@@ -225,7 +226,7 @@ protected:
static void _bind_methods();
public:
- void set_undoredo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_node(Node *p_node);
void update_tree();
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index e6168f4924..4ac32d7317 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -38,7 +38,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
-void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type) {
+void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_current_type, const String &p_current_name) {
_fill_type_list();
icon_fallback = search_options->has_theme_icon(base_type, SNAME("EditorIcons")) ? base_type : "Object";
@@ -50,14 +50,14 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const St
}
if (p_replace_mode) {
- search_box->set_text(p_select_type);
+ search_box->set_text(p_current_type);
}
search_box->grab_focus();
_update_search();
if (p_replace_mode) {
- set_title(vformat(TTR("Change %s Type"), base_type));
+ set_title(vformat(TTR("Change Type of \"%s\""), p_current_name));
set_ok_button_text(TTR("Change"));
} else {
set_title(vformat(TTR("Create New %s"), base_type));
@@ -309,7 +309,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String
}
const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description);
- r_item->set_tooltip(0, description);
+ r_item->set_tooltip_text(0, description);
if (p_type_category == TypeCategory::OTHER_TYPE && !script_type) {
Ref<Texture2D> icon = EditorNode::get_editor_data().get_custom_types()[custom_type_parents[p_type]][custom_type_indices[p_type]].icon;
@@ -379,7 +379,7 @@ void CreateDialog::_confirmed() {
}
{
- Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("create_recent." + base_type), FileAccess::WRITE);
if (f.is_valid()) {
f->store_line(selected_item);
@@ -656,12 +656,12 @@ void CreateDialog::_save_and_update_favorite_list() {
TreeItem *root = favorites->create_item();
{
- Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites." + base_type), FileAccess::WRITE);
if (f.is_valid()) {
for (int i = 0; i < favorite_list.size(); i++) {
String l = favorite_list[i];
String name = l.get_slicec(' ', 0);
- if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) {
+ if (!EditorNode::get_editor_data().is_type_recognized(name)) {
continue;
}
f->store_line(l);
@@ -682,19 +682,19 @@ void CreateDialog::_save_and_update_favorite_list() {
void CreateDialog::_load_favorites_and_history() {
String dir = EditorPaths::get_singleton()->get_project_settings_dir();
- Ref<FileAccess> f = FileAccess::open(dir.plus_file("create_recent." + base_type), FileAccess::READ);
+ Ref<FileAccess> f = FileAccess::open(dir.path_join("create_recent." + base_type), FileAccess::READ);
if (f.is_valid()) {
while (!f->eof_reached()) {
String l = f->get_line().strip_edges();
String name = l.get_slicec(' ', 0);
- if ((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name)) {
+ if (EditorNode::get_editor_data().is_type_recognized(name) && !_is_class_disabled_by_feature_profile(name)) {
recent->add_item(l, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
}
}
}
- f = FileAccess::open(dir.plus_file("favorites." + base_type), FileAccess::READ);
+ f = FileAccess::open(dir.path_join("favorites." + base_type), FileAccess::READ);
if (f.is_valid()) {
while (!f->eof_reached()) {
String l = f->get_line().strip_edges();
@@ -776,7 +776,7 @@ CreateDialog::CreateDialog() {
favorite = memnew(Button);
favorite->set_toggle_mode(true);
- favorite->set_tooltip(TTR("(Un)favorite selected item."));
+ favorite->set_tooltip_text(TTR("(Un)favorite selected item."));
favorite->connect("pressed", callable_mp(this, &CreateDialog::_favorite_toggled));
search_hb->add_child(favorite);
vbc->add_margin_child(TTR("Search:"), search_hb);
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index 04094108ad..f2e741624f 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -120,7 +120,7 @@ public:
void set_preferred_search_result_type(const String &p_preferred_type) { preferred_search_result_type = p_preferred_type; }
String get_preferred_search_result_type() { return preferred_search_result_type; }
- void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node");
+ void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_current_type = "", const String &p_current_name = "");
CreateDialog();
};
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index 3c3e4faa6f..ac41306cde 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -201,7 +201,7 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const {
}
} else if (platform_string == "web") {
for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
- if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "HTML5") {
+ if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "Web") {
idx = i;
break;
}
diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp
index 58206efc20..6c0ba55ec8 100644
--- a/editor/debugger/editor_debugger_inspector.cpp
+++ b/editor/debugger/editor_debugger_inspector.cpp
@@ -85,6 +85,7 @@ void EditorDebuggerRemoteObject::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_variant"), &EditorDebuggerRemoteObject::get_variant);
ClassDB::bind_method(D_METHOD("clear"), &EditorDebuggerRemoteObject::clear);
ClassDB::bind_method(D_METHOD("get_remote_object_id"), &EditorDebuggerRemoteObject::get_remote_object_id);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &EditorDebuggerRemoteObject::_is_read_only);
ADD_SIGNAL(MethodInfo("value_edited", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
}
diff --git a/editor/debugger/editor_debugger_inspector.h b/editor/debugger/editor_debugger_inspector.h
index 5aac4dbf11..c595e0acaa 100644
--- a/editor/debugger/editor_debugger_inspector.h
+++ b/editor/debugger/editor_debugger_inspector.h
@@ -50,6 +50,7 @@ public:
HashMap<StringName, Variant> prop_values;
ObjectID get_remote_object_id() { return remote_object_id; };
+ bool _is_read_only() { return true; };
String get_title();
Variant get_variant(const StringName &p_name);
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 472e53c0e8..9fd7fa578f 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -30,6 +30,7 @@
#include "editor_debugger_node.h"
+#include "core/object/undo_redo.h"
#include "editor/debugger/editor_debugger_tree.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_log.h"
@@ -83,8 +84,6 @@ EditorDebuggerNode::EditorDebuggerNode() {
inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2);
EditorNode *editor = EditorNode::get_singleton();
- editor->get_undo_redo()->set_method_notify_callback(_method_changeds, this);
- editor->get_undo_redo()->set_property_notify_callback(_property_changeds, this);
editor->get_pause_button()->connect("pressed", callable_mp(this, &EditorDebuggerNode::_paused));
}
@@ -181,6 +180,11 @@ void EditorDebuggerNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled")));
}
+void EditorDebuggerNode::register_undo_redo(UndoRedo *p_undo_redo) {
+ p_undo_redo->set_method_notify_callback(_method_changeds, this);
+ p_undo_redo->set_property_notify_callback(_property_changeds, this);
+}
+
EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() {
return Object::cast_to<EditorDebuggerRemoteObject>(ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_current()));
}
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index 4c9ad49ac4..e79e60b180 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -41,6 +41,7 @@ class EditorDebuggerRemoteObject;
class MenuButton;
class ScriptEditorDebugger;
class TabContainer;
+class UndoRedo;
class EditorDebuggerNode : public MarginContainer {
GDCLASS(EditorDebuggerNode, MarginContainer);
@@ -152,6 +153,7 @@ protected:
public:
static EditorDebuggerNode *get_singleton() { return singleton; }
+ void register_undo_redo(UndoRedo *p_undo_redo);
ScriptEditorDebugger *get_current_debugger() const;
ScriptEditorDebugger *get_default_debugger() const;
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index dbd2c61d44..76efcd7190 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -155,7 +155,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
const SceneDebuggerTree::RemoteNode &node = p_tree->nodes[i];
TreeItem *item = create_item(parent);
item->set_text(0, node.name);
- item->set_tooltip(0, TTR("Type:") + " " + node.type_name);
+ item->set_tooltip_text(0, TTR("Type:") + " " + node.type_name);
Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(node.type_name, "");
if (icon.is_valid()) {
item->set_icon(0, icon);
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index 55d025f675..10b50a81e4 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -61,7 +61,7 @@ void EditorPerformanceProfiler::Monitor::update_value(float p_value) {
} break;
}
item->set_text(1, label);
- item->set_tooltip(1, tooltip);
+ item->set_tooltip_text(1, tooltip);
if (p_value > max) {
max = p_value;
@@ -73,7 +73,7 @@ void EditorPerformanceProfiler::Monitor::reset() {
max = 0.0f;
if (item) {
item->set_text(1, "");
- item->set_tooltip(1, "");
+ item->set_tooltip_text(1, "");
}
}
@@ -92,7 +92,7 @@ String EditorPerformanceProfiler::_create_label(float p_value, Performance::Moni
}
void EditorPerformanceProfiler::_monitor_select() {
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
void EditorPerformanceProfiler::_monitor_draw() {
@@ -283,12 +283,12 @@ void EditorPerformanceProfiler::_marker_input(const Ref<InputEvent> &p_event) {
float spacing = float(point_sep) / float(columns);
marker_frame = (rect.size.x - point.x) / spacing;
}
- monitor_draw->update();
+ monitor_draw->queue_redraw();
return;
}
}
marker_key = "";
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
}
@@ -308,7 +308,7 @@ void EditorPerformanceProfiler::reset() {
_build_monitor_tree();
marker_key = "";
marker_frame = 0;
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
void EditorPerformanceProfiler::update_monitors(const Vector<StringName> &p_names) {
@@ -357,7 +357,7 @@ void EditorPerformanceProfiler::add_profile_frame(const Vector<float> &p_values)
E.value.update_value(data);
}
marker_frame++;
- monitor_draw->update();
+ monitor_draw->queue_redraw();
}
List<float> *EditorPerformanceProfiler::get_monitor_data(const StringName &p_name) {
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 28b5d4be15..cf48366bd3 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -318,7 +318,7 @@ void EditorProfiler::_update_plot() {
graph_texture->update(img);
graph->set_texture(graph_texture);
- graph->update();
+ graph->queue_redraw();
}
void EditorProfiler::_update_frame() {
@@ -356,7 +356,7 @@ void EditorProfiler::_update_frame() {
item->set_metadata(1, it.script);
item->set_metadata(2, it.line);
item->set_text_alignment(2, HORIZONTAL_ALIGNMENT_RIGHT);
- item->set_tooltip(0, it.name + "\n" + it.script + ":" + itos(it.line));
+ item->set_tooltip_text(0, it.name + "\n" + it.script + ":" + itos(it.line));
float time = dtime == DISPLAY_SELF_TIME ? it.self : it.total;
@@ -421,7 +421,7 @@ void EditorProfiler::_graph_tex_draw() {
void EditorProfiler::_graph_tex_mouse_exit() {
hover_metric = -1;
- graph->update();
+ graph->queue_redraw();
}
void EditorProfiler::_cursor_metric_changed(double) {
@@ -429,7 +429,7 @@ void EditorProfiler::_cursor_metric_changed(double) {
return;
}
- graph->update();
+ graph->queue_redraw();
_update_frame();
}
@@ -480,13 +480,13 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
}
}
- graph->update();
+ graph->queue_redraw();
}
}
void EditorProfiler::disable_seeking() {
seeking = false;
- graph->update();
+ graph->queue_redraw();
}
void EditorProfiler::_combo_changed(int) {
@@ -607,7 +607,7 @@ EditorProfiler::EditorProfiler() {
display_time = memnew(OptionButton);
display_time->add_item(TTR("Inclusive"));
display_time->add_item(TTR("Self"));
- display_time->set_tooltip(TTR("Inclusive: Includes time from other functions called by this function.\nUse this to spot bottlenecks.\n\nSelf: Only count the time spent in the function itself, not in other functions called by that function.\nUse this to find individual functions to optimize."));
+ display_time->set_tooltip_text(TTR("Inclusive: Includes time from other functions called by this function.\nUse this to spot bottlenecks.\n\nSelf: Only count the time spent in the function itself, not in other functions called by that function.\nUse this to find individual functions to optimize."));
display_time->connect("item_selected", callable_mp(this, &EditorProfiler::_combo_changed));
hb->add_child(display_time);
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index 6f3dd1793c..8e7135f1c5 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -312,7 +312,7 @@ void EditorVisualProfiler::_update_plot() {
graph_texture->update(img);
graph->set_texture(graph_texture);
- graph->update();
+ graph->queue_redraw();
}
void EditorVisualProfiler::_update_frame(bool p_focus_selected) {
@@ -489,7 +489,7 @@ void EditorVisualProfiler::_graph_tex_draw() {
void EditorVisualProfiler::_graph_tex_mouse_exit() {
hover_metric = -1;
- graph->update();
+ graph->queue_redraw();
}
void EditorVisualProfiler::_cursor_metric_changed(double) {
@@ -497,7 +497,7 @@ void EditorVisualProfiler::_cursor_metric_changed(double) {
return;
}
- graph->update();
+ graph->queue_redraw();
_update_frame();
}
@@ -613,7 +613,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
}
}
- graph->update();
+ graph->queue_redraw();
}
}
@@ -637,7 +637,7 @@ int EditorVisualProfiler::_get_cursor_index() const {
void EditorVisualProfiler::disable_seeking() {
seeking = false;
- graph->update();
+ graph->queue_redraw();
}
void EditorVisualProfiler::_combo_changed(int) {
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index ac2e958c5b..5baa9970af 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -369,7 +369,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
}
}
- vmem_total->set_tooltip(TTR("Bytes:") + " " + itos(total));
+ vmem_total->set_tooltip_text(TTR("Bytes:") + " " + itos(total));
vmem_total->set_text(String::humanize_size(total));
} else if (p_msg == "stack_dump") {
@@ -580,8 +580,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
stack_trace->set_text(1, frame_txt);
}
- error->set_tooltip(0, tooltip);
- error->set_tooltip(1, tooltip);
+ error->set_tooltip_text(0, tooltip);
+ error->set_tooltip_text(1, tooltip);
if (warning_count == 0 && error_count == 0) {
expand_all_button->set_disabled(false);
@@ -776,7 +776,7 @@ void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType
reason->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
}
reason->set_text(p_reason);
- reason->set_tooltip(p_reason.word_wrap(80));
+ reason->set_tooltip_text(p_reason.word_wrap(80));
}
void ScriptEditorDebugger::_notification(int p_what) {
@@ -964,7 +964,7 @@ void ScriptEditorDebugger::stop() {
peer->close();
peer.unref();
reason->set_text("");
- reason->set_tooltip("");
+ reason->set_tooltip_text("");
}
node_path_cache.clear();
@@ -1706,7 +1706,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
skip_breakpoints = memnew(Button);
skip_breakpoints->set_flat(true);
hbc->add_child(skip_breakpoints);
- skip_breakpoints->set_tooltip(TTR("Skip Breakpoints"));
+ skip_breakpoints->set_tooltip_text(TTR("Skip Breakpoints"));
skip_breakpoints->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_skip_breakpoints));
hbc->add_child(memnew(VSeparator));
@@ -1714,7 +1714,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
copy = memnew(Button);
copy->set_flat(true);
hbc->add_child(copy);
- copy->set_tooltip(TTR("Copy Error"));
+ copy->set_tooltip_text(TTR("Copy Error"));
copy->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_copy));
hbc->add_child(memnew(VSeparator));
@@ -1722,14 +1722,14 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
step = memnew(Button);
step->set_flat(true);
hbc->add_child(step);
- step->set_tooltip(TTR("Step Into"));
+ step->set_tooltip_text(TTR("Step Into"));
step->set_shortcut(ED_GET_SHORTCUT("debugger/step_into"));
step->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_step));
next = memnew(Button);
next->set_flat(true);
hbc->add_child(next);
- next->set_tooltip(TTR("Step Over"));
+ next->set_tooltip_text(TTR("Step Over"));
next->set_shortcut(ED_GET_SHORTCUT("debugger/step_over"));
next->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_next));
@@ -1738,14 +1738,14 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
dobreak = memnew(Button);
dobreak->set_flat(true);
hbc->add_child(dobreak);
- dobreak->set_tooltip(TTR("Break"));
+ dobreak->set_tooltip_text(TTR("Break"));
dobreak->set_shortcut(ED_GET_SHORTCUT("debugger/break"));
dobreak->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_break));
docontinue = memnew(Button);
docontinue->set_flat(true);
hbc->add_child(docontinue);
- docontinue->set_tooltip(TTR("Continue"));
+ docontinue->set_tooltip_text(TTR("Continue"));
docontinue->set_shortcut(ED_GET_SHORTCUT("debugger/continue"));
docontinue->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_continue));
@@ -1917,7 +1917,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
vmem_hb->add_child(vmem_refresh);
vmem_export = memnew(Button);
vmem_export->set_flat(true);
- vmem_export->set_tooltip(TTR("Export list to a CSV file"));
+ vmem_export->set_tooltip_text(TTR("Export list to a CSV file"));
vmem_hb->add_child(vmem_export);
vmem_vb->add_child(vmem_hb);
vmem_refresh->connect("pressed", callable_mp(this, &ScriptEditorDebugger::_video_mem_request));
@@ -1959,15 +1959,18 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
info_left->set_columns(2);
misc->add_child(info_left);
clicked_ctrl = memnew(LineEdit);
+ clicked_ctrl->set_editable(false);
clicked_ctrl->set_h_size_flags(SIZE_EXPAND_FILL);
info_left->add_child(memnew(Label(TTR("Clicked Control:"))));
info_left->add_child(clicked_ctrl);
clicked_ctrl_type = memnew(LineEdit);
+ clicked_ctrl_type->set_editable(false);
info_left->add_child(memnew(Label(TTR("Clicked Control Type:"))));
info_left->add_child(clicked_ctrl_type);
scene_tree = memnew(SceneDebuggerTree);
live_edit_root = memnew(LineEdit);
+ live_edit_root->set_editable(false);
live_edit_root->set_h_size_flags(SIZE_EXPAND_FILL);
{
diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp
index 630265e268..f16c5402ad 100644
--- a/editor/dictionary_property_edit.cpp
+++ b/editor/dictionary_property_edit.cpp
@@ -30,6 +30,7 @@
#include "dictionary_property_edit.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
void DictionaryPropertyEdit::_notif_change() {
notify_property_list_changed();
@@ -118,7 +119,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
int index = pn.substr(0, slash).to_int();
if (type == "key" && index < keys.size()) {
const Variant &key = keys[index];
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Dictionary Key"));
ur->add_do_method(this, "_set_key", key, p_value);
@@ -130,7 +131,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
const Variant &key = keys[index];
if (dict.has(key)) {
Variant value = dict[key];
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Dictionary Value"));
ur->add_do_method(this, "_set_value", key, p_value);
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 864871bb7e..ec9a744e57 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -41,6 +41,7 @@
#include "core/version.h"
#include "editor/editor_settings.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
// Used for a hack preserving Mono properties on non-Mono builds.
#include "modules/modules_enabled.gen.h" // For mono.
@@ -567,29 +568,29 @@ void DocTools::generate(bool p_basic_types) {
{
List<StringName> l;
- Theme::get_default()->get_color_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
tid.type = "Color";
tid.data_type = "color";
- tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string().replace("\n", " ");
+ tid.default_value = Variant(ThemeDB::get_singleton()->get_default_theme()->get_color(E, cname)).get_construct_string().replace("\n", " ");
c.theme_properties.push_back(tid);
}
l.clear();
- Theme::get_default()->get_constant_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
tid.type = "int";
tid.data_type = "constant";
- tid.default_value = itos(Theme::get_default()->get_constant(E, cname));
+ tid.default_value = itos(ThemeDB::get_singleton()->get_default_theme()->get_constant(E, cname));
c.theme_properties.push_back(tid);
}
l.clear();
- Theme::get_default()->get_font_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -599,7 +600,7 @@ void DocTools::generate(bool p_basic_types) {
}
l.clear();
- Theme::get_default()->get_font_size_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -609,7 +610,7 @@ void DocTools::generate(bool p_basic_types) {
}
l.clear();
- Theme::get_default()->get_icon_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_icon_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -619,7 +620,7 @@ void DocTools::generate(bool p_basic_types) {
}
l.clear();
- Theme::get_default()->get_stylebox_list(cname, &l);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(cname, &l);
for (const StringName &E : l) {
DocData::ThemeItemDoc tid;
tid.name = E;
@@ -1070,7 +1071,7 @@ Error DocTools::load_classes(const String &p_dir) {
while (!path.is_empty()) {
if (!da->current_is_dir() && path.ends_with("xml")) {
Ref<XMLParser> parser = memnew(XMLParser);
- Error err2 = parser->open(p_dir.plus_file(path));
+ Error err2 = parser->open(p_dir.path_join(path));
if (err2) {
return err2;
}
@@ -1379,7 +1380,7 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
}
Error err;
- String save_file = save_path.plus_file(c.name + ".xml");
+ String save_file = save_path.path_join(c.name + ".xml");
Ref<FileAccess> f = FileAccess::open(save_file, FileAccess::WRITE, &err);
ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + ".");
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 17aa67cd45..7baaffb1be 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -147,7 +147,7 @@ EditorAbout::EditorAbout() {
// Set the text to copy in metadata as it slightly differs from the button's text.
version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash);
version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
- version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->set_tooltip_text(TTR("Click to copy."));
version_btn->connect("pressed", callable_mp(this, &EditorAbout::_version_button_pressed));
version_info_vbc->add_child(version_btn);
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index 8dc8a0ab6b..aaa5956c17 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -215,11 +215,11 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
if (FileAccess::exists(res_path)) {
num_file_conflicts += 1;
ti->set_custom_color(0, tree->get_theme_color(SNAME("error_color"), SNAME("Editor")));
- ti->set_tooltip(0, vformat(TTR("%s (already exists)"), res_path));
+ ti->set_tooltip_text(0, vformat(TTR("%s (already exists)"), res_path));
ti->set_checked(0, false);
ti->propagate_check(0);
} else {
- ti->set_tooltip(0, res_path);
+ ti->set_tooltip_text(0, res_path);
}
ti->set_metadata(0, res_path);
diff --git a/editor/editor_atlas_packer.cpp b/editor/editor_atlas_packer.cpp
index 9c6bcd769a..7f4bd8cc89 100644
--- a/editor/editor_atlas_packer.cpp
+++ b/editor/editor_atlas_packer.cpp
@@ -81,7 +81,7 @@ void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_h
int l = k == 0 ? 2 : k - 1;
Vector<Point2i> points = Geometry2D::bresenham_line(v[k], v[l]);
for (Point2i point : points) {
- src_bitmap->set_bit(point, true);
+ src_bitmap->set_bitv(point, true);
}
}
}
@@ -128,7 +128,7 @@ void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_h
continue;
}
- if (src_bitmap->get_bit(Vector2(px, py))) {
+ if (src_bitmap->get_bit(px, py)) {
found_pixel = true;
}
}
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index b6d7bbc45f..09dce869c9 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "filesystem_dock.h"
#include "scene/resources/font.h"
#include "servers/audio_server.h"
@@ -181,7 +182,7 @@ void EditorAudioBus::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -280,7 +281,7 @@ void EditorAudioBus::_name_changed(const String &p_new_name) {
}
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
StringName current = AudioServer::get_singleton()->get_bus_name(get_index());
ur->create_action(TTR("Rename Audio Bus"));
@@ -321,7 +322,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) {
slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index()));
@@ -394,7 +395,7 @@ void EditorAudioBus::_show_value(float slider_value) {
// Also set the preview text as a standard Control tooltip.
// This way, it can be seen when the slider is merely hovered (instead of dragged).
- slider->set_tooltip(text);
+ slider->set_tooltip_text(text);
audio_value_preview_label->set_text(text);
const Vector2 slider_size = slider->get_size();
const Vector2 slider_position = slider->get_global_position();
@@ -415,7 +416,7 @@ void EditorAudioBus::_hide_value_preview() {
void EditorAudioBus::_solo_toggled() {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Toggle Audio Bus Solo"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index()));
@@ -429,7 +430,7 @@ void EditorAudioBus::_solo_toggled() {
void EditorAudioBus::_mute_toggled() {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Toggle Audio Bus Mute"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index()));
@@ -443,7 +444,7 @@ void EditorAudioBus::_mute_toggled() {
void EditorAudioBus::_bypass_toggled() {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Toggle Audio Bus Bypass Effects"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));
@@ -457,7 +458,7 @@ void EditorAudioBus::_bypass_toggled() {
void EditorAudioBus::_send_selected(int p_which) {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index()));
@@ -507,7 +508,7 @@ void EditorAudioBus::_effect_edited() {
int index = effect->get_metadata(0);
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));
@@ -534,7 +535,7 @@ void EditorAudioBus::_effect_add(int p_which) {
afxr->set_name(effect_options->get_item_text(p_which));
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Audio Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1);
ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index()));
@@ -688,7 +689,7 @@ void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data,
bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Move Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect);
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at);
@@ -730,7 +731,7 @@ void EditorAudioBus::_delete_effect_pressed(int p_option) {
int index = item->get_metadata(0);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Delete Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index);
ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index);
@@ -778,7 +779,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
buses = p_buses;
is_master = p_is_master;
- set_tooltip(TTR("Drag & drop to rearrange."));
+ set_tooltip_text(TTR("Drag & drop to rearrange."));
VBoxContainer *vb = memnew(VBoxContainer);
add_child(vb);
@@ -795,21 +796,21 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
solo = memnew(Button);
solo->set_flat(true);
solo->set_toggle_mode(true);
- solo->set_tooltip(TTR("Solo"));
+ solo->set_tooltip_text(TTR("Solo"));
solo->set_focus_mode(FOCUS_NONE);
solo->connect("pressed", callable_mp(this, &EditorAudioBus::_solo_toggled));
hbc->add_child(solo);
mute = memnew(Button);
mute->set_flat(true);
mute->set_toggle_mode(true);
- mute->set_tooltip(TTR("Mute"));
+ mute->set_tooltip_text(TTR("Mute"));
mute->set_focus_mode(FOCUS_NONE);
mute->connect("pressed", callable_mp(this, &EditorAudioBus::_mute_toggled));
hbc->add_child(mute);
bypass = memnew(Button);
bypass->set_flat(true);
bypass->set_toggle_mode(true);
- bypass->set_tooltip(TTR("Bypass"));
+ bypass->set_tooltip_text(TTR("Bypass"));
bypass->set_focus_mode(FOCUS_NONE);
bypass->connect("pressed", callable_mp(this, &EditorAudioBus::_bypass_toggled));
hbc->add_child(bypass);
@@ -935,11 +936,11 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
bus_options->set_shortcut_context(this);
bus_options->set_h_size_flags(SIZE_SHRINK_END);
bus_options->set_anchor(SIDE_RIGHT, 0.0);
- bus_options->set_tooltip(TTR("Bus Options"));
+ bus_options->set_tooltip_text(TTR("Bus Options"));
hbc->add_child(bus_options);
bus_popup = bus_options->get_popup();
- bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/duplicate_selected_bus", TTR("Duplicate Bus"), KeyModifierMask::CMD | Key::D));
+ bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/duplicate_selected_bus", TTR("Duplicate Bus"), KeyModifierMask::CMD_OR_CTRL | Key::D));
bus_popup->add_shortcut(ED_SHORTCUT("audio_bus_editor/delete_selected_bus", TTR("Delete Bus"), Key::KEY_DELETE));
bus_popup->set_item_disabled(1, is_master);
bus_popup->add_item(TTR("Reset Volume"));
@@ -966,7 +967,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER: {
if (!hovering_drop) {
hovering_drop = true;
- update();
+ queue_redraw();
}
} break;
@@ -974,7 +975,7 @@ void EditorAudioBusDrop::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (hovering_drop) {
hovering_drop = false;
- update();
+ queue_redraw();
}
} break;
}
@@ -1026,7 +1027,7 @@ void EditorAudioBuses::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- bus_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ bus_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_READY: {
@@ -1063,7 +1064,7 @@ void EditorAudioBuses::_notification(int p_what) {
}
void EditorAudioBuses::_add_bus() {
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);
@@ -1095,7 +1096,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
return;
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Delete Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index);
@@ -1117,7 +1118,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
void EditorAudioBuses::_duplicate_bus(int p_which) {
int add_at_pos = p_which + 1;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Duplicate Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy");
@@ -1140,7 +1141,7 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) {
EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);
int index = bus->get_index();
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Reset Bus Volume"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));
@@ -1160,7 +1161,7 @@ void EditorAudioBuses::_request_drop_end() {
}
void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Move Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index);
@@ -1219,7 +1220,7 @@ void EditorAudioBuses::_load_default_layout() {
file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
@@ -1235,7 +1236,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
} else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
@@ -1255,7 +1256,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
edited_path = p_string;
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
}
@@ -1281,7 +1282,7 @@ EditorAudioBuses::EditorAudioBuses() {
add = memnew(Button);
top_hb->add_child(add);
add->set_text(TTR("Add Bus"));
- add->set_tooltip(TTR("Add a new Audio Bus to this layout."));
+ add->set_tooltip_text(TTR("Add a new Audio Bus to this layout."));
add->connect("pressed", callable_mp(this, &EditorAudioBuses::_add_bus));
VSeparator *separator = memnew(VSeparator);
@@ -1289,25 +1290,25 @@ EditorAudioBuses::EditorAudioBuses() {
load = memnew(Button);
load->set_text(TTR("Load"));
- load->set_tooltip(TTR("Load an existing Bus Layout."));
+ load->set_tooltip_text(TTR("Load an existing Bus Layout."));
top_hb->add_child(load);
load->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_layout));
save_as = memnew(Button);
save_as->set_text(TTR("Save As"));
- save_as->set_tooltip(TTR("Save this Bus Layout to a file."));
+ save_as->set_tooltip_text(TTR("Save this Bus Layout to a file."));
top_hb->add_child(save_as);
save_as->connect("pressed", callable_mp(this, &EditorAudioBuses::_save_as_layout));
_default = memnew(Button);
_default->set_text(TTR("Load Default"));
- _default->set_tooltip(TTR("Load the default Bus Layout."));
+ _default->set_tooltip_text(TTR("Load the default Bus Layout."));
top_hb->add_child(_default);
_default->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_default_layout));
_new = memnew(Button);
_new->set_text(TTR("Create"));
- _new->set_tooltip(TTR("Create a new Bus Layout."));
+ _new->set_tooltip_text(TTR("Create a new Bus Layout."));
top_hb->add_child(_new);
_new->connect("pressed", callable_mp(this, &EditorAudioBuses::_new_layout));
@@ -1354,7 +1355,7 @@ void EditorAudioBuses::open_layout(const String &p_path) {
file->set_text(p_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index ee4955d0a0..544b6c7141 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/filesystem_dock.h"
#include "project_settings_editor.h"
#include "scene/main/window.h"
@@ -163,7 +164,7 @@ void EditorAutoloadSettings::_autoload_add() {
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- dialog->config("Node", fpath.plus_file(vformat("%s.gd", autoload_add_name->get_text().camelcase_to_underscore())), false, false);
+ dialog->config("Node", fpath.path_join(vformat("%s.gd", autoload_add_name->get_text().to_snake_case())), false, false);
dialog->popup_centered();
} else {
if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text())) {
@@ -193,7 +194,7 @@ void EditorAutoloadSettings::_autoload_edited() {
TreeItem *ti = tree->get_edited();
int column = tree->get_edited_column();
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
if (column == 0) {
String name = ti->get_text(0);
@@ -288,7 +289,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu
String name = "autoload/" + ti->get_text(0);
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
switch (p_button) {
case BUTTON_OPEN: {
@@ -370,7 +371,7 @@ void EditorAutoloadSettings::_autoload_open(const String &fpath) {
void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) {
// Convert the file name to PascalCase, which is the convention for classes in GDScript.
- const String class_name = p_path.get_file().get_basename().capitalize().replace(" ", "");
+ const String class_name = p_path.get_file().get_basename().to_pascal_case();
// If the name collides with a built-in class, prefix the name to make it possible to add without having to edit the name.
// The prefix is subjective, but it provides better UX than leaving the Add button disabled :)
@@ -579,7 +580,7 @@ void EditorAutoloadSettings::_script_created(Ref<Script> p_script) {
FileSystemDock::get_singleton()->get_script_create_dialog()->hide();
path = p_script->get_path().get_base_dir();
autoload_add_path->set_text(p_script->get_path());
- autoload_add_name->set_text(p_script->get_path().get_file().get_basename().capitalize().replace(" ", ""));
+ autoload_add_name->set_text(p_script->get_path().get_file().get_basename().to_pascal_case());
_autoload_add();
}
@@ -713,7 +714,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant &
orders.sort();
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Rearrange Autoloads"));
@@ -757,7 +758,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
name = "autoload/" + name;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Add Autoload"));
// Singleton autoloads are represented with a leading "*" in their path.
@@ -783,7 +784,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
void EditorAutoloadSettings::autoload_remove(const String &p_name) {
String name = "autoload/" + p_name;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
int order = ProjectSettings::get_singleton()->get_order(name);
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 2d4945db14..d1ea0f2814 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -35,6 +35,7 @@
#include "core/io/resource_loader.h"
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/script_editor_plugin.h"
#include "scene/resources/packed_scene.h"
@@ -364,13 +365,13 @@ void EditorData::restore_editor_global_states() {
void EditorData::paste_object_params(Object *p_object) {
ERR_FAIL_NULL(p_object);
- undo_redo.create_action(TTR("Paste Params"));
+ undo_redo_manager->create_action(TTR("Paste Params"));
for (const PropertyData &E : clipboard) {
String name = E.name;
- undo_redo.add_do_property(p_object, name, E.value);
- undo_redo.add_undo_property(p_object, name, p_object->get(name));
+ undo_redo_manager->add_do_property(p_object, name, E.value);
+ undo_redo_manager->add_undo_property(p_object, name, p_object->get(name));
}
- undo_redo.commit_action();
+ undo_redo_manager->commit_action();
}
bool EditorData::call_build() {
@@ -383,8 +384,49 @@ bool EditorData::call_build() {
return result;
}
-UndoRedo &EditorData::get_undo_redo() {
- return undo_redo;
+void EditorData::set_scene_as_saved(int p_idx) {
+ if (p_idx == -1) {
+ p_idx = current_edited_scene;
+ }
+ ERR_FAIL_INDEX(p_idx, edited_scene.size());
+
+ get_undo_redo()->set_history_as_saved(edited_scene[p_idx].history_id);
+}
+
+bool EditorData::is_scene_changed(int p_idx) {
+ if (p_idx == -1) {
+ p_idx = current_edited_scene;
+ }
+ ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), false);
+
+ uint64_t current_scene_version = get_undo_redo()->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version();
+ bool is_changed = edited_scene[p_idx].last_checked_version != current_scene_version;
+ edited_scene.write[p_idx].last_checked_version = current_scene_version;
+ return is_changed;
+}
+
+int EditorData::get_scene_history_id_from_path(const String &p_path) const {
+ for (const EditedScene &E : edited_scene) {
+ if (E.path == p_path) {
+ return E.history_id;
+ }
+ }
+ return 0;
+}
+
+int EditorData::get_current_edited_scene_history_id() const {
+ if (current_edited_scene != -1) {
+ return edited_scene[current_edited_scene].history_id;
+ }
+ return 0;
+}
+
+int EditorData::get_scene_history_id(int p_idx) const {
+ return edited_scene[p_idx].history_id;
+}
+
+Ref<EditorUndoRedoManager> &EditorData::get_undo_redo() {
+ return undo_redo_manager;
}
void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) {
@@ -415,12 +457,12 @@ Callable EditorData::get_move_array_element_function(const StringName &p_class)
}
void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) {
- p_plugin->undo_redo = nullptr;
+ p_plugin->undo_redo = Ref<EditorUndoRedoManager>();
editor_plugins.erase(p_plugin);
}
void EditorData::add_editor_plugin(EditorPlugin *p_plugin) {
- p_plugin->undo_redo = &undo_redo;
+ p_plugin->undo_redo = undo_redo_manager;
editor_plugins.push_back(p_plugin);
}
@@ -467,6 +509,32 @@ Variant EditorData::instance_custom_type(const String &p_type, const String &p_i
return Variant();
}
+const EditorData::CustomType *EditorData::get_custom_type_by_name(const String &p_type) const {
+ for (const KeyValue<String, Vector<CustomType>> &E : custom_types) {
+ for (const CustomType &F : E.value) {
+ if (F.name == p_type) {
+ return &F;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const EditorData::CustomType *EditorData::get_custom_type_by_path(const String &p_path) const {
+ for (const KeyValue<String, Vector<CustomType>> &E : custom_types) {
+ for (const CustomType &F : E.value) {
+ if (F.script->get_path() == p_path) {
+ return &F;
+ }
+ }
+ }
+ return nullptr;
+}
+
+bool EditorData::is_type_recognized(const String &p_type) const {
+ return ClassDB::class_exists(p_type) || ScriptServer::is_global_class(p_type) || get_custom_type_by_name(p_type);
+}
+
void EditorData::remove_custom_type(const String &p_type) {
for (KeyValue<String, Vector<CustomType>> &E : custom_types) {
for (int i = 0; i < E.value.size(); i++) {
@@ -505,8 +573,8 @@ int EditorData::add_edited_scene(int p_at_pos) {
es.path = String();
es.file_modified_time = 0;
es.history_current = -1;
- es.version = 0;
es.live_edit_root = NodePath(String("/root"));
+ es.history_id = last_created_scene++;
if (p_at_pos == edited_scene.size()) {
edited_scene.push_back(es);
@@ -547,6 +615,7 @@ void EditorData::remove_scene(int p_idx) {
ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(edited_scene[p_idx].path);
}
+ undo_redo_manager->discard_history(edited_scene[p_idx].history_id);
edited_scene.remove_at(p_idx);
}
@@ -679,26 +748,10 @@ Vector<EditorData::EditedScene> EditorData::get_edited_scenes() const {
return out_edited_scenes_list;
}
-void EditorData::set_edited_scene_version(uint64_t version, int p_scene_idx) {
- ERR_FAIL_INDEX(current_edited_scene, edited_scene.size());
- if (p_scene_idx < 0) {
- edited_scene.write[current_edited_scene].version = version;
- } else {
- ERR_FAIL_INDEX(p_scene_idx, edited_scene.size());
- edited_scene.write[p_scene_idx].version = version;
- }
-}
-
-uint64_t EditorData::get_scene_version(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), 0);
- return edited_scene[p_idx].version;
-}
-
void EditorData::set_scene_modified_time(int p_idx, uint64_t p_time) {
if (p_idx == -1) {
p_idx = current_edited_scene;
}
-
ERR_FAIL_INDEX(p_idx, edited_scene.size());
edited_scene.write[p_idx].file_modified_time = p_time;
@@ -991,6 +1044,7 @@ void EditorData::script_class_load_icon_paths() {
EditorData::EditorData() {
current_edited_scene = -1;
+ undo_redo_manager.instantiate();
script_class_load_icon_paths();
}
@@ -1028,7 +1082,7 @@ void EditorSelection::add_node(Node *p_node) {
}
selection[p_node] = meta;
- p_node->connect("tree_exiting", callable_mp(this, &EditorSelection::_node_removed).bind(p_node), CONNECT_ONESHOT);
+ p_node->connect("tree_exiting", callable_mp(this, &EditorSelection::_node_removed).bind(p_node), CONNECT_ONE_SHOT);
}
void EditorSelection::remove_node(Node *p_node) {
@@ -1115,8 +1169,8 @@ void EditorSelection::_emit_change() {
emitted = false;
}
-Array EditorSelection::_get_transformable_selected_nodes() {
- Array ret;
+TypedArray<Node> EditorSelection::_get_transformable_selected_nodes() {
+ TypedArray<Node> ret;
for (const Node *E : selected_node_list) {
ret.push_back(E);
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 351c63f4b9..4f1740d4f0 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -31,12 +31,12 @@
#ifndef EDITOR_DATA_H
#define EDITOR_DATA_H
-#include "core/object/undo_redo.h"
#include "core/templates/list.h"
#include "scene/resources/texture.h"
class ConfigFile;
class EditorPlugin;
+class EditorUndoRedoManager;
/**
* Stores the history of objects which have been selected for editing in the Editor & the Inspector.
@@ -118,8 +118,9 @@ public:
Vector<EditorSelectionHistory::HistoryElement> history_stored;
int history_current = 0;
Dictionary custom_state;
- uint64_t version = 0;
NodePath live_edit_root;
+ int history_id = 0;
+ uint64_t last_checked_version = 0;
};
private:
@@ -132,12 +133,13 @@ private:
HashMap<String, Vector<CustomType>> custom_types;
List<PropertyData> clipboard;
- UndoRedo undo_redo;
+ Ref<EditorUndoRedoManager> undo_redo_manager;
Vector<Callable> undo_redo_callbacks;
HashMap<StringName, Callable> move_element_functions;
Vector<EditedScene> edited_scene;
- int current_edited_scene;
+ int current_edited_scene = -1;
+ int last_created_scene = 1;
bool _find_updated_instances(Node *p_root, Node *p_node, HashSet<String> &checked_paths);
@@ -166,7 +168,7 @@ public:
int get_editor_plugin_count() const;
EditorPlugin *get_editor_plugin(int p_idx);
- UndoRedo &get_undo_redo();
+ Ref<EditorUndoRedoManager> &get_undo_redo();
void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value)
void remove_undo_redo_inspector_hook_callback(Callable p_callable);
const Vector<Callable> get_undo_redo_inspector_hook_callback();
@@ -182,6 +184,9 @@ public:
Variant instance_custom_type(const String &p_type, const String &p_inherits);
void remove_custom_type(const String &p_type);
const HashMap<String, Vector<CustomType>> &get_custom_types() const { return custom_types; }
+ const CustomType *get_custom_type_by_name(const String &p_name) const;
+ const CustomType *get_custom_type_by_path(const String &p_path) const;
+ bool is_type_recognized(const String &p_type) const;
void instantiate_object_properties(Object *p_object);
@@ -200,7 +205,6 @@ public:
void set_scene_path(int p_idx, const String &p_path);
Ref<Script> get_scene_root_script(int p_idx) const;
void set_edited_scene_version(uint64_t version, int p_scene_idx = -1);
- uint64_t get_scene_version(int p_idx) const;
void set_scene_modified_time(int p_idx, uint64_t p_time);
uint64_t get_scene_modified_time(int p_idx) const;
void clear_edited_scenes();
@@ -210,6 +214,13 @@ public:
void move_edited_scene_to_index(int p_idx);
bool call_build();
+ void set_scene_as_saved(int p_idx);
+ bool is_scene_changed(int p_idx);
+
+ int get_scene_history_id_from_path(const String &p_path) const;
+ int get_current_edited_scene_history_id() const;
+ int get_scene_history_id(int p_idx) const;
+
void set_plugin_window_layout(Ref<ConfigFile> p_layout);
void get_plugin_window_layout(Ref<ConfigFile> p_layout);
@@ -263,7 +274,7 @@ class EditorSelection : public Object {
List<Node *> selected_node_list;
void _update_node_list();
- Array _get_transformable_selected_nodes();
+ TypedArray<Node> _get_transformable_selected_nodes();
void _emit_change();
protected:
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index 4071722185..f464ca3b3c 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -44,7 +44,7 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p
p_item->set_metadata(0, p_dir->get_path());
p_item->set_icon(0, tree->get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
- p_item->set_icon_modulate(0, tree->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")));
+ p_item->set_icon_modulate(0, tree->get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")));
if (!p_item->get_parent()) {
p_item->set_text(0, "res://");
@@ -172,7 +172,7 @@ void EditorDirDialog::_make_dir_confirm() {
mkdirerr->popup_centered(Size2(250, 80) * EDSCALE);
} else {
opened_paths.insert(dir);
- //reload(dir.plus_file(makedirname->get_text()));
+ //reload(dir.path_join(makedirname->get_text()));
EditorFileSystem::get_singleton()->scan_changes(); //we created a dir, so rescan changes
}
makedirname->set_text(""); // reset label
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index f0bf9fd5b3..708173ea26 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -315,7 +315,7 @@ void EditorFeatureProfileManager::_notification(int p_what) {
current_profile = EDITOR_GET("_default_feature_profile");
if (!current_profile.is_empty()) {
current.instantiate();
- Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(current_profile + ".profile"));
+ Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(current_profile + ".profile"));
if (err != OK) {
ERR_PRINT("Error loading default feature profile: " + current_profile);
current_profile = String();
@@ -346,7 +346,7 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr
if (p_select_profile.is_empty()) { //default, keep
if (profile_list->get_selected() >= 0) {
selected_profile = profile_list->get_item_metadata(profile_list->get_selected());
- if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(selected_profile + ".profile"))) {
+ if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(selected_profile + ".profile"))) {
selected_profile = String(); //does not exist
}
}
@@ -475,7 +475,7 @@ void EditorFeatureProfileManager::_create_new_profile() {
EditorNode::get_singleton()->show_warning(TTR("Profile must be a valid filename and must not contain '.'"));
return;
}
- String file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(name + ".profile");
+ String file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(name + ".profile");
if (FileAccess::exists(file)) {
EditorNode::get_singleton()->show_warning(TTR("Profile with this name already exists."));
return;
@@ -630,7 +630,7 @@ void EditorFeatureProfileManager::_class_list_item_selected() {
property->set_selectable(0, true);
property->set_checked(0, !edited->is_class_property_disabled(class_name, name));
property->set_text(0, text);
- property->set_tooltip(0, tooltip);
+ property->set_tooltip_text(0, tooltip);
property->set_metadata(0, name);
String icon_type = Variant::get_type_name(E.type);
property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type));
@@ -754,8 +754,8 @@ void EditorFeatureProfileManager::_update_selected_profile() {
} else {
//reload edited, if different from current
edited.instantiate();
- Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile"));
- ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile") + "'.");
+ Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile"));
+ ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile") + "'.");
}
updating_features = true;
@@ -810,7 +810,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths
return;
}
- String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile);
+ String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile);
if (FileAccess::exists(dst_file)) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Profile '%s' already exists. Remove it first before importing, import aborted."), basefile.get_basename()));
@@ -825,7 +825,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths
Error err = profile->load_from_file(p_paths[i]);
ERR_CONTINUE(err != OK);
String basefile = p_paths[i].get_file();
- String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile);
+ String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile);
profile->save_to_file(dst_file);
}
@@ -849,7 +849,7 @@ void EditorFeatureProfileManager::_save_and_update() {
ERR_FAIL_COND(edited_path.is_empty());
ERR_FAIL_COND(edited.is_null());
- edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(edited_path + ".profile"));
+ edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(edited_path + ".profile"));
if (edited == current) {
update_timer->start();
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 2f1134e8ef..9fa08a0adb 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -37,6 +37,7 @@
#include "core/string/print_string.h"
#include "dependency_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"
@@ -68,13 +69,49 @@ VBoxContainer *EditorFileDialog::get_vbox() {
return vbox;
}
+void EditorFileDialog::_update_theme_item_cache() {
+ ConfirmationDialog::_update_theme_item_cache();
+
+ theme_cache.parent_folder = get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons"));
+ theme_cache.forward_folder = get_theme_icon(SNAME("Forward"), SNAME("EditorIcons"));
+ theme_cache.back_folder = get_theme_icon(SNAME("Back"), SNAME("EditorIcons"));
+ theme_cache.reload = get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"));
+ theme_cache.toggle_hidden = get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"));
+ theme_cache.favorite = get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons"));
+ theme_cache.mode_thumbnails = get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons"));
+ theme_cache.mode_list = get_theme_icon(SNAME("FileList"), SNAME("EditorIcons"));
+ theme_cache.favorites_up = get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons"));
+ theme_cache.favorites_down = get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons"));
+
+ theme_cache.folder = get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"));
+ theme_cache.folder_icon_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog"));
+
+ theme_cache.action_copy = get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons"));
+ theme_cache.action_delete = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
+ theme_cache.filesystem = get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons"));
+
+ theme_cache.folder_medium_thumbnail = get_theme_icon(SNAME("FolderMediumThumb"), SNAME("EditorIcons"));
+ theme_cache.file_medium_thumbnail = get_theme_icon(SNAME("FileMediumThumb"), SNAME("EditorIcons"));
+ theme_cache.folder_big_thumbnail = get_theme_icon(SNAME("FolderBigThumb"), SNAME("EditorIcons"));
+ theme_cache.file_big_thumbnail = get_theme_icon(SNAME("FileBigThumb"), SNAME("EditorIcons"));
+
+ theme_cache.progress[0] = get_theme_icon("Progress1", SNAME("EditorIcons"));
+ theme_cache.progress[1] = get_theme_icon("Progress2", SNAME("EditorIcons"));
+ theme_cache.progress[2] = get_theme_icon("Progress3", SNAME("EditorIcons"));
+ theme_cache.progress[3] = get_theme_icon("Progress4", SNAME("EditorIcons"));
+ theme_cache.progress[4] = get_theme_icon("Progress5", SNAME("EditorIcons"));
+ theme_cache.progress[5] = get_theme_icon("Progress6", SNAME("EditorIcons"));
+ theme_cache.progress[6] = get_theme_icon("Progress7", SNAME("EditorIcons"));
+ theme_cache.progress[7] = get_theme_icon("Progress8", SNAME("EditorIcons"));
+}
+
void EditorFileDialog::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY:
case NOTIFICATION_THEME_CHANGED:
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
_update_icons();
+ invalidate();
} break;
case NOTIFICATION_PROCESS: {
@@ -85,7 +122,8 @@ void EditorFileDialog::_notification(int p_what) {
if (preview_wheel_index >= 8) {
preview_wheel_index = 0;
}
- Ref<Texture2D> frame = item_list->get_theme_icon("Progress" + itos(preview_wheel_index + 1), SNAME("EditorIcons"));
+
+ Ref<Texture2D> frame = theme_cache.progress[preview_wheel_index];
preview->set_texture(frame);
preview_wheel_timeout = 0.1;
}
@@ -99,7 +137,6 @@ void EditorFileDialog::_notification(int p_what) {
}
set_display_mode((DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int());
- _update_icons();
// DO NOT CALL UPDATE FILE LIST HERE, ALL HUNDREDS OF HIDDEN DIALOGS WILL RESPOND, CALL INVALIDATE INSTEAD
invalidate();
} break;
@@ -108,6 +145,8 @@ void EditorFileDialog::_notification(int p_what) {
if (!is_visible()) {
set_process_shortcut_input(false);
}
+
+ invalidate(); // For consistency with the standard FileDialog.
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
@@ -251,7 +290,7 @@ void EditorFileDialog::_file_submitted(const String &p_file) {
}
void EditorFileDialog::_save_confirm_pressed() {
- String f = dir_access->get_current_dir().plus_file(file->get_text());
+ String f = dir_access->get_current_dir().path_join(file->get_text());
_save_to_recent();
hide();
emit_signal(SNAME("file_selected"), f);
@@ -267,10 +306,6 @@ void EditorFileDialog::_post_popup() {
}
set_current_dir(current);
- if (invalidated) {
- update_file_list();
- invalidated = false;
- }
if (mode == FILE_MODE_SAVE_FILE) {
file->grab_focus();
} else {
@@ -283,49 +318,13 @@ void EditorFileDialog::_post_popup() {
file_box->set_visible(true);
}
- if (is_visible() && !get_current_file().is_empty()) {
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ if (!get_current_file().is_empty()) {
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
}
- if (is_visible()) {
- Ref<Texture2D> folder = item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- const Color folder_color = item_list->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
- recent->clear();
-
- bool res = (access == ACCESS_RESOURCES);
- Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
- for (int i = 0; i < recentd.size(); i++) {
- bool cres = recentd[i].begins_with("res://");
- if (cres != res) {
- continue;
- }
- String name = recentd[i];
- if (res && name == "res://") {
- name = "/";
- } else {
- if (name.ends_with("/")) {
- name = name.substr(0, name.length() - 1);
- }
- name = name.get_file() + "/";
- }
- bool exists = dir_access->dir_exists(recentd[i]);
- if (!exists) {
- // Remove invalid directory from the list of Recent directories.
- recentd.remove_at(i--);
- } else {
- recent->add_item(name, folder);
- recent->set_item_metadata(-1, recentd[i]);
- recent->set_item_icon_modulate(-1, folder_color);
- }
- }
- EditorSettings::get_singleton()->set_recent_dirs(recentd);
-
- local_history.clear();
- local_history_pos = -1;
- _push_history();
-
- _update_favorites();
- }
+ local_history.clear();
+ local_history_pos = -1;
+ _push_history();
set_process_shortcut_input(true);
}
@@ -381,7 +380,7 @@ void EditorFileDialog::_action_pressed() {
Vector<String> files;
for (int i = 0; i < item_list->get_item_count(); i++) {
if (item_list->is_selected(i)) {
- files.push_back(fbase.plus_file(item_list->get_item_text(i)));
+ files.push_back(fbase.path_join(item_list->get_item_text(i)));
}
}
@@ -395,7 +394,7 @@ void EditorFileDialog::_action_pressed() {
}
String file_text = file->get_text();
- String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text);
+ String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text);
if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
_save_to_recent();
@@ -410,7 +409,7 @@ void EditorFileDialog::_action_pressed() {
if (item_list->is_selected(i)) {
Dictionary d = item_list->get_item_metadata(i);
if (d["dir"]) {
- path = path.plus_file(d["name"]);
+ path = path.path_join(d["name"]);
break;
}
@@ -461,7 +460,7 @@ void EditorFileDialog::_action_pressed() {
if (!valid && filterSliceCount > 0) {
String str = (flt.get_slice(",", 0).strip_edges());
f += str.substr(1, str.length() - 1);
- _request_single_thumbnail(get_current_dir().plus_file(f.get_file()));
+ _request_single_thumbnail(get_current_dir().path_join(f.get_file()));
file->set_text(f.get_file());
valid = true;
}
@@ -505,7 +504,7 @@ void EditorFileDialog::_item_selected(int p_item) {
if (!d["dir"]) {
file->set_text(d["name"]);
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
} else if (mode == FILE_MODE_OPEN_DIR) {
set_ok_button_text(TTR("Select This Folder"));
}
@@ -523,7 +522,7 @@ void EditorFileDialog::_multi_selected(int p_item, bool p_selected) {
if (!d["dir"] && p_selected) {
file->set_text(d["name"]);
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
}
get_ok_button()->set_disabled(_is_open_should_be_disabled());
@@ -613,16 +612,16 @@ void EditorFileDialog::_item_list_item_rmb_clicked(int p_item, const Vector2 &p_
}
if (single_item_selected) {
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")), TTR("Copy Path"), ITEM_MENU_COPY_PATH);
+ item_menu->add_icon_item(theme_cache.action_copy, TTR("Copy Path"), ITEM_MENU_COPY_PATH);
}
if (allow_delete) {
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete"), ITEM_MENU_DELETE, Key::KEY_DELETE);
+ item_menu->add_icon_item(theme_cache.action_delete, TTR("Delete"), ITEM_MENU_DELETE, Key::KEY_DELETE);
}
if (single_item_selected) {
item_menu->add_separator();
Dictionary item_meta = item_list->get_item_metadata(p_item);
String item_text = item_meta["dir"] ? TTR("Open in File Manager") : TTR("Show in File Manager");
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), item_text, ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(theme_cache.filesystem, item_text, ITEM_MENU_SHOW_IN_EXPLORER);
}
if (item_menu->get_item_count() > 0) {
@@ -650,11 +649,11 @@ void EditorFileDialog::_item_list_empty_clicked(const Vector2 &p_pos, MouseButto
item_menu->reset_size();
if (can_create_dir) {
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog")), TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD | Key::N);
+ item_menu->add_icon_item(theme_cache.folder, TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD_OR_CTRL | Key::N);
}
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Refresh"), ITEM_MENU_REFRESH, Key::F5);
+ item_menu->add_icon_item(theme_cache.reload, TTR("Refresh"), ITEM_MENU_REFRESH, Key::F5);
item_menu->add_separator();
- item_menu->add_icon_item(item_list->get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(theme_cache.filesystem, TTR("Open in File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
item_menu->set_position(item_list->get_screen_position() + p_pos);
item_menu->reset_size();
@@ -760,11 +759,11 @@ void EditorFileDialog::update_file_list() {
item_list->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size));
if (thumbnail_size < 64) {
- folder_thumbnail = item_list->get_theme_icon(SNAME("FolderMediumThumb"), SNAME("EditorIcons"));
- file_thumbnail = item_list->get_theme_icon(SNAME("FileMediumThumb"), SNAME("EditorIcons"));
+ folder_thumbnail = theme_cache.folder_medium_thumbnail;
+ file_thumbnail = theme_cache.file_medium_thumbnail;
} else {
- folder_thumbnail = item_list->get_theme_icon(SNAME("FolderBigThumb"), SNAME("EditorIcons"));
- file_thumbnail = item_list->get_theme_icon(SNAME("FileBigThumb"), SNAME("EditorIcons"));
+ folder_thumbnail = theme_cache.folder_big_thumbnail;
+ file_thumbnail = theme_cache.file_big_thumbnail;
}
preview_vb->hide();
@@ -784,8 +783,6 @@ void EditorFileDialog::update_file_list() {
dir_access->list_dir_begin();
- Ref<Texture2D> folder = item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- const Color folder_color = item_list->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
List<String> files;
List<String> dirs;
@@ -825,16 +822,16 @@ void EditorFileDialog::update_file_list() {
if (display_mode == DISPLAY_THUMBNAILS) {
item_list->set_item_icon(-1, folder_thumbnail);
} else {
- item_list->set_item_icon(-1, folder);
+ item_list->set_item_icon(-1, theme_cache.folder);
}
Dictionary d;
d["name"] = dir_name;
- d["path"] = cdir.plus_file(dir_name);
+ d["path"] = cdir.path_join(dir_name);
d["dir"] = true;
item_list->set_item_metadata(-1, d);
- item_list->set_item_icon_modulate(-1, folder_color);
+ item_list->set_item_icon_modulate(-1, theme_cache.folder_icon_color);
dirs.pop_front();
}
@@ -879,7 +876,7 @@ void EditorFileDialog::update_file_list() {
item_list->add_item(files.front()->get());
if (get_icon_func) {
- Ref<Texture2D> icon = get_icon_func(cdir.plus_file(files.front()->get()));
+ Ref<Texture2D> icon = get_icon_func(cdir.path_join(files.front()->get()));
if (display_mode == DISPLAY_THUMBNAILS) {
item_list->set_item_icon(-1, file_thumbnail);
item_list->set_item_tag_icon(-1, icon);
@@ -891,7 +888,7 @@ void EditorFileDialog::update_file_list() {
Dictionary d;
d["name"] = files.front()->get();
d["dir"] = false;
- String fullpath = cdir.plus_file(files.front()->get());
+ String fullpath = cdir.path_join(files.front()->get());
d["path"] = fullpath;
item_list->set_item_metadata(-1, d);
@@ -995,7 +992,7 @@ String EditorFileDialog::get_current_file() const {
}
String EditorFileDialog::get_current_path() const {
- return dir_access->get_current_dir().plus_file(file->get_text());
+ return dir_access->get_current_dir().path_join(file->get_text());
}
void EditorFileDialog::set_current_dir(const String &p_dir) {
@@ -1014,7 +1011,7 @@ void EditorFileDialog::set_current_file(const String &p_file) {
_focus_file_text();
if (is_visible()) {
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
}
}
@@ -1107,6 +1104,7 @@ void EditorFileDialog::invalidate() {
if (is_visible()) {
update_file_list();
_update_favorites();
+ _update_recent();
invalidated = false;
} else {
invalidated = true;
@@ -1222,22 +1220,25 @@ void EditorFileDialog::_update_drives(bool p_select) {
void EditorFileDialog::_update_icons() {
// Update icons.
- mode_thumbnails->set_icon(item_list->get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons")));
- mode_list->set_icon(item_list->get_theme_icon(SNAME("FileList"), SNAME("EditorIcons")));
+
+ mode_thumbnails->set_icon(theme_cache.mode_thumbnails);
+ mode_list->set_icon(theme_cache.mode_list);
+
if (is_layout_rtl()) {
- dir_prev->set_icon(item_list->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons")));
- dir_next->set_icon(item_list->get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
+ dir_prev->set_icon(theme_cache.forward_folder);
+ dir_next->set_icon(theme_cache.back_folder);
} else {
- dir_prev->set_icon(item_list->get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
- dir_next->set_icon(item_list->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons")));
+ dir_prev->set_icon(theme_cache.back_folder);
+ dir_next->set_icon(theme_cache.forward_folder);
}
- dir_up->set_icon(item_list->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")));
- refresh->set_icon(item_list->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
- favorite->set_icon(item_list->get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
- show_hidden->set_icon(item_list->get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
+ dir_up->set_icon(theme_cache.parent_folder);
- fav_up->set_icon(item_list->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
- fav_down->set_icon(item_list->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
+ refresh->set_icon(theme_cache.reload);
+ favorite->set_icon(theme_cache.favorite);
+ show_hidden->set_icon(theme_cache.toggle_hidden);
+
+ fav_up->set_icon(theme_cache.favorites_up);
+ fav_down->set_icon(theme_cache.favorites_down);
}
void EditorFileDialog::_favorite_selected(int p_idx) {
@@ -1322,56 +1323,63 @@ void EditorFileDialog::_update_favorites() {
bool res = (access == ACCESS_RESOURCES);
String current = get_current_dir();
- Ref<Texture2D> folder_icon = item_list->get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"));
- const Color folder_color = item_list->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
favorites->clear();
favorite->set_pressed(false);
Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> favorited_paths;
+ Vector<String> favorited_names;
bool fav_changed = false;
- for (int i = favorited.size() - 1; i >= 0; i--) {
- if (!dir_access->dir_exists(favorited[i])) {
- favorited.remove_at(i);
- fav_changed = true;
- }
- }
- if (fav_changed) {
- EditorSettings::get_singleton()->set_favorites(favorited);
- }
-
+ int current_favorite = -1;
for (int i = 0; i < favorited.size(); i++) {
bool cres = favorited[i].begins_with("res://");
if (cres != res) {
continue;
}
- String name = favorited[i];
- bool setthis = false;
+ if (!dir_access->dir_exists(favorited[i])) {
+ // Remove invalid directory from the list of Favorited directories.
+ favorited.remove_at(i--);
+ fav_changed = true;
+ continue;
+ }
+
+ // Compute favorite display text.
+ String name = favorited[i];
if (res && name == "res://") {
if (name == current) {
- setthis = true;
+ current_favorite = favorited_paths.size();
}
name = "/";
-
- favorites->add_item(name, folder_icon);
+ favorited_paths.append(favorited[i]);
+ favorited_names.append(name);
} else if (name.ends_with("/")) {
if (name == current || name == current + "/") {
- setthis = true;
+ current_favorite = favorited_paths.size();
}
name = name.substr(0, name.length() - 1);
name = name.get_file();
-
- favorites->add_item(name, folder_icon);
+ favorited_paths.append(favorited[i]);
+ favorited_names.append(name);
} else {
- continue; // We don't handle favorite files here.
+ // Ignore favorited files.
}
+ }
+
+ if (fav_changed) {
+ EditorSettings::get_singleton()->set_favorites(favorited);
+ }
+
+ EditorNode::disambiguate_filenames(favorited_paths, favorited_names);
- favorites->set_item_metadata(-1, favorited[i]);
- favorites->set_item_icon_modulate(-1, folder_color);
+ for (int i = 0; i < favorited_paths.size(); i++) {
+ favorites->add_item(favorited_names[i], theme_cache.folder);
+ favorites->set_item_metadata(-1, favorited_paths[i]);
+ favorites->set_item_icon_modulate(-1, theme_cache.folder_icon_color);
- if (setthis) {
+ if (i == current_favorite) {
favorite->set_pressed(true);
favorites->set_current(favorites->get_item_count() - 1);
recent->deselect_all();
@@ -1413,6 +1421,50 @@ void EditorFileDialog::_favorite_pressed() {
_update_favorites();
}
+void EditorFileDialog::_update_recent() {
+ recent->clear();
+
+ bool res = (access == ACCESS_RESOURCES);
+ Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
+ Vector<String> recentd_paths;
+ Vector<String> recentd_names;
+
+ for (int i = 0; i < recentd.size(); i++) {
+ bool cres = recentd[i].begins_with("res://");
+ if (cres != res) {
+ continue;
+ }
+
+ if (!dir_access->dir_exists(recentd[i])) {
+ // Remove invalid directory from the list of Recent directories.
+ recentd.remove_at(i--);
+ continue;
+ }
+
+ // Compute recent directory display text.
+ String name = recentd[i];
+ if (res && name == "res://") {
+ name = "/";
+ } else {
+ if (name.ends_with("/")) {
+ name = name.substr(0, name.length() - 1);
+ }
+ name = name.get_file();
+ }
+ recentd_paths.append(recentd[i]);
+ recentd_names.append(name);
+ }
+
+ EditorNode::disambiguate_filenames(recentd_paths, recentd_names);
+
+ for (int i = 0; i < recentd_paths.size(); i++) {
+ recent->add_item(recentd_names[i], theme_cache.folder);
+ recent->set_item_metadata(-1, recentd_paths[i]);
+ recent->set_item_icon_modulate(-1, theme_cache.folder_icon_color);
+ }
+ EditorSettings::get_singleton()->set_recent_dirs(recentd);
+}
+
void EditorFileDialog::_recent_selected(int p_idx) {
Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
ERR_FAIL_INDEX(p_idx, recentd.size());
@@ -1612,26 +1664,26 @@ EditorFileDialog::EditorFileDialog() {
ED_SHORTCUT("file_dialog/go_forward", TTR("Go Forward"), KeyModifierMask::ALT | Key::RIGHT);
ED_SHORTCUT("file_dialog/go_up", TTR("Go Up"), KeyModifierMask::ALT | Key::UP);
ED_SHORTCUT("file_dialog/refresh", TTR("Refresh"), Key::F5);
- ED_SHORTCUT("file_dialog/toggle_hidden_files", TTR("Toggle Hidden Files"), KeyModifierMask::CMD | Key::H);
+ ED_SHORTCUT("file_dialog/toggle_hidden_files", TTR("Toggle Hidden Files"), KeyModifierMask::CMD_OR_CTRL | Key::H);
ED_SHORTCUT("file_dialog/toggle_favorite", TTR("Toggle Favorite"), KeyModifierMask::ALT | Key::F);
ED_SHORTCUT("file_dialog/toggle_mode", TTR("Toggle Mode"), KeyModifierMask::ALT | Key::V);
- ED_SHORTCUT("file_dialog/create_folder", TTR("Create Folder"), KeyModifierMask::CMD | Key::N);
+ ED_SHORTCUT("file_dialog/create_folder", TTR("Create Folder"), KeyModifierMask::CMD_OR_CTRL | Key::N);
ED_SHORTCUT("file_dialog/delete", TTR("Delete"), Key::KEY_DELETE);
- ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KeyModifierMask::CMD | Key::D);
- ED_SHORTCUT("file_dialog/move_favorite_up", TTR("Move Favorite Up"), KeyModifierMask::CMD | Key::UP);
- ED_SHORTCUT("file_dialog/move_favorite_down", TTR("Move Favorite Down"), KeyModifierMask::CMD | Key::DOWN);
+ ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KeyModifierMask::CMD_OR_CTRL | Key::D);
+ ED_SHORTCUT("file_dialog/move_favorite_up", TTR("Move Favorite Up"), KeyModifierMask::CMD_OR_CTRL | Key::UP);
+ ED_SHORTCUT("file_dialog/move_favorite_down", TTR("Move Favorite Down"), KeyModifierMask::CMD_OR_CTRL | Key::DOWN);
HBoxContainer *pathhb = memnew(HBoxContainer);
dir_prev = memnew(Button);
dir_prev->set_flat(true);
- dir_prev->set_tooltip(TTR("Go to previous folder."));
+ dir_prev->set_tooltip_text(TTR("Go to previous folder."));
dir_next = memnew(Button);
dir_next->set_flat(true);
- dir_next->set_tooltip(TTR("Go to next folder."));
+ dir_next->set_tooltip_text(TTR("Go to next folder."));
dir_up = memnew(Button);
dir_up->set_flat(true);
- dir_up->set_tooltip(TTR("Go to parent folder."));
+ dir_up->set_tooltip_text(TTR("Go to parent folder."));
pathhb->add_child(dir_prev);
pathhb->add_child(dir_next);
@@ -1655,14 +1707,14 @@ EditorFileDialog::EditorFileDialog() {
refresh = memnew(Button);
refresh->set_flat(true);
- refresh->set_tooltip(TTR("Refresh files."));
+ refresh->set_tooltip_text(TTR("Refresh files."));
refresh->connect("pressed", callable_mp(this, &EditorFileDialog::update_file_list));
pathhb->add_child(refresh);
favorite = memnew(Button);
favorite->set_flat(true);
favorite->set_toggle_mode(true);
- favorite->set_tooltip(TTR("(Un)favorite current folder."));
+ favorite->set_tooltip_text(TTR("(Un)favorite current folder."));
favorite->connect("pressed", callable_mp(this, &EditorFileDialog::_favorite_pressed));
pathhb->add_child(favorite);
@@ -1670,7 +1722,7 @@ EditorFileDialog::EditorFileDialog() {
show_hidden->set_flat(true);
show_hidden->set_toggle_mode(true);
show_hidden->set_pressed(is_showing_hidden_files());
- show_hidden->set_tooltip(TTR("Toggle the visibility of hidden files."));
+ show_hidden->set_tooltip_text(TTR("Toggle the visibility of hidden files."));
show_hidden->connect("toggled", callable_mp(this, &EditorFileDialog::set_show_hidden_files));
pathhb->add_child(show_hidden);
@@ -1685,7 +1737,7 @@ EditorFileDialog::EditorFileDialog() {
mode_thumbnails->set_toggle_mode(true);
mode_thumbnails->set_pressed(display_mode == DISPLAY_THUMBNAILS);
mode_thumbnails->set_button_group(view_mode_group);
- mode_thumbnails->set_tooltip(TTR("View items as a grid of thumbnails."));
+ mode_thumbnails->set_tooltip_text(TTR("View items as a grid of thumbnails."));
pathhb->add_child(mode_thumbnails);
mode_list = memnew(Button);
@@ -1694,7 +1746,7 @@ EditorFileDialog::EditorFileDialog() {
mode_list->set_toggle_mode(true);
mode_list->set_pressed(display_mode == DISPLAY_LIST);
mode_list->set_button_group(view_mode_group);
- mode_list->set_tooltip(TTR("View items as a list."));
+ mode_list->set_tooltip_text(TTR("View items as a list."));
pathhb->add_child(mode_list);
shortcuts_container = memnew(HBoxContainer);
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 51629f2682..6d11cb10ed 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -148,6 +148,33 @@ private:
bool disable_overwrite_warning = false;
bool invalidated = true;
+ struct ThemeCache {
+ Ref<Texture2D> parent_folder;
+ Ref<Texture2D> forward_folder;
+ Ref<Texture2D> back_folder;
+ Ref<Texture2D> reload;
+ Ref<Texture2D> toggle_hidden;
+ Ref<Texture2D> favorite;
+ Ref<Texture2D> mode_thumbnails;
+ Ref<Texture2D> mode_list;
+ Ref<Texture2D> favorites_up;
+ Ref<Texture2D> favorites_down;
+
+ Ref<Texture2D> folder;
+ Color folder_icon_color;
+
+ Ref<Texture2D> action_copy;
+ Ref<Texture2D> action_delete;
+ Ref<Texture2D> filesystem;
+
+ Ref<Texture2D> folder_medium_thumbnail;
+ Ref<Texture2D> file_medium_thumbnail;
+ Ref<Texture2D> folder_big_thumbnail;
+ Ref<Texture2D> file_big_thumbnail;
+
+ Ref<Texture2D> progress[8]{};
+ } theme_cache;
+
void update_dir();
void update_file_name();
void update_file_list();
@@ -161,6 +188,7 @@ private:
void _favorite_move_up();
void _favorite_move_down();
+ void _update_recent();
void _recent_selected(int p_idx);
void _item_selected(int p_item);
@@ -206,6 +234,8 @@ private:
bool _is_open_should_be_disabled();
protected:
+ virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 1a105c7fe8..177bc6d2b2 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -99,7 +99,7 @@ String EditorFileSystemDirectory::get_path() const {
String p;
const EditorFileSystemDirectory *d = this;
while (d->parent) {
- p = d->name.plus_file(p);
+ p = d->name.path_join(p);
d = d->parent;
}
@@ -110,7 +110,7 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const {
String file = get_file(p_idx);
const EditorFileSystemDirectory *d = this;
while (d->parent) {
- file = d->name.plus_file(file);
+ file = d->name.path_join(file);
d = d->parent;
}
@@ -219,7 +219,7 @@ void EditorFileSystem::_scan_filesystem() {
String project = ProjectSettings::get_singleton()->get_resource_path();
- String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
+ String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME);
{
Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::READ);
@@ -261,7 +261,7 @@ void EditorFileSystem::_scan_filesystem() {
String file;
file = name;
- name = cpath.plus_file(name);
+ name = cpath.path_join(name);
FileCache fc;
fc.type = split[1];
@@ -289,7 +289,7 @@ void EditorFileSystem::_scan_filesystem() {
}
}
- String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
+ String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4");
if (FileAccess::exists(update_cache)) {
{
@@ -332,7 +332,7 @@ void EditorFileSystem::_scan_filesystem() {
void EditorFileSystem::_save_filesystem_cache() {
group_file_cache.clear();
- String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
+ String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME);
Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE);
ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions.");
@@ -758,7 +758,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
continue;
}
- if (_should_skip_directory(cd.plus_file(f))) {
+ if (_should_skip_directory(cd.path_join(f))) {
continue;
}
@@ -822,7 +822,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = E->get();
- String path = cd.plus_file(fi->file);
+ String path = cd.path_join(fi->file);
FileCache *fc = file_cache.getptr(path);
uint64_t mt = FileAccess::get_modified_time(path);
@@ -982,7 +982,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
int idx = p_dir->find_dir_index(f);
if (idx == -1) {
- if (_should_skip_directory(cd.plus_file(f))) {
+ if (_should_skip_directory(cd.path_join(f))) {
continue;
}
@@ -991,7 +991,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
efd->parent = p_dir;
efd->name = f;
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- d->change_dir(cd.plus_file(f));
+ d->change_dir(cd.path_join(f));
_scan_new_dir(efd, d, p_progress.get_sub(1, 1));
ItemAction ia;
@@ -1017,7 +1017,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = f;
- String path = cd.plus_file(fi->file);
+ String path = cd.path_join(fi->file);
fi->modified_time = FileAccess::get_modified_time(path);
fi->import_modified_time = 0;
fi->type = ResourceLoader::get_resource_type(path);
@@ -1066,7 +1066,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
continue;
}
- String path = cd.plus_file(p_dir->files[i]->file);
+ String path = cd.path_join(p_dir->files[i]->file);
if (import_extensions.has(p_dir->files[i]->file.get_extension().to_lower())) {
//check here if file must be imported or not
@@ -1192,11 +1192,6 @@ void EditorFileSystem::scan_changes() {
void EditorFileSystem::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- call_deferred(SNAME("scan")); //this should happen after every editor node entered the tree
-
- } break;
-
case NOTIFICATION_EXIT_TREE: {
Thread &active_thread = thread.is_started() ? thread : thread_sources;
if (use_threads && active_thread.is_started()) {
@@ -1457,7 +1452,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
void EditorFileSystem::_save_late_updated_files() {
//files that already existed, and were modified, need re-scanning for dependencies upon project restart. This is done via saving this special file
- String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
+ String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4");
Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE);
ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions.");
for (const String &E : late_update_files) {
@@ -2203,12 +2198,12 @@ bool EditorFileSystem::_should_skip_directory(const String &p_path) {
return true;
}
- if (FileAccess::exists(p_path.plus_file("project.godot"))) {
+ if (FileAccess::exists(p_path.path_join("project.godot"))) {
// skip if another project inside this
return true;
}
- if (FileAccess::exists(p_path.plus_file(".gdignore"))) {
+ if (FileAccess::exists(p_path.path_join(".gdignore"))) {
// skip if a `.gdignore` file is inside this
return true;
}
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index c1d6e505db..d455e0248e 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -56,7 +56,7 @@ void EditorFolding::save_resource_folding(const Ref<Resource> &p_resource, const
config->set_value("folding", "sections_unfolded", unfolds);
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
config->save(file);
}
@@ -74,7 +74,7 @@ void EditorFolding::load_resource_folding(Ref<Resource> p_resource, const String
config.instantiate();
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
if (config->load(file) != OK) {
return;
@@ -150,7 +150,7 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path
config->set_value("folding", "nodes_folded", nodes_folded);
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
config->save(file);
}
@@ -160,7 +160,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
String path = EditorPaths::get_singleton()->get_project_settings_dir();
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
if (config->load(file) != OK) {
return;
@@ -214,7 +214,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
bool EditorFolding::has_folding_data(const String &p_path) {
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
return FileAccess::exists(file);
}
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index a02051c8ee..fffe77f1c4 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -37,7 +37,7 @@
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/font.h"
-Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
+Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
Ref<FontFile> font;
font.instantiate();
@@ -45,7 +45,7 @@ Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hin
font->set_data(data);
font->set_multichannel_signed_distance_field(p_msdf);
- font->set_antialiased(p_aa);
+ font->set_antialiasing(p_aa);
font->set_hinting(p_hinting);
font->set_force_autohinter(p_autohint);
font->set_subpixel_positioning(p_font_subpixel_positioning);
@@ -57,13 +57,13 @@ Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hin
return font;
}
-Ref<FontFile> load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
+Ref<FontFile> load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
Ref<FontFile> font;
font.instantiate();
font->set_data_ptr(p_data, p_size);
font->set_multichannel_signed_distance_field(p_msdf);
- font->set_antialiased(p_aa);
+ font->set_antialiasing(p_aa);
font->set_hinting(p_hinting);
font->set_force_autohinter(p_autohint);
font->set_subpixel_positioning(p_font_subpixel_positioning);
@@ -91,7 +91,7 @@ Ref<FontVariation> make_bold_font(const Ref<Font> &p_font, double p_embolden, Ty
void editor_register_fonts(Ref<Theme> p_theme) {
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- bool font_antialiased = (bool)EditorSettings::get_singleton()->get("interface/editor/font_antialiased");
+ TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)EditorSettings::get_singleton()->get("interface/editor/font_antialiasing");
int font_hinting_setting = (int)EditorSettings::get_singleton()->get("interface/editor/font_hinting");
TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning");
@@ -123,47 +123,47 @@ void editor_register_fonts(Ref<Theme> p_theme) {
const int default_font_size = int(EDITOR_GET("interface/editor/main_font_size")) * EDSCALE;
const float embolden_strength = 0.6;
- Ref<Font> default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false);
- Ref<Font> default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
+ Ref<Font> default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false);
+ Ref<Font> default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, true);
TypedArray<Font> fallbacks;
- Ref<FontFile> arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> hebrew_font = load_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> malayalam_font = load_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> oriya_font = load_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> sinhala_font = load_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> tamil_font = load_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> telugu_font = load_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> thai_font = load_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> fallback_font = load_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> hebrew_font = load_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> malayalam_font = load_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> oriya_font = load_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> sinhala_font = load_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> tamil_font = load_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> telugu_font = load_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> thai_font = load_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> fallback_font = load_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
default_font->set_fallbacks(fallbacks);
default_font_msdf->set_fallbacks(fallbacks);
- Ref<FontFile> default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false);
- Ref<FontFile> default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
+ Ref<FontFile> default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false);
+ Ref<FontFile> default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, true);
TypedArray<Font> fallbacks_bold;
- Ref<FontFile> arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> hebrew_font_bold = load_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> malayalam_font_bold = load_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> oriya_font_bold = load_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> sinhala_font_bold = load_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> tamil_font_bold = load_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> telugu_font_bold = load_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> hebrew_font_bold = load_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> malayalam_font_bold = load_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> oriya_font_bold = load_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> sinhala_font_bold = load_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> tamil_font_bold = load_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> telugu_font_bold = load_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
Ref<FontVariation> fallback_font_bold = make_bold_font(fallback_font, embolden_strength, &fallbacks_bold);
Ref<FontVariation> japanese_font_bold = make_bold_font(japanese_font, embolden_strength, &fallbacks_bold);
default_font_bold->set_fallbacks(fallbacks_bold);
default_font_bold_msdf->set_fallbacks(fallbacks_bold);
- Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning);
default_font_mono->set_fallbacks(fallbacks);
// Init base font configs and load custom fonts.
@@ -174,7 +174,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> default_fc;
default_fc.instantiate();
if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font);
@@ -191,7 +191,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> default_fc_msdf;
default_fc_msdf.instantiate();
if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_msdf);
@@ -208,7 +208,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> bold_fc;
bold_fc.instantiate();
if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold);
@@ -216,7 +216,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
}
bold_fc->set_base_font(custom_font);
} else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold);
@@ -234,7 +234,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> bold_fc_msdf;
bold_fc_msdf.instantiate();
if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold_msdf);
@@ -242,7 +242,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
}
bold_fc_msdf->set_base_font(custom_font);
} else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold_msdf);
@@ -260,7 +260,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> mono_fc;
mono_fc.instantiate();
if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_mono);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 8d58469684..b8f115e82e 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -239,6 +239,27 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
class_desc->pop();
}
+void EditorHelp::_add_type_icon(const String &p_type, int p_size) {
+ Ref<Texture2D> icon;
+ if (has_theme_icon(p_type, SNAME("EditorIcons"))) {
+ icon = get_theme_icon(p_type, SNAME("EditorIcons"));
+ } else if (ClassDB::class_exists(p_type) && ClassDB::is_parent_class(p_type, "Object")) {
+ icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
+ } else {
+ icon = get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons"));
+ }
+
+ Vector2i size = Vector2i(icon->get_width(), icon->get_height());
+ if (p_size > 0) {
+ // Ensures icon scales proportionally on both axis, based on icon height.
+ float ratio = p_size / float(size.height);
+ size.width *= ratio;
+ size.height *= ratio;
+ }
+
+ class_desc->add_image(icon, size.width, size.height);
+}
+
String EditorHelp::_fix_constant(const String &p_constant) const {
if (p_constant.strip_edges() == "4294967295") {
return "0xFFFFFFFF";
@@ -530,22 +551,13 @@ void EditorHelp::_update_doc() {
DocData::ClassDoc cd = doc->class_list[edited_class]; // Make a copy, so we can sort without worrying.
- Ref<Texture2D> icon;
- if (has_theme_icon(edited_class, SNAME("EditorIcons"))) {
- icon = get_theme_icon(edited_class, SNAME("EditorIcons"));
- } else if (ClassDB::class_exists(edited_class) && ClassDB::is_parent_class(edited_class, "Object")) {
- icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
- } else {
- icon = get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons"));
- }
-
// Class name
section_line.push_back(Pair<String, int>(TTR("Top"), 0));
class_desc->push_font(doc_title_font);
class_desc->push_font_size(doc_title_font_size);
class_desc->push_color(title_color);
class_desc->add_text(TTR("Class:") + " ");
- class_desc->add_image(icon, icon->get_width(), icon->get_height());
+ _add_type_icon(edited_class, doc_title_font_size);
class_desc->add_text(" ");
class_desc->push_color(headline_color);
_add_text(edited_class);
@@ -555,6 +567,8 @@ void EditorHelp::_update_doc() {
class_desc->pop(); // font
class_desc->add_newline();
+ const String non_breaking_space = String::chr(160);
+
// Inheritance tree
// Ascendents
@@ -566,6 +580,8 @@ void EditorHelp::_update_doc() {
String inherits = cd.inherits;
while (!inherits.is_empty()) {
+ _add_type_icon(inherits);
+ class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
_add_type(inherits);
inherits = doc->class_list[inherits].inherits;
@@ -597,7 +613,8 @@ void EditorHelp::_update_doc() {
if (prev) {
class_desc->add_text(" , ");
}
-
+ _add_type_icon(E.value.name);
+ class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
_add_type(E.value.name);
prev = true;
}
@@ -1645,19 +1662,19 @@ void EditorHelp::_help_callback(const String &p_topic) {
}
}
-static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
+static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control *p_owner_node) {
DocTools *doc = EditorHelp::get_doc_data();
String base_path;
- Ref<Font> doc_font = p_rt->get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
- Ref<Font> doc_bold_font = p_rt->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
- Ref<Font> doc_italic_font = p_rt->get_theme_font(SNAME("doc_italic"), SNAME("EditorFonts"));
- Ref<Font> doc_code_font = p_rt->get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
- Ref<Font> doc_kbd_font = p_rt->get_theme_font(SNAME("doc_keyboard"), SNAME("EditorFonts"));
+ Ref<Font> doc_font = p_owner_node->get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
+ Ref<Font> doc_bold_font = p_owner_node->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
+ Ref<Font> doc_italic_font = p_owner_node->get_theme_font(SNAME("doc_italic"), SNAME("EditorFonts"));
+ Ref<Font> doc_code_font = p_owner_node->get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ Ref<Font> doc_kbd_font = p_owner_node->get_theme_font(SNAME("doc_keyboard"), SNAME("EditorFonts"));
- Color link_color = p_rt->get_theme_color(SNAME("link_color"), SNAME("EditorHelp"));
- Color code_color = p_rt->get_theme_color(SNAME("code_color"), SNAME("EditorHelp"));
- Color kbd_color = p_rt->get_theme_color(SNAME("kbd_color"), SNAME("EditorHelp"));
+ Color link_color = p_owner_node->get_theme_color(SNAME("link_color"), SNAME("EditorHelp"));
+ Color code_color = p_owner_node->get_theme_color(SNAME("code_color"), SNAME("EditorHelp"));
+ Color kbd_color = p_owner_node->get_theme_color(SNAME("kbd_color"), SNAME("EditorHelp"));
String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges();
@@ -1785,7 +1802,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
p_rt->add_text("[");
pos = brk_pos + 1;
- } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ")) {
+ } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("annotation ") || tag.begins_with("theme_item ")) {
const int tag_end = tag.find(" ");
const String link_tag = tag.substr(0, tag_end);
const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
@@ -1914,7 +1931,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
}
String image = bbcode.substr(brk_end + 1, end - brk_end - 1);
- Ref<Texture2D> texture = ResourceLoader::load(base_path.plus_file(image), "Texture2D");
+ Ref<Texture2D> texture = ResourceLoader::load(base_path.path_join(image), "Texture2D");
if (texture.is_valid()) {
p_rt->add_image(texture);
}
@@ -1931,7 +1948,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
} else if (tag.begins_with("font=")) {
String fnt = tag.substr(5, tag.length());
- Ref<Font> font = ResourceLoader::load(base_path.plus_file(fnt), "Font");
+ Ref<Font> font = ResourceLoader::load(base_path.path_join(fnt), "Font");
if (font.is_valid()) {
p_rt->push_font(font);
} else {
@@ -1949,7 +1966,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
}
void EditorHelp::_add_text(const String &p_bbcode) {
- _add_text_to_rt(p_bbcode, class_desc);
+ _add_text_to_rt(p_bbcode, class_desc, this);
}
Thread EditorHelp::thread;
@@ -2078,7 +2095,7 @@ void EditorHelp::update_toggle_scripts_button() {
} else {
toggle_scripts_button->set_icon(get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons")));
}
- toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
+ toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
}
void EditorHelp::_bind_methods() {
@@ -2175,11 +2192,10 @@ void EditorHelpBit::_bind_methods() {
void EditorHelpBit::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
rich_text->add_theme_color_override("selection_color", get_theme_color(SNAME("selection_color"), SNAME("EditorHelp")));
rich_text->clear();
- _add_text_to_rt(text, rich_text);
+ _add_text_to_rt(text, rich_text, this);
rich_text->reset_size(); // Force recalculating size after parsing bbcode.
} break;
}
@@ -2188,7 +2204,7 @@ void EditorHelpBit::_notification(int p_what) {
void EditorHelpBit::set_text(const String &p_text) {
text = p_text;
rich_text->clear();
- _add_text_to_rt(text, rich_text);
+ _add_text_to_rt(text, rich_text, this);
}
EditorHelpBit::EditorHelpBit() {
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 9f8da938f1..c9c1afb51b 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -153,6 +153,7 @@ class EditorHelp : public VBoxContainer {
//void _button_pressed(int p_idx);
void _add_type(const String &p_type, const String &p_enum = String());
+ void _add_type_icon(const String &p_type, int p_size = 0);
void _add_method(const DocData::MethodDoc &p_method, bool p_overview = true);
void _add_bulletpoint();
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 297d1226e3..af0cff9ad6 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -206,7 +206,7 @@ EditorHelpSearch::EditorHelpSearch() {
case_sensitive_button = memnew(Button);
case_sensitive_button->set_flat(true);
- case_sensitive_button->set_tooltip(TTR("Case Sensitive"));
+ case_sensitive_button->set_tooltip_text(TTR("Case Sensitive"));
case_sensitive_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results));
case_sensitive_button->set_toggle_mode(true);
case_sensitive_button->set_focus_mode(Control::FOCUS_NONE);
@@ -214,7 +214,7 @@ EditorHelpSearch::EditorHelpSearch() {
hierarchy_button = memnew(Button);
hierarchy_button->set_flat(true);
- hierarchy_button->set_tooltip(TTR("Show Hierarchy"));
+ hierarchy_button->set_tooltip_text(TTR("Show Hierarchy"));
hierarchy_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results));
hierarchy_button->set_toggle_mode(true);
hierarchy_button->set_pressed(true);
@@ -231,6 +231,7 @@ EditorHelpSearch::EditorHelpSearch() {
filter_combo->add_item(TTR("Methods Only"), SEARCH_METHODS);
filter_combo->add_item(TTR("Operators Only"), SEARCH_OPERATORS);
filter_combo->add_item(TTR("Signals Only"), SEARCH_SIGNALS);
+ filter_combo->add_item(TTR("Annotations Only"), SEARCH_ANNOTATIONS);
filter_combo->add_item(TTR("Constants Only"), SEARCH_CONSTANTS);
filter_combo->add_item(TTR("Properties Only"), SEARCH_PROPERTIES);
filter_combo->add_item(TTR("Theme Properties Only"), SEARCH_THEME_ITEMS);
@@ -339,8 +340,9 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
match.name = (term.is_empty() && (!class_doc.is_script_doc || class_doc.name[0] != '\"')) || _match_string(term, class_doc.name);
}
- // Match members if the term is long enough.
- if (term.length() > 1) {
+ // Match members only if the term is long enough, to avoid slow performance from building a large tree.
+ // Make an exception for annotations, since there are not that many of them.
+ if (term.length() > 1 || term == "@") {
if (search_flags & SEARCH_CONSTRUCTORS) {
for (int i = 0; i < class_doc.constructors.size(); i++) {
String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.constructors[i].name : class_doc.constructors[i].name.to_lower();
@@ -402,6 +404,13 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
}
}
}
+ if (search_flags & SEARCH_ANNOTATIONS) {
+ for (int i = 0; i < class_doc.annotations.size(); i++) {
+ if (_match_string(term, class_doc.annotations[i].name)) {
+ match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc.annotations[i]));
+ }
+ }
+ }
matches[class_doc.name] = match;
}
matches[class_doc.name] = match;
@@ -485,6 +494,10 @@ bool EditorHelpSearch::Runner::_phase_member_items() {
for (int i = 0; i < match.theme_properties.size(); i++) {
_create_theme_property_item(parent, match.doc, match.theme_properties[i]);
}
+ for (int i = 0; i < match.annotations.size(); i++) {
+ // Hide the redundant leading @ symbol.
+ _create_annotation_item(parent, match.doc, match.annotations[i]->name.substr(1), match.annotations[i]);
+ }
++iterator_match;
return !iterator_match;
@@ -523,6 +536,22 @@ void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_tex
}
}
+String EditorHelpSearch::Runner::_build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const {
+ String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "(";
+ for (int i = 0; i < p_doc->arguments.size(); i++) {
+ const DocData::ArgumentDoc &arg = p_doc->arguments[i];
+ tooltip += arg.type + " " + arg.name;
+ if (!arg.default_value.is_empty()) {
+ tooltip += " = " + arg.default_value;
+ }
+ if (i < p_doc->arguments.size() - 1) {
+ tooltip += ", ";
+ }
+ }
+ tooltip += ")";
+ return tooltip;
+}
+
TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_match) {
if (p_match.doc->name.is_empty()) {
return nullptr;
@@ -562,8 +591,8 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
item->set_icon(0, icon);
item->set_text(0, p_doc->name);
item->set_text(1, TTR("Class"));
- item->set_tooltip(0, tooltip);
- item->set_tooltip(1, tooltip);
+ item->set_tooltip_text(0, tooltip);
+ item->set_tooltip_text(1, tooltip);
item->set_metadata(0, "class_name:" + p_doc->name);
if (p_gray) {
item->set_custom_color(0, disabled_color);
@@ -576,37 +605,20 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
}
TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
- String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "(";
- for (int i = 0; i < p_doc->arguments.size(); i++) {
- const DocData::ArgumentDoc &arg = p_doc->arguments[i];
- tooltip += arg.type + " " + arg.name;
- if (!arg.default_value.is_empty()) {
- tooltip += " = " + arg.default_value;
- }
- if (i < p_doc->arguments.size() - 1) {
- tooltip += ", ";
- }
- }
- tooltip += ")";
+ String tooltip = _build_method_tooltip(p_class_doc, p_doc);
return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip);
}
TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) {
- String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "(";
- for (int i = 0; i < p_doc->arguments.size(); i++) {
- const DocData::ArgumentDoc &arg = p_doc->arguments[i];
- tooltip += arg.type + " " + arg.name;
- if (!arg.default_value.is_empty()) {
- tooltip += " = " + arg.default_value;
- }
- if (i < p_doc->arguments.size() - 1) {
- tooltip += ", ";
- }
- }
- tooltip += ")";
+ String tooltip = _build_method_tooltip(p_class_doc, p_doc);
return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip);
}
+TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
+ String tooltip = _build_method_tooltip(p_class_doc, p_doc);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip);
+}
+
TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) {
String tooltip = p_class_doc->name + "." + p_doc->name;
return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip);
@@ -639,8 +651,8 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons
item->set_icon(0, icon);
item->set_text(0, text);
item->set_text(1, TTRGET(p_type));
- item->set_tooltip(0, p_tooltip);
- item->set_tooltip(1, p_tooltip);
+ item->set_tooltip_text(0, p_tooltip);
+ item->set_tooltip_text(1, p_tooltip);
item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name);
_match_item(item, p_name);
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index 3f17c992ac..26abaec6e6 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -50,7 +50,8 @@ class EditorHelpSearch : public ConfirmationDialog {
SEARCH_CONSTANTS = 1 << 5,
SEARCH_PROPERTIES = 1 << 6,
SEARCH_THEME_ITEMS = 1 << 7,
- SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS,
+ SEARCH_ANNOTATIONS = 1 << 8,
+ SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS | SEARCH_ANNOTATIONS,
SEARCH_CASE_SENSITIVE = 1 << 29,
SEARCH_SHOW_HIERARCHY = 1 << 30
};
@@ -108,9 +109,10 @@ class EditorHelpSearch::Runner : public RefCounted {
Vector<DocData::ConstantDoc *> constants;
Vector<DocData::PropertyDoc *> properties;
Vector<DocData::ThemeItemDoc *> theme_properties;
+ Vector<DocData::MethodDoc *> annotations;
bool required() {
- return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size();
+ return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size() || annotations.size();
}
};
@@ -141,12 +143,15 @@ class EditorHelpSearch::Runner : public RefCounted {
bool _phase_member_items();
bool _phase_select_match();
+ String _build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const;
+
bool _match_string(const String &p_term, const String &p_string) const;
void _match_item(TreeItem *p_item, const String &p_text);
TreeItem *_create_class_hierarchy(const ClassMatch &p_match);
TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray);
TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc);
TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc);
+ TreeItem *_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc);
TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc);
TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc);
TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 2064b6f3a1..7bbdc16c61 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -231,7 +231,7 @@ void EditorProperty::_notification(int p_what) {
bottom_child_rect = bottom_rect;
}
- update(); //need to redraw text
+ queue_redraw(); //need to redraw text
} break;
case NOTIFICATION_DRAW: {
@@ -340,6 +340,8 @@ void EditorProperty::_notification(int p_what) {
draw_string(font, Point2(ofs, v_ofs + font->get_ascent(font_size)), label, HORIZONTAL_ALIGNMENT_LEFT, text_limit, font_size, color);
}
+ ofs = size.width;
+
if (keying) {
Ref<Texture2D> key;
@@ -349,7 +351,7 @@ void EditorProperty::_notification(int p_what) {
key = get_theme_icon(SNAME("Key"), SNAME("EditorIcons"));
}
- ofs = size.width - key->get_width() - get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
+ ofs -= key->get_width() + get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
Color color2(1, 1, 1);
if (keying_hover) {
@@ -373,7 +375,7 @@ void EditorProperty::_notification(int p_what) {
close = get_theme_icon(SNAME("Close"), SNAME("EditorIcons"));
- ofs = size.width - close->get_width() - get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
+ ofs -= close->get_width() + get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
Color color2(1, 1, 1);
if (delete_hover) {
@@ -396,7 +398,7 @@ void EditorProperty::_notification(int p_what) {
void EditorProperty::set_label(const String &p_label) {
label = p_label;
- update();
+ queue_redraw();
}
String EditorProperty::get_label() const {
@@ -432,11 +434,11 @@ bool EditorProperty::is_read_only() const {
}
Variant EditorPropertyRevert::get_property_revert_value(Object *p_object, const StringName &p_property, bool *r_is_valid) {
- if (p_object->has_method("property_can_revert") && p_object->call("property_can_revert", p_property)) {
+ if (p_object->property_can_revert(p_property)) {
if (r_is_valid) {
*r_is_valid = true;
}
- return p_object->call("property_get_revert", p_property);
+ return p_object->property_get_revert(p_property);
}
return PropertyUtils::get_property_default_value(p_object, p_property, r_is_valid);
@@ -476,7 +478,7 @@ void EditorProperty::update_revert_and_pin_status() {
}
can_revert = new_can_revert;
pinned = new_pinned;
- update();
+ queue_redraw();
}
}
@@ -497,7 +499,7 @@ bool EditorProperty::use_keying_next() const {
void EditorProperty::set_checkable(bool p_checkable) {
checkable = p_checkable;
- update();
+ queue_redraw();
queue_sort();
}
@@ -507,7 +509,7 @@ bool EditorProperty::is_checkable() const {
void EditorProperty::set_checked(bool p_checked) {
checked = p_checked;
- update();
+ queue_redraw();
}
bool EditorProperty::is_checked() const {
@@ -516,18 +518,18 @@ bool EditorProperty::is_checked() const {
void EditorProperty::set_draw_warning(bool p_draw_warning) {
draw_warning = p_draw_warning;
- update();
+ queue_redraw();
}
void EditorProperty::set_keying(bool p_keying) {
keying = p_keying;
- update();
+ queue_redraw();
queue_sort();
}
void EditorProperty::set_deletable(bool p_deletable) {
deletable = p_deletable;
- update();
+ queue_redraw();
queue_sort();
}
@@ -550,7 +552,7 @@ void EditorProperty::_focusable_focused(int p_index) {
bool already_selected = selected;
selected = true;
selected_focusable = p_index;
- update();
+ queue_redraw();
if (!already_selected && selected) {
emit_signal(SNAME("selected"), property, selected_focusable);
}
@@ -569,7 +571,7 @@ void EditorProperty::select(int p_focusable) {
focusables[p_focusable]->grab_focus();
} else {
selected = true;
- update();
+ queue_redraw();
}
if (!already_selected && selected) {
@@ -580,7 +582,7 @@ void EditorProperty::select(int p_focusable) {
void EditorProperty::deselect() {
selected = false;
selected_focusable = -1;
- update();
+ queue_redraw();
}
bool EditorProperty::is_selected() const {
@@ -606,25 +608,25 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
bool new_keying_hover = keying_rect.has_point(mpos) && !button_left;
if (new_keying_hover != keying_hover) {
keying_hover = new_keying_hover;
- update();
+ queue_redraw();
}
bool new_delete_hover = delete_rect.has_point(mpos) && !button_left;
if (new_delete_hover != delete_hover) {
delete_hover = new_delete_hover;
- update();
+ queue_redraw();
}
bool new_revert_hover = revert_rect.has_point(mpos) && !button_left;
if (new_revert_hover != revert_hover) {
revert_hover = new_revert_hover;
- update();
+ queue_redraw();
}
bool new_check_hover = check_rect.has_point(mpos) && !button_left;
if (new_check_hover != check_hover) {
check_hover = new_check_hover;
- update();
+ queue_redraw();
}
}
@@ -639,7 +641,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
if (!selected && selectable) {
selected = true;
emit_signal(SNAME("selected"), property, -1);
- update();
+ queue_redraw();
}
if (keying_rect.has_point(mpos)) {
@@ -679,7 +681,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
if (check_rect.has_point(mpos)) {
checked = !checked;
- update();
+ queue_redraw();
emit_signal(SNAME("property_checked"), property, checked);
}
} else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
@@ -894,14 +896,9 @@ static Control *make_help_bit(const String &p_text, bool p_property) {
}
Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
- tooltip_text = p_text;
return make_help_bit(p_text, true);
}
-String EditorProperty::get_tooltip_text() const {
- return tooltip_text;
-}
-
void EditorProperty::menu_option(int p_option) {
switch (p_option) {
case MENU_COPY_PROPERTY: {
@@ -915,7 +912,7 @@ void EditorProperty::menu_option(int p_option) {
} break;
case MENU_PIN_VALUE: {
emit_signal(SNAME("property_pinned"), property, !pinned);
- update();
+ queue_redraw();
} break;
case MENU_OPEN_DOCUMENTATION: {
ScriptEditor::get_singleton()->goto_help(doc_path);
@@ -949,7 +946,6 @@ void EditorProperty::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_edited_property"), &EditorProperty::get_edited_property);
ClassDB::bind_method(D_METHOD("get_edited_object"), &EditorProperty::get_edited_object);
- ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorProperty::get_tooltip_text);
ClassDB::bind_method(D_METHOD("update_property"), &EditorProperty::update_property);
ClassDB::bind_method(D_METHOD("add_focusable", "control"), &EditorProperty::add_focusable);
@@ -965,7 +961,7 @@ void EditorProperty::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keying"), "set_keying", "is_keying");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deletable"), "set_deletable", "is_deletable");
- ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
+ ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::STRING_NAME, "field"), PropertyInfo(Variant::BOOL, "changing")));
ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::PACKED_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value")));
ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING_NAME, "property")));
ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING_NAME, "property")));
@@ -1127,7 +1123,6 @@ void EditorInspectorCategory::_notification(int p_what) {
}
Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
- tooltip_text = p_text;
return make_help_bit(p_text, false);
}
@@ -1146,14 +1141,6 @@ Size2 EditorInspectorCategory::get_minimum_size() const {
return ms;
}
-void EditorInspectorCategory::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorInspectorCategory::get_tooltip_text);
-}
-
-String EditorInspectorCategory::get_tooltip_text() const {
- return tooltip_text;
-}
-
EditorInspectorCategory::EditorInspectorCategory() {
}
@@ -1385,26 +1372,26 @@ void EditorInspectorSection::_notification(int p_what) {
}
dropping = children_can_drop;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAG_END: {
dropping = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_ENTER: {
if (dropping) {
dropping_unfold_timer->start();
}
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
if (dropping) {
dropping_unfold_timer->stop();
}
- update();
+ queue_redraw();
} break;
}
}
@@ -1490,7 +1477,7 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
fold();
}
} else if (mb.is_valid() && !mb->is_pressed()) {
- update();
+ queue_redraw();
}
}
@@ -1507,7 +1494,7 @@ void EditorInspectorSection::unfold() {
object->editor_set_section_unfold(section, true);
vbox->show();
- update();
+ queue_redraw();
}
void EditorInspectorSection::fold() {
@@ -1521,7 +1508,7 @@ void EditorInspectorSection::fold() {
object->editor_set_section_unfold(section, false);
vbox->hide();
- update();
+ queue_redraw();
}
bool EditorInspectorSection::has_revertable_properties() const {
@@ -1536,7 +1523,7 @@ void EditorInspectorSection::property_can_revert_changed(const String &p_path, b
revertable_properties.erase(p_path);
}
if (has_revertable_properties() != had_revertable_properties) {
- update();
+ queue_redraw();
}
}
@@ -1701,7 +1688,7 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, p_element_index, p_to_pos };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, p_element_index, p_to_pos };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1845,7 +1832,7 @@ void EditorInspectorArray::_clear_array() {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1898,7 +1885,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, -1, -1 };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, -1, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1917,7 +1904,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -2064,9 +2051,9 @@ void EditorInspectorArray::_setup() {
ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
ae.panel->set_drag_forwarding(this);
ae.panel->set_meta("index", begin_array_index + i);
- ae.panel->set_tooltip(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
- ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
- ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
+ ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
+ ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
+ ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
ae.panel->connect("draw", callable_mp(this, &EditorInspectorArray::_panel_draw).bind(i));
ae.panel->connect("gui_input", callable_mp(this, &EditorInspectorArray::_panel_gui_input).bind(i));
ae.panel->add_theme_style_override(SNAME("panel"), i % 2 ? odd_style : even_style);
@@ -2168,7 +2155,7 @@ bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant
return false;
}
// First, update drawing.
- control_dropping->update();
+ control_dropping->queue_redraw();
if (p_data.get_type() != Variant::DICTIONARY) {
return false;
@@ -2219,14 +2206,14 @@ void EditorInspectorArray::_notification(int p_what) {
Dictionary dict = get_viewport()->gui_get_drag_data();
if (dict.has("type") && dict["type"] == "property_array_element" && String(dict["property_array_prefix"]) == array_element_prefix) {
dropping = true;
- control_dropping->update();
+ control_dropping->queue_redraw();
}
} break;
case NOTIFICATION_DRAG_END: {
if (dropping) {
dropping = false;
- control_dropping->update();
+ control_dropping->queue_redraw();
}
} break;
}
@@ -2240,7 +2227,7 @@ void EditorInspectorArray::_bind_methods() {
ADD_SIGNAL(MethodInfo("page_change_request"));
}
-void EditorInspectorArray::set_undo_redo(UndoRedo *p_undo_redo) {
+void EditorInspectorArray::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -2502,7 +2489,7 @@ Button *EditorInspector::create_inspector_action_button(const String &p_text) {
return button;
}
-void EditorInspector::set_undo_redo(UndoRedo *p_undo_redo) {
+void EditorInspector::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -2628,15 +2615,28 @@ void EditorInspector::update_tree() {
valid_plugins.push_back(inspector_plugins[i]);
}
- // Decide if properties should be drawn with the warning color (yellow).
+ // Decide if properties should be drawn with the warning color (yellow),
+ // or if the whole object should be considered read-only.
bool draw_warning = false;
+ bool all_read_only = false;
if (is_inside_tree()) {
+ if (object->has_method("_is_read_only")) {
+ all_read_only = object->call("_is_read_only");
+ }
+
Node *nod = Object::cast_to<Node>(object);
Node *es = EditorNode::get_singleton()->get_edited_scene();
if (nod && es != nod && nod->get_owner() != es) {
// Draw in warning color edited nodes that are not in the currently edited scene,
// as changes may be lost in the future.
draw_warning = true;
+ } else {
+ if (!all_read_only) {
+ Resource *res = Object::cast_to<Resource>(object);
+ if (res) {
+ all_read_only = EditorNode::get_singleton()->is_resource_read_only(res);
+ }
+ }
}
}
@@ -2662,7 +2662,7 @@ void EditorInspector::update_tree() {
_parse_added_editors(main_vbox, nullptr, ped);
}
- StringName type_name;
+ StringName doc_name;
// Get the lists of editors for properties.
for (List<PropertyInfo>::Element *E_property = plist.front(); E_property; E_property = E_property->next()) {
@@ -2711,6 +2711,11 @@ void EditorInspector::update_tree() {
continue;
}
+ // Hide the "MultiNodeEdit" category for MultiNodeEdit.
+ if (Object::cast_to<MultiNodeEdit>(object) && p.name == "MultiNodeEdit") {
+ continue;
+ }
+
// Iterate over remaining properties. If no properties in category, skip the category.
List<PropertyInfo>::Element *N = E_property->next();
bool valid = true;
@@ -2735,10 +2740,10 @@ void EditorInspector::update_tree() {
String type = p.name;
String label = p.name;
- type_name = p.name;
+ doc_name = p.name;
// Set the category icon.
- if (!ClassDB::class_exists(type) && !ScriptServer::is_global_class(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
+ if (!EditorNode::get_editor_data().is_type_recognized(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
// If we have a category inside a script, search for the first script with a valid icon.
Ref<Script> script = ResourceLoader::load(p.hint_string, "Script");
StringName base_type;
@@ -2746,6 +2751,10 @@ void EditorInspector::update_tree() {
if (script.is_valid()) {
base_type = script->get_instance_base_type();
name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ Vector<DocData::ClassDoc> docs = script->get_documentation();
+ if (!docs.is_empty()) {
+ doc_name = docs[0].name;
+ }
if (name != StringName() && label != name) {
label = name;
}
@@ -2753,10 +2762,16 @@ void EditorInspector::update_tree() {
while (script.is_valid()) {
name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
- if (name != StringName() && icon_path.length()) {
+ if (name != StringName() && !icon_path.is_empty()) {
category->icon = ResourceLoader::load(icon_path, "Texture");
break;
}
+
+ const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_path(script->get_path());
+ if (ctype) {
+ category->icon = ctype->icon;
+ break;
+ }
script = script->get_base_script();
}
if (category->icon.is_null() && has_theme_icon(base_type, SNAME("EditorIcons"))) {
@@ -2774,17 +2789,17 @@ void EditorInspector::update_tree() {
if (use_doc_hints) {
// Sets the category tooltip to show documentation.
- if (!class_descr_cache.has(type_name)) {
+ if (!class_descr_cache.has(doc_name)) {
String descr;
DocTools *dd = EditorHelp::get_doc_data();
- HashMap<String, DocData::ClassDoc>::Iterator E = dd->class_list.find(type_name);
+ HashMap<String, DocData::ClassDoc>::Iterator E = dd->class_list.find(doc_name);
if (E) {
descr = DTR(E->value.brief_description);
}
- class_descr_cache[type_name] = descr;
+ class_descr_cache[doc_name] = descr;
}
- category->set_tooltip(p.name + "::" + (class_descr_cache[type_name].is_empty() ? "" : class_descr_cache[type_name]));
+ category->set_tooltip_text(p.name + "::" + (class_descr_cache[doc_name].is_empty() ? "" : class_descr_cache[doc_name]));
}
// Add editors at the start of a category.
@@ -2815,6 +2830,11 @@ void EditorInspector::update_tree() {
continue;
}
+ if (p.name.begins_with("metadata/") && bool(object->call("_hide_metadata_from_inspector"))) {
+ // Hide metadata from inspector if required.
+ continue;
+ }
+
// Get the path for property.
String path = p.name;
@@ -2977,7 +2997,7 @@ void EditorInspector::update_tree() {
Color c = sscolor;
c.a /= level;
section->setup(acc_path, label, object, c, use_folding, section_depth);
- section->set_tooltip(tooltip);
+ section->set_tooltip_text(tooltip);
// Add editors at the start of a group.
for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
@@ -3082,9 +3102,11 @@ void EditorInspector::update_tree() {
// Build the doc hint, to use as tooltip.
// Get the class name.
- StringName classname = type_name == "" ? object->get_class_name() : type_name;
+ StringName classname = doc_name == "" ? object->get_class_name() : doc_name;
if (!object_class.is_empty()) {
classname = object_class;
+ } else if (Object::cast_to<MultiNodeEdit>(object)) {
+ classname = Object::cast_to<MultiNodeEdit>(object)->get_edited_class_name();
}
StringName propname = property_prefix + p.name;
@@ -3175,7 +3197,6 @@ void EditorInspector::update_tree() {
ep->property_usage = p.usage;
//and set label?
}
-
if (!editors[i].label.is_empty()) {
ep->set_label(editors[i].label);
} else {
@@ -3202,7 +3223,7 @@ void EditorInspector::update_tree() {
ep->set_checkable(checkable);
ep->set_checked(checked);
ep->set_keying(keying);
- ep->set_read_only(property_read_only);
+ ep->set_read_only(property_read_only || all_read_only);
ep->set_deletable(deletable_properties || p.name.begins_with("metadata/"));
}
@@ -3222,9 +3243,9 @@ void EditorInspector::update_tree() {
ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), CONNECT_DEFERRED);
ep->connect("object_id_selected", callable_mp(this, &EditorInspector::_object_id_selected), CONNECT_DEFERRED);
if (!doc_info.description.is_empty()) {
- ep->set_tooltip(property_prefix + p.name + "::" + doc_info.description);
+ ep->set_tooltip_text(property_prefix + p.name + "::" + doc_info.description);
} else {
- ep->set_tooltip(property_prefix + p.name);
+ ep->set_tooltip_text(property_prefix + p.name);
}
ep->set_doc_path(doc_info.path);
ep->update_property();
@@ -3239,7 +3260,7 @@ void EditorInspector::update_tree() {
}
}
- if (!hide_metadata) {
+ if (!hide_metadata && !object->call("_hide_metadata_from_inspector")) {
// Add 4px of spacing between the "Add Metadata" button and the content above it.
Control *spacer = memnew(Control);
spacer->set_custom_minimum_size(Size2(0, 4) * EDSCALE);
@@ -3249,6 +3270,9 @@ void EditorInspector::update_tree() {
add_md->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
add_md->connect(SNAME("pressed"), callable_mp(this, &EditorInspector::_show_add_meta_dialog));
main_vbox->add_child(add_md);
+ if (all_read_only) {
+ add_md->set_disabled(true);
+ }
}
// Get the lists of to add at the end.
@@ -3469,9 +3493,9 @@ void EditorInspector::_update_inspector_bg() {
n = n->get_parent();
}
count_subinspectors = MIN(15, count_subinspectors);
- add_theme_style_override("bg", get_theme_stylebox("sub_inspector_bg" + itos(count_subinspectors), SNAME("Editor")));
+ add_theme_style_override("panel", get_theme_stylebox("sub_inspector_bg" + itos(count_subinspectors), SNAME("Editor")));
} else {
- add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
}
}
void EditorInspector::set_sub_inspector(bool p_enable) {
@@ -3521,7 +3545,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
- if (!undo_redo || bool(object->call("_dont_undo_redo"))) {
+ if (!undo_redo.is_valid() || bool(object->call("_dont_undo_redo"))) {
object->set(p_name, p_value);
if (p_refresh_all) {
_edit_request_change(object, "");
@@ -3564,7 +3588,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
- Variant v_undo_redo = (Object *)undo_redo;
+ Variant v_undo_redo = undo_redo;
Variant v_object = object;
Variant v_name = p_name;
for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback().size(); i++) {
@@ -3740,7 +3764,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
Node *node = Object::cast_to<Node>(object);
ERR_FAIL_COND(!node);
- if (undo_redo) {
+ if (undo_redo.is_valid()) {
undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned);
undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
@@ -3943,16 +3967,22 @@ void EditorInspector::_add_meta_confirm() {
undo_redo->commit_action();
}
-void EditorInspector::_check_meta_name(String name) {
+void EditorInspector::_check_meta_name(const String &p_name) {
String error;
- if (name == "") {
- error = TTR("Metadata can't be empty.");
- } else if (!name.is_valid_identifier()) {
- error = TTR("Invalid metadata identifier.");
- } else if (object->has_meta(name)) {
- error = TTR("Metadata already exists.");
- } else if (name[0] == '_') {
+ if (p_name == "") {
+ error = TTR("Metadata name can't be empty.");
+ } else if (!p_name.is_valid_identifier()) {
+ error = TTR("Metadata name must be a valid identifier.");
+ } else if (object->has_meta(p_name)) {
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ error = vformat(TTR("Metadata with name \"%s\" already exists on \"%s\"."), p_name, node->get_name());
+ } else {
+ // This should normally never be reached, but the error is set just in case.
+ error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name, node->get_name());
+ }
+ } else if (p_name[0] == '_') {
error = TTR("Names starting with _ are reserved for editor-only metadata.");
}
@@ -3970,7 +4000,15 @@ void EditorInspector::_check_meta_name(String name) {
void EditorInspector::_show_add_meta_dialog() {
if (!add_meta_dialog) {
add_meta_dialog = memnew(ConfirmationDialog);
- add_meta_dialog->set_title(TTR("Add Metadata Property"));
+
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
+ } else {
+ // This should normally never be reached, but the title is set just in case.
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property"), node->get_name()));
+ }
+
VBoxContainer *vbc = memnew(VBoxContainer);
add_meta_dialog->add_child(vbc);
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -4022,7 +4060,6 @@ void EditorInspector::_bind_methods() {
EditorInspector::EditorInspector() {
object = nullptr;
- undo_redo = nullptr;
main_vbox = memnew(VBoxContainer);
main_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
main_vbox->add_theme_constant_override("separation", 0);
@@ -4045,7 +4082,7 @@ EditorInspector::EditorInspector() {
refresh_countdown = 0.33;
}
- ED_SHORTCUT("property_editor/copy_property", TTR("Copy Property"), KeyModifierMask::CMD | Key::C);
- ED_SHORTCUT("property_editor/paste_property", TTR("Paste Property"), KeyModifierMask::CMD | Key::V);
- ED_SHORTCUT("property_editor/copy_property_path", TTR("Copy Property Path"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::C);
+ ED_SHORTCUT("property_editor/copy_property", TTR("Copy Property"), KeyModifierMask::CMD_OR_CTRL | Key::C);
+ ED_SHORTCUT("property_editor/paste_property", TTR("Paste Property"), KeyModifierMask::CMD_OR_CTRL | Key::V);
+ ED_SHORTCUT("property_editor/copy_property_path", TTR("Copy Property Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
}
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index baba9ec1f4..d634eae23f 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -31,6 +31,7 @@
#ifndef EDITOR_INSPECTOR_H
#define EDITOR_INSPECTOR_H
+#include "editor/editor_undo_redo_manager.h"
#include "editor_property_name_processor.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
@@ -42,8 +43,6 @@
#include "scene/gui/spin_box.h"
#include "scene/gui/texture_rect.h"
-class UndoRedo;
-
class EditorPropertyRevert {
public:
static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true);
@@ -118,8 +117,6 @@ private:
Control *bottom_editor = nullptr;
PopupMenu *menu = nullptr;
- mutable String tooltip_text;
-
HashMap<StringName, Variant> cache;
GDVIRTUAL0(_update_property)
@@ -200,8 +197,6 @@ public:
void set_object_and_property(Object *p_object, const StringName &p_property);
virtual Control *make_custom_tooltip(const String &p_text) const override;
- String get_tooltip_text() const;
-
void set_draw_top_bg(bool p_draw) { draw_top_bg = p_draw; }
bool can_revert_to_default() const { return can_revert; }
@@ -255,18 +250,13 @@ class EditorInspectorCategory : public Control {
Ref<Texture2D> icon;
String label;
- mutable String tooltip_text;
-
protected:
void _notification(int p_what);
- static void _bind_methods();
public:
virtual Size2 get_minimum_size() const override;
virtual Control *make_custom_tooltip(const String &p_text) const override;
- String get_tooltip_text() const;
-
EditorInspectorCategory();
};
@@ -313,7 +303,7 @@ public:
class EditorInspectorArray : public EditorInspectorSection {
GDCLASS(EditorInspectorArray, EditorInspectorSection);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum Mode {
MODE_NONE,
@@ -408,7 +398,7 @@ protected:
static void _bind_methods();
public:
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "");
void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
@@ -448,7 +438,7 @@ public:
class EditorInspector : public ScrollContainer {
GDCLASS(EditorInspector, ScrollContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum {
MAX_PLUGINS = 1024
};
@@ -548,7 +538,7 @@ class EditorInspector : public ScrollContainer {
void _add_meta_confirm();
void _show_add_meta_dialog();
- void _check_meta_name(String name);
+ void _check_meta_name(const String &p_name);
protected:
static void _bind_methods();
@@ -562,7 +552,7 @@ public:
static EditorProperty *instantiate_property_editor(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);
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
String get_selected_path() const;
diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp
index cd8150d235..87da67fb05 100644
--- a/editor/editor_locale_dialog.cpp
+++ b/editor/editor_locale_dialog.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/check_button.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
@@ -492,7 +493,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
{
lang_code = memnew(LineEdit);
lang_code->set_max_length(3);
- lang_code->set_tooltip("Language");
+ lang_code->set_tooltip_text("Language");
vb_language->add_child(lang_code);
}
hb_locale->add_child(vb_language);
@@ -508,7 +509,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
{
script_code = memnew(LineEdit);
script_code->set_max_length(4);
- script_code->set_tooltip("Script");
+ script_code->set_tooltip_text("Script");
vb_script->add_child(script_code);
}
hb_locale->add_child(vb_script);
@@ -524,7 +525,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
{
country_code = memnew(LineEdit);
country_code->set_max_length(2);
- country_code->set_tooltip("Country");
+ country_code->set_tooltip_text("Country");
vb_country->add_child(country_code);
}
hb_locale->add_child(vb_country);
@@ -541,7 +542,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
variant_code = memnew(LineEdit);
variant_code->set_h_size_flags(Control::SIZE_EXPAND_FILL);
variant_code->set_placeholder("Variant");
- variant_code->set_tooltip("Variant");
+ variant_code->set_tooltip_text("Variant");
vb_variant->add_child(variant_code);
}
hb_locale->add_child(vb_variant);
diff --git a/editor/editor_locale_dialog.h b/editor/editor_locale_dialog.h
index 7a4828e83a..8ac642a038 100644
--- a/editor/editor_locale_dialog.h
+++ b/editor/editor_locale_dialog.h
@@ -40,7 +40,7 @@ class VBoxContainer;
class LineEdit;
class Tree;
class OptionButton;
-class UndoRedo;
+class EditorUndoRedoManager;
class EditorLocaleDialog : public ConfirmationDialog {
GDCLASS(EditorLocaleDialog, ConfirmationDialog);
@@ -63,7 +63,7 @@ class EditorLocaleDialog : public ConfirmationDialog {
Tree *script_list = nullptr;
Tree *cnt_list = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool locale_set = false;
bool updating_lists = false;
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 38cc85bb4e..6e6a898757 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -93,6 +93,12 @@ void EditorLog::_update_theme() {
collapse_button->set_icon(get_theme_icon(SNAME("CombineLines"), SNAME("EditorIcons")));
show_search_button->set_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+
+ theme_cache.error_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ theme_cache.error_icon = get_theme_icon(SNAME("Error"), SNAME("EditorIcons"));
+ theme_cache.warning_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ theme_cache.warning_icon = get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"));
+ theme_cache.message_color = get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.6);
}
void EditorLog::_notification(int p_what) {
@@ -125,7 +131,7 @@ void EditorLog::_save_state() {
Ref<ConfigFile> config;
config.instantiate();
// Load and amend existing config if it exists.
- config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
const String section = "editor_log";
for (const KeyValue<MessageType, LogFilter *> &E : type_filter_map) {
@@ -135,7 +141,7 @@ void EditorLog::_save_state() {
config->set_value(section, "collapse", collapse);
config->set_value(section, "show_search", search_box->is_visible());
- config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
}
void EditorLog::_load_state() {
@@ -143,7 +149,7 @@ void EditorLog::_load_state() {
Ref<ConfigFile> config;
config.instantiate();
- config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
// Run the below code even if config->load returns an error, since we want the defaults to be set even if the file does not exist yet.
const String section = "editor_log";
@@ -218,6 +224,10 @@ void EditorLog::set_tool_button(Button *p_tool_button) {
tool_button = p_tool_button;
}
+void EditorLog::register_undo_redo(UndoRedo *p_undo_redo) {
+ p_undo_redo->set_commit_notify_callback(_undo_redo_cbk, this);
+}
+
void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) {
EditorLog *self = static_cast<EditorLog *>(p_self);
self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR);
@@ -242,6 +252,11 @@ void EditorLog::_rebuild_log() {
}
void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
+ if (!is_inside_tree()) {
+ // The log will be built all at once when it enters the tree and has its theme items.
+ return;
+ }
+
// Only add the message to the log if it passes the filters.
bool filter_active = type_filter_map[p_message.type]->is_active();
String search_text = search_box->get_text();
@@ -264,22 +279,22 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
case MSG_TYPE_STD_RICH: {
} break;
case MSG_TYPE_ERROR: {
- log->push_color(get_theme_color(SNAME("error_color"), SNAME("Editor")));
- Ref<Texture2D> icon = get_theme_icon(SNAME("Error"), SNAME("EditorIcons"));
+ log->push_color(theme_cache.error_color);
+ Ref<Texture2D> icon = theme_cache.error_icon;
log->add_image(icon);
log->add_text(" ");
tool_button->set_icon(icon);
} break;
case MSG_TYPE_WARNING: {
- log->push_color(get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- Ref<Texture2D> icon = get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"));
+ log->push_color(theme_cache.warning_color);
+ Ref<Texture2D> icon = theme_cache.warning_icon;
log->add_image(icon);
log->add_text(" ");
tool_button->set_icon(icon);
} break;
case MSG_TYPE_EDITOR: {
// Distinguish editor messages from messages printed by the project
- log->push_color(get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.6));
+ log->push_color(theme_cache.message_color);
} break;
}
@@ -381,7 +396,7 @@ EditorLog::EditorLog() {
clear_button = memnew(Button);
clear_button->set_flat(true);
clear_button->set_focus_mode(FOCUS_NONE);
- clear_button->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::K));
+ clear_button->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::K));
clear_button->set_shortcut_context(this);
clear_button->connect("pressed", callable_mp(this, &EditorLog::_clear_request));
hb_tools->add_child(clear_button);
@@ -390,7 +405,7 @@ EditorLog::EditorLog() {
copy_button = memnew(Button);
copy_button->set_flat(true);
copy_button->set_focus_mode(FOCUS_NONE);
- copy_button->set_shortcut(ED_SHORTCUT("editor/copy_output", TTR("Copy Selection"), KeyModifierMask::CMD | Key::C));
+ copy_button->set_shortcut(ED_SHORTCUT("editor/copy_output", TTR("Copy Selection"), KeyModifierMask::CMD_OR_CTRL | Key::C));
copy_button->set_shortcut_context(this);
copy_button->connect("pressed", callable_mp(this, &EditorLog::_copy_request));
hb_tools->add_child(copy_button);
@@ -404,7 +419,7 @@ EditorLog::EditorLog() {
collapse_button = memnew(Button);
collapse_button->set_flat(true);
collapse_button->set_focus_mode(FOCUS_NONE);
- collapse_button->set_tooltip(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences."));
+ collapse_button->set_tooltip_text(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences."));
collapse_button->set_toggle_mode(true);
collapse_button->set_pressed(false);
collapse_button->connect("toggled", callable_mp(this, &EditorLog::_set_collapse));
@@ -416,7 +431,7 @@ EditorLog::EditorLog() {
show_search_button->set_focus_mode(FOCUS_NONE);
show_search_button->set_toggle_mode(true);
show_search_button->set_pressed(true);
- show_search_button->set_shortcut(ED_SHORTCUT("editor/open_search", TTR("Focus Search/Filter Bar"), KeyModifierMask::CMD | Key::F));
+ show_search_button->set_shortcut(ED_SHORTCUT("editor/open_search", TTR("Focus Search/Filter Bar"), KeyModifierMask::CMD_OR_CTRL | Key::F));
show_search_button->set_shortcut_context(this);
show_search_button->connect("toggled", callable_mp(this, &EditorLog::_set_search_visible));
hb_tools2->add_child(show_search_button);
@@ -452,8 +467,6 @@ EditorLog::EditorLog() {
add_error_handler(&eh);
current = Thread::get_caller_id();
-
- EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this);
}
void EditorLog::deinit() {
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 003a148b9b..43d7037414 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -41,6 +41,8 @@
#include "scene/gui/texture_button.h"
#include "scene/gui/texture_rect.h"
+class UndoRedo;
+
class EditorLog : public HBoxContainer {
GDCLASS(EditorLog, HBoxContainer);
@@ -67,6 +69,16 @@ private:
}
};
+ struct {
+ Color error_color;
+ Ref<Texture2D> error_icon;
+
+ Color warning_color;
+ Ref<Texture2D> warning_icon;
+
+ Color message_color;
+ } theme_cache;
+
// Encapsulates all data and functionality regarding filters.
struct LogFilter {
private:
@@ -83,7 +95,7 @@ private:
toggle_button->set_toggle_mode(true);
toggle_button->set_pressed(true);
toggle_button->set_text(itos(message_count));
- toggle_button->set_tooltip(TTR(p_tooltip));
+ toggle_button->set_tooltip_text(TTR(p_tooltip));
// Don't tint the icon even when in "pressed" state.
toggle_button->add_theme_color_override("icon_color_pressed", Color(1, 1, 1, 1));
toggle_button->set_focus_mode(FOCUS_NONE);
@@ -172,6 +184,7 @@ protected:
public:
void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD);
void set_tool_button(Button *p_tool_button);
+ void register_undo_redo(UndoRedo *p_undo_redo);
void deinit();
void clear();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index e7946f56da..1d2540f0fd 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -37,7 +37,7 @@
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/object/class_db.h"
#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
@@ -54,6 +54,7 @@
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
#include "scene/gui/link_button.h"
+#include "scene/gui/menu_bar.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/gui/panel_container.h"
@@ -104,6 +105,7 @@
#include "editor/editor_themes.h"
#include "editor/editor_toaster.h"
#include "editor/editor_translation_parser.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/export/editor_export.h"
#include "editor/export/export_template_manager.h"
#include "editor/export/project_export.h"
@@ -168,6 +170,7 @@
#include "editor/plugins/mesh_instance_3d_editor_plugin.h"
#include "editor/plugins/mesh_library_editor_plugin.h"
#include "editor/plugins/multimesh_editor_plugin.h"
+#include "editor/plugins/navigation_link_2d_editor_plugin.h"
#include "editor/plugins/navigation_polygon_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/occluder_instance_3d_editor_plugin.h"
@@ -214,6 +217,8 @@ EditorNode *EditorNode::singleton = nullptr;
static const String META_TEXT_TO_COPY = "text_to_copy";
void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
+ ERR_FAIL_COND_MSG(p_full_paths.size() != r_filenames.size(), vformat("disambiguate_filenames requires two string vectors of same length (%d != %d).", p_full_paths.size(), r_filenames.size()));
+
// Keep track of a list of "index sets," i.e. sets of indices
// within disambiguated_scene_names which contain the same name.
Vector<RBSet<int>> index_sets;
@@ -248,6 +253,10 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
full_path = full_path.substr(0, full_path.rfind("."));
}
+ // Normalize trailing slashes when normalizing directory names.
+ scene_name = scene_name.trim_suffix("/");
+ full_path = full_path.trim_suffix("/");
+
int scene_name_size = scene_name.size();
int full_path_size = full_path.size();
int difference = full_path_size - scene_name_size;
@@ -290,17 +299,23 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
// and the scene name first to remove extensions so that this
// comparison actually works.
String path = p_full_paths[E->get()];
+
+ // Get rid of file extensions and res:// prefixes.
+ if (scene_name.rfind(".") >= 0) {
+ scene_name = scene_name.substr(0, scene_name.rfind("."));
+ }
if (path.begins_with("res://")) {
path = path.substr(6);
}
if (path.rfind(".") >= 0) {
path = path.substr(0, path.rfind("."));
}
- if (scene_name.rfind(".") >= 0) {
- scene_name = scene_name.substr(0, scene_name.rfind("."));
- }
- // We can proceed iff the full path is longer than the scene name,
+ // Normalize trailing slashes when normalizing directory names.
+ scene_name = scene_name.trim_suffix("/");
+ path = path.trim_suffix("/");
+
+ // We can proceed if the full path is longer than the scene name,
// meaning that there is at least one more parent folder we can
// tack onto the name.
can_proceed = can_proceed || (path.size() - scene_name.size()) >= 1;
@@ -348,12 +363,11 @@ void EditorNode::_update_scene_tabs() {
icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node");
}
- int current = editor_data.get_edited_scene();
- bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
- DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), i);
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), Callable(), i);
}
if (show_rb && editor_data.get_scene_root_script(i).is_valid()) {
@@ -410,9 +424,6 @@ void EditorNode::_version_control_menu_option(int p_idx) {
case RUN_VCS_SETTINGS: {
VersionControlEditorPlugin::get_singleton()->popup_vcs_set_up_dialog(gui_base);
} break;
- case RUN_VCS_SHUT_DOWN: {
- VersionControlEditorPlugin::get_singleton()->shut_down();
- } break;
}
}
@@ -491,10 +502,10 @@ void EditorNode::_update_from_settings() {
}
RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape")));
- RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
+ RS::get_singleton()->camera_attributes_set_dof_blur_bokeh_shape(dof_shape);
RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality")));
bool dof_jitter = GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter");
- RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter);
+ RS::get_singleton()->camera_attributes_set_dof_blur_quality(dof_quality, dof_jitter);
RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit"));
bool glow_bicubic = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0;
@@ -510,13 +521,13 @@ void EditorNode::_update_from_settings() {
float sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale);
- uint32_t directional_shadow_size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
- uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
+ uint32_t directional_shadow_size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size");
+ uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits");
RS::get_singleton()->directional_shadow_atlas_set_size(directional_shadow_size, directional_shadow_16_bits);
- RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/positional_shadow/soft_shadow_filter_quality")));
+ RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality")));
RS::get_singleton()->positional_soft_shadow_filter_set_quality(shadows_quality);
- RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_filter_quality")));
+ RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality")));
RS::get_singleton()->directional_soft_shadow_filter_set_quality(directional_shadow_quality);
float probe_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed");
RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed);
@@ -543,6 +554,9 @@ void EditorNode::_update_from_settings() {
Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/2d/sdf/scale")));
scene_root->set_sdf_scale(sdf_scale);
+ Viewport::MSAA msaa = Viewport::MSAA(int(GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d")));
+ scene_root->set_msaa_2d(msaa);
+
float mesh_lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels");
scene_root->set_mesh_lod_threshold(mesh_lod_threshold);
@@ -552,8 +566,6 @@ void EditorNode::_update_from_settings() {
SceneTree *tree = get_tree();
tree->set_debug_collisions_color(GLOBAL_GET("debug/shapes/collision/shape_color"));
tree->set_debug_collision_contact_color(GLOBAL_GET("debug/shapes/collision/contact_color"));
- tree->set_debug_navigation_color(GLOBAL_GET("debug/shapes/navigation/geometry_color"));
- tree->set_debug_navigation_disabled_color(GLOBAL_GET("debug/shapes/navigation/disabled_geometry_color"));
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->set_debug_navigation_edge_connection_color(GLOBAL_GET("debug/shapes/navigation/edge_connection_color"));
@@ -596,15 +608,15 @@ void EditorNode::_notification(int p_what) {
opening_prev = false;
}
- bool unsaved_cache_changed = false;
- if (unsaved_cache != (saved_version != editor_data.get_undo_redo().get_version())) {
- unsaved_cache = (saved_version != editor_data.get_undo_redo().get_version());
- unsaved_cache_changed = true;
+ bool global_unsaved = get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY);
+ bool scene_or_global_unsaved = global_unsaved || get_undo_redo()->is_history_unsaved(editor_data.get_current_edited_scene_history_id());
+ if (unsaved_cache != scene_or_global_unsaved) {
+ unsaved_cache = scene_or_global_unsaved;
+ _update_title();
}
- if (last_checked_version != editor_data.get_undo_redo().get_version()) {
+ if (editor_data.is_scene_changed(-1)) {
_update_scene_tabs();
- last_checked_version = editor_data.get_undo_redo().get_version();
}
// Update the animation frame of the update spinner.
@@ -630,7 +642,7 @@ void EditorNode::_notification(int p_what) {
ResourceImporterTexture::get_singleton()->update_imports();
- if (settings_changed || unsaved_cache_changed) {
+ if (settings_changed) {
_update_title();
}
@@ -660,6 +672,7 @@ void EditorNode::_notification(int p_what) {
command_palette->register_shortcuts_as_command();
+ MessageQueue::get_singleton()->push_callable(callable_mp(this, &EditorNode::_begin_first_scan));
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -747,15 +760,10 @@ void EditorNode::_notification(int p_what) {
gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles")));
scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Content"), SNAME("EditorStyles")));
- bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
- scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles")));
- scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
+ tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer")));
- file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
+ main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
}
scene_tabs->set_max_tab_width(int(EDITOR_GET("interface/scene_tabs/maximum_width")) * EDSCALE);
@@ -783,6 +791,14 @@ void EditorNode::_notification(int p_what) {
_build_icon_type_cache();
+ if (write_movie_button->is_pressed()) {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadMovieMode"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonPressed"), SNAME("EditorStyles")));
+ } else {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
+ }
+
play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
@@ -803,16 +819,15 @@ void EditorNode::_notification(int p_what) {
dock_tab_move_right->set_icon(theme->get_icon(SNAME("Forward"), SNAME("EditorIcons")));
}
- PopupMenu *p = help_menu->get_popup();
- p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_SUGGEST_A_FEATURE), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_DOCS), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_QA), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SUGGEST_A_FEATURE), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")));
for (int i = 0; i < main_editor_buttons.size(); i++) {
main_editor_buttons.write[i]->add_theme_font_override("font", gui_base->get_theme_font(SNAME("main_button_font"), SNAME("EditorFonts")));
@@ -848,7 +863,7 @@ void EditorNode::_update_update_spinner() {
update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !update_continuously);
if (update_continuously) {
- update_spinner->set_tooltip(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it."));
+ update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it."));
// Use a different color for the update spinner when Update Continuously is enabled,
// as this feature should only be enabled for troubleshooting purposes.
@@ -858,7 +873,7 @@ void EditorNode::_update_update_spinner() {
update_spinner->set_self_modulate(
gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor")) * (dark_theme ? Color(1.1, 1.1, 1.1) : Color(4.25, 4.25, 4.25)));
} else {
- update_spinner->set_tooltip(TTR("Spins when the editor window redraws."));
+ update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws."));
update_spinner->set_self_modulate(Color(1, 1, 1));
}
@@ -1047,9 +1062,11 @@ void EditorNode::_sources_changed(bool p_exist) {
if (waiting_for_first_scan) {
waiting_for_first_scan = false;
+ Engine::get_singleton()->startup_benchmark_end_measure(); // editor_scan_and_reimport
+
// Reload the global shader variables, but this time
// loading textures, as they are now properly imported.
- RenderingServer::get_singleton()->global_shader_uniforms_load_settings(true);
+ RenderingServer::get_singleton()->global_shader_parameters_load_settings(true);
// Start preview thread now that it's safe.
if (!singleton->cmdline_export_mode) {
@@ -1059,8 +1076,16 @@ void EditorNode::_sources_changed(bool p_exist) {
_load_docks();
if (!defer_load_scene.is_empty()) {
+ Engine::get_singleton()->startup_benchmark_begin_measure("editor_load_scene");
load_scene(defer_load_scene);
defer_load_scene = "";
+ Engine::get_singleton()->startup_benchmark_end_measure();
+
+ if (use_startup_benchmark) {
+ Engine::get_singleton()->startup_dump(startup_benchmark_file);
+ startup_benchmark_file = String();
+ use_startup_benchmark = false;
+ }
}
}
}
@@ -1089,7 +1114,7 @@ void EditorNode::_scan_external_changes() {
}
}
- String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("project.godot");
+ String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().path_join("project.godot");
if (FileAccess::get_modified_time(project_settings_path) > ProjectSettings::get_singleton()->get_last_saved_time()) {
TreeItem *ti = disk_changed_list->create_item(r);
ti->set_text(0, "project.godot");
@@ -1131,7 +1156,6 @@ void EditorNode::_reload_modified_scenes() {
}
}
- get_undo_redo()->clear_history(false);
set_current_scene(current_idx);
_update_scene_tabs();
disk_changed->hide();
@@ -1244,7 +1268,9 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St
}
void EditorNode::save_resource(const Ref<Resource> &p_resource) {
- if (p_resource->get_path().is_resource_file()) {
+ // If the resource has been imported, ask the user to use a different path in order to save it.
+ String path = p_resource->get_path();
+ if (path.is_resource_file() && !FileAccess::exists(path + ".import")) {
save_resource_in_path(p_resource, p_resource->get_path());
} else {
save_resource_as(p_resource);
@@ -1254,11 +1280,18 @@ void EditorNode::save_resource(const Ref<Resource> &p_resource) {
void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path) {
{
String path = p_resource->get_path();
- int srpos = path.find("::");
- if (srpos != -1) {
- String base = path.substr(0, srpos);
- if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) {
- show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first."));
+ if (!path.is_resource_file()) {
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) {
+ show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first."));
+ return;
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ show_warning(TTR("This resource can't be saved because it was imported from another file. Make it unique first."));
return;
}
}
@@ -1299,7 +1332,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
file->set_current_file(p_resource->get_path().get_file());
} else {
if (extensions.size()) {
- String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
+ String resource_name_snake_case = p_resource->get_class().to_snake_case();
file->set_current_file("new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower());
} else {
file->set_current_file(String());
@@ -1316,7 +1349,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
} else if (preferred.size()) {
String existing;
if (extensions.size()) {
- String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore();
+ String resource_name_snake_case = p_resource->get_class().to_snake_case();
existing = "new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower();
}
file->set_current_path(existing);
@@ -1378,7 +1411,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) {
return;
}
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
Ref<ConfigFile> cf;
cf.instantiate();
@@ -1410,7 +1443,7 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) {
return;
}
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
Ref<ConfigFile> cf;
cf.instantiate();
@@ -1606,7 +1639,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
// Save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5.
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ cache_base = temp_path.path_join("resthumb-" + cache_base);
// Does not have it, try to load a cached thumbnail.
String file = cache_base + ".png";
@@ -1685,6 +1718,8 @@ int EditorNode::_save_external_resources() {
saved++;
}
+ get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY);
+
return saved;
}
@@ -1766,11 +1801,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
if (err == OK) {
scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_file));
- if (idx < 0 || idx == editor_data.get_edited_scene()) {
- set_current_version(editor_data.get_undo_redo().get_version());
- } else {
- editor_data.set_edited_scene_version(0, idx);
- }
+ editor_data.set_scene_as_saved(idx);
editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file));
editor_folding.save_scene_folding(scene, p_file);
@@ -1815,15 +1846,15 @@ void EditorNode::restart_editor() {
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
+ args.push_back(a);
+ }
+
args.push_back("--path");
args.push_back(ProjectSettings::get_singleton()->get_resource_path());
args.push_back("-e");
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
if (!to_reopen.is_empty()) {
args.push_back(to_reopen);
}
@@ -1862,12 +1893,9 @@ void EditorNode::_mark_unsaved_scenes() {
}
String path = node->get_scene_file_path();
- if (!(path.is_empty() || FileAccess::exists(path))) {
- if (i == editor_data.get_edited_scene()) {
- set_current_version(-1);
- } else {
- editor_data.set_edited_scene_version(-1, i);
- }
+ if (!path.is_empty() && !FileAccess::exists(path)) {
+ // Mark scene tab as unsaved if the file is gone.
+ get_undo_redo()->set_history_as_unsaved(editor_data.get_scene_history_id(i));
}
}
@@ -1942,6 +1970,21 @@ void EditorNode::_dialog_action(String p_file) {
}
} break;
+ case FILE_SAVE_AND_RUN_MAIN_SCENE: {
+ ProjectSettings::get_singleton()->set("application/run/main_scene", p_file);
+ ProjectSettings::get_singleton()->save();
+
+ if (file->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
+ _save_default_environment();
+ _save_scene_with_preview(p_file);
+ if ((bool)pick_main_scene->get_meta("from_native", false)) {
+ run_native->resume_run_native();
+ } else {
+ _run(false, p_file);
+ }
+ }
+ } break;
+
case FILE_EXPORT_MESH_LIBRARY: {
Ref<MeshLibrary> ml;
if (file_export_lib_merge->is_pressed() && FileAccess::exists(p_file)) {
@@ -2207,7 +2250,14 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
bool stay_in_script_editor_on_node_selected = bool(EDITOR_GET("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected"));
bool skip_main_plugin = false;
- String editable_warning; // None by default.
+ String editable_info; // None by default.
+ bool info_is_warning = false;
+
+ if (current_obj->has_method("_is_read_only")) {
+ if (current_obj->call("_is_read_only")) {
+ editable_info = TTR("This object is marked as read-only, so it's not editable.");
+ }
+ }
if (is_resource) {
Resource *current_res = Object::cast_to<Resource>(current_obj);
@@ -2221,16 +2271,25 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
int subr_idx = current_res->get_path().find("::");
if (subr_idx != -1) {
String base_path = current_res->get_path().substr(0, subr_idx);
- if (FileAccess::exists(base_path + ".import")) {
- editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ if (!base_path.is_resource_file()) {
+ if (FileAccess::exists(base_path + ".import")) {
+ if (get_edited_scene() && get_edited_scene()->get_scene_file_path() == base_path) {
+ info_is_warning = true;
+ }
+ editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ } else {
+ if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") {
+ editable_info = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it must be made inside the original scene.");
+ }
+ }
} else {
- if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") {
- editable_warning = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it won't be kept when saving the current scene.");
+ if (FileAccess::exists(base_path + ".import")) {
+ editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
}
}
} else if (current_res->get_path().is_resource_file()) {
if (FileAccess::exists(current_res->get_path() + ".import")) {
- editable_warning = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import.");
+ editable_info = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import.");
}
}
} else if (is_node) {
@@ -2254,7 +2313,8 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) {
String source_scene = get_edited_scene()->get_scene_file_path();
if (FileAccess::exists(source_scene + ".import")) {
- editable_warning = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ info_is_warning = true;
}
}
@@ -2262,7 +2322,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
Node *selected_node = nullptr;
if (current_obj->is_class("EditorDebuggerRemoteObject")) {
- editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow.");
+ editable_info = TTR("This is a remote object, so it's not editable.\nPlease read the documentation relevant to debugging to better understand this workflow.");
disable_folding = true;
} else if (current_obj->is_class("MultiNodeEdit")) {
Node *scene = get_edited_scene();
@@ -2297,7 +2357,10 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
InspectorDock::get_inspector_singleton()->update_tree();
}
- InspectorDock::get_singleton()->set_warning(editable_warning);
+ InspectorDock::get_singleton()->set_info(
+ info_is_warning ? TTR("Changes may be lost!") : TTR("This object is read-only."),
+ editable_info,
+ info_is_warning);
if (InspectorDock::get_inspector_singleton()->is_using_folding() == disable_folding) {
InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding);
@@ -2357,6 +2420,16 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
InspectorDock::get_singleton()->update(current_obj);
}
+void EditorNode::_write_movie_toggled(bool p_enabled) {
+ if (p_enabled) {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadMovieMode"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonPressed"), SNAME("EditorStyles")));
+ } else {
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles")));
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
+ }
+}
+
void EditorNode::_run(bool p_current, const String &p_custom) {
if (editor_run.get_status() == EditorRun::STATUS_PLAY) {
play_button->set_pressed(!_playing_edited);
@@ -2387,7 +2460,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
String run_filename;
- if (p_current || (editor_data.get_edited_scene_root() && !p_custom.is_empty() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) {
+ if ((p_current && p_custom.is_empty()) || (editor_data.get_edited_scene_root() && !p_custom.is_empty() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
@@ -2396,10 +2469,8 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
}
if (scene->get_scene_file_path().is_empty()) {
- current_menu_option = -1;
- _menu_option(FILE_SAVE_AS_SCENE);
- // Set the option to save and run so when the dialog is accepted, the scene runs.
current_menu_option = FILE_SAVE_AND_RUN;
+ _menu_option_confirm(FILE_SAVE_AS_SCENE, true);
file->set_title(TTR("Save scene before running..."));
return;
}
@@ -2414,6 +2485,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (!ensure_main_scene(false)) {
return;
}
+ run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", "");
}
if (bool(EDITOR_GET("run/auto_save/save_before_running"))) {
@@ -2450,15 +2522,19 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
emit_signal(SNAME("play_pressed"));
if (p_current) {
+ run_current_filename = run_filename;
play_scene_button->set_pressed(true);
play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ play_scene_button->set_tooltip_text(TTR("Reload the played scene."));
} else if (!p_custom.is_empty()) {
run_custom_filename = p_custom;
play_custom_scene_button->set_pressed(true);
play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ play_custom_scene_button->set_tooltip_text(TTR("Reload the played scene."));
} else {
play_button->set_pressed(true);
play_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ play_button->set_tooltip_text(TTR("Reload the played scene."));
}
stop_button->set_disabled(false);
@@ -2483,9 +2559,22 @@ void EditorNode::_run_native(const Ref<EditorExportPreset> &p_preset) {
}
}
+void EditorNode::_reset_play_buttons() {
+ play_button->set_pressed(false);
+ play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ play_button->set_tooltip_text(TTR("Play the project."));
+ play_scene_button->set_pressed(false);
+ play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
+ play_scene_button->set_tooltip_text(TTR("Play the edited scene."));
+ play_custom_scene_button->set_pressed(false);
+ play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
+ play_custom_scene_button->set_tooltip_text(TTR("Play a custom scene."));
+}
+
void EditorNode::_android_build_source_selected(const String &p_file) {
export_template_manager->install_android_template_from_file(p_file);
}
+
void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!p_confirmed) { // FIXME: this may be a hack.
current_menu_option = (MenuOptions)p_option;
@@ -2566,22 +2655,36 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT: {
if (!p_confirmed) {
tab_closing_idx = _next_unsaved_scene(false);
- _scene_tab_changed(tab_closing_idx);
+ if (tab_closing_idx == -1) {
+ tab_closing_idx = -2; // Only external resources are unsaved.
+ } else {
+ _scene_tab_changed(tab_closing_idx);
+ }
if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER || p_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
- Node *scene_root = editor_data.get_edited_scene_root(tab_closing_idx);
- if (scene_root) {
- String scene_filename = scene_root->get_scene_file_path();
+ if (tab_closing_idx == -2) {
if (p_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
save_confirmation->set_ok_button_text(TTR("Save & Reload"));
- save_confirmation->set_text(vformat(TTR("Save changes to '%s' before reloading?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ save_confirmation->set_text(TTR("Save modified resources before reloading?"));
} else {
save_confirmation->set_ok_button_text(TTR("Save & Quit"));
- save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ save_confirmation->set_text(TTR("Save modified resources before closing?"));
+ }
+ } else {
+ Node *scene_root = editor_data.get_edited_scene_root(tab_closing_idx);
+ if (scene_root) {
+ String scene_filename = scene_root->get_scene_file_path();
+ if (p_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
+ save_confirmation->set_ok_button_text(TTR("Save & Reload"));
+ save_confirmation->set_text(vformat(TTR("Save changes to '%s' before reloading?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ } else {
+ save_confirmation->set_ok_button_text(TTR("Save & Quit"));
+ save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
+ }
}
- save_confirmation->popup_centered();
- break;
}
+ save_confirmation->popup_centered();
+ break;
}
}
if (!editor_data.get_edited_scene_root(tab_closing_idx)) {
@@ -2669,10 +2772,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
// Use casing of the root node.
break;
case SCENE_NAME_CASING_PASCAL_CASE: {
- root_name = root_name.capitalize().replace(" ", "");
+ root_name = root_name.to_pascal_case();
} break;
case SCENE_NAME_CASING_SNAKE_CASE:
- root_name = root_name.capitalize().replace(" ", "").replace("-", "_").camelcase_to_underscore();
+ root_name = root_name.replace("-", "_").to_snake_case();
break;
}
file->set_current_path(root_name + "." + extensions.front()->get().to_lower());
@@ -2711,9 +2814,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo().get_current_action_name();
+ String action = editor_data.get_undo_redo()->get_current_action_name();
- if (!editor_data.get_undo_redo().undo()) {
+ if (!editor_data.get_undo_redo()->undo()) {
log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR);
} else if (!action.is_empty()) {
log->add_message(vformat(TTR("Undo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
@@ -2724,10 +2827,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- if (!editor_data.get_undo_redo().redo()) {
+ if (!editor_data.get_undo_redo()->redo()) {
log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo().get_current_action_name();
+ String action = editor_data.get_undo_redo()->get_current_action_name();
log->add_message(vformat(TTR("Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
}
}
@@ -2762,7 +2865,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
ERR_PRINT("Failed to load scene");
}
editor_data.move_edited_scene_to_index(cur_idx);
- get_undo_redo()->clear_history(false);
+ get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
scene_tabs->set_current_tab(cur_idx);
} break;
@@ -2777,7 +2880,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
quick_run->set_title(TTR("Quick Run Scene..."));
play_custom_scene_button->set_pressed(false);
} else {
- String last_custom_scene = run_custom_filename;
+ String last_custom_scene = run_custom_filename; // This is necessary to have a copy of the string.
run_play_custom(last_custom_scene);
}
@@ -2789,13 +2892,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
editor_run.stop();
run_custom_filename.clear();
- play_button->set_pressed(false);
- play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
- play_scene_button->set_pressed(false);
- play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
- play_custom_scene_button->set_pressed(false);
- play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
+ run_current_filename.clear();
stop_button->set_disabled(true);
+ _reset_play_buttons();
if (bool(EDITOR_GET("run/output/always_close_output_on_stop"))) {
for (int i = 0; i < bottom_panel_items.size(); i++) {
@@ -2818,7 +2917,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case RUN_PLAY_SCENE: {
- run_play_current();
+ if (run_current_filename.is_empty() || editor_run.get_status() == EditorRun::STATUS_STOP) {
+ run_play_current();
+ } else {
+ String last_current_scene = run_current_filename; // This is necessary to have a copy of the string.
+ run_play_custom(last_current_scene);
+ }
} break;
case RUN_SETTINGS: {
@@ -2846,14 +2950,14 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
} break;
case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: {
- OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().plus_file("android"));
+ OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().path_join("android"));
} break;
case FILE_QUIT:
case RUN_PROJECT_MANAGER:
case RELOAD_CURRENT_PROJECT: {
if (!p_confirmed) {
bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit");
- if (_next_unsaved_scene(!save_each) == -1) {
+ if (_next_unsaved_scene(!save_each) == -1 && !get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY)) {
_discard_changes();
break;
} else {
@@ -3003,14 +3107,14 @@ void EditorNode::_screenshot(bool p_use_utc) {
}
void EditorNode::_save_screenshot(NodePath p_path) {
- Control *editor_main_control = EditorInterface::get_singleton()->get_editor_main_control();
- ERR_FAIL_COND_MSG(!editor_main_control, "Cannot get editor main control.");
- Viewport *viewport = editor_main_control->get_viewport();
- ERR_FAIL_COND_MSG(!viewport, "Cannot get editor main control viewport.");
+ Control *editor_main_screen = EditorInterface::get_singleton()->get_editor_main_screen();
+ ERR_FAIL_COND_MSG(!editor_main_screen, "Cannot get the editor main screen control.");
+ Viewport *viewport = editor_main_screen->get_viewport();
+ ERR_FAIL_COND_MSG(!viewport, "Cannot get a viewport from the editor main screen.");
Ref<ViewportTexture> texture = viewport->get_texture();
- ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor main control viewport texture.");
+ ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get a viewport texture from the editor main screen.");
Ref<Image> img = texture->get_image();
- ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor main control viewport texture image.");
+ ERR_FAIL_COND_MSG(img.is_null(), "Cannot get an image from a viewport texture of the editor main screen.");
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
}
@@ -3075,8 +3179,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
if (!editor_data.get_edited_scene_root(i)) {
continue;
}
- int current = editor_data.get_edited_scene();
- bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
if (unsaved) {
String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path();
if (p_valid_filename && scene_filename.length() == 0) {
@@ -3162,8 +3265,15 @@ void EditorNode::_discard_changes(const String &p_str) {
String exec = OS::get_singleton()->get_executable_path();
List<String> args;
- args.push_back("--path");
- args.push_back(exec.get_base_dir());
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
+ args.push_back(a);
+ }
+
+ String exec_base_dir = exec.get_base_dir();
+ if (!exec_base_dir.is_empty()) {
+ args.push_back("--path");
+ args.push_back(exec_base_dir);
+ }
args.push_back("--project-manager");
Error err = OS::get_singleton()->create_instance(args);
@@ -3181,21 +3291,19 @@ void EditorNode::_update_file_menu_opened() {
Ref<Shortcut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene"));
- PopupMenu *pop = file_menu->get_popup();
- pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty());
+ file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty());
- const UndoRedo &undo_redo = editor_data.get_undo_redo();
- pop->set_item_disabled(pop->get_item_index(EDIT_UNDO), !undo_redo.has_undo());
- pop->set_item_disabled(pop->get_item_index(EDIT_REDO), !undo_redo.has_redo());
+ Ref<EditorUndoRedoManager> undo_redo = editor_data.get_undo_redo();
+ file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo->has_undo());
+ file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo->has_redo());
}
void EditorNode::_update_file_menu_closed() {
- PopupMenu *pop = file_menu->get_popup();
- pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), false);
+ file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), false);
}
-Control *EditorNode::get_main_control() {
- return main_control;
+VBoxContainer *EditorNode::get_main_screen_control() {
+ return main_screen_vbox;
}
void EditorNode::_editor_select(int p_which) {
@@ -3283,7 +3391,7 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed
singleton->main_editor_button_vb->add_child(tb);
singleton->editor_table.push_back(p_editor);
- singleton->distraction_free->raise();
+ singleton->distraction_free->move_to_front();
}
singleton->editor_data.add_editor_plugin(p_editor);
singleton->add_child(p_editor);
@@ -3383,7 +3491,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Only try to load the script if it has a name. Else, the plugin has no init script.
if (script_path.length() > 0) {
- script_path = addon_path.get_base_dir().plus_file(script_path);
+ script_path = addon_path.get_base_dir().path_join(script_path);
script = ResourceLoader::load(script_path);
if (script.is_null()) {
@@ -3443,7 +3551,6 @@ void EditorNode::_remove_edited_scene(bool p_change_tab) {
_scene_tab_changed(new_index);
}
editor_data.remove_scene(old_index);
- editor_data.get_undo_redo().clear_history(false);
_update_title();
_update_scene_tabs();
}
@@ -3499,7 +3606,6 @@ Dictionary EditorNode::_get_main_scene_state() {
state["main_tab"] = _get_current_main_editor();
state["scene_tree_offset"] = SceneTreeDock::get_singleton()->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value();
state["property_edit_offset"] = InspectorDock::get_inspector_singleton()->get_scroll_offset();
- state["saved_version"] = saved_version;
state["node_filter"] = SceneTreeDock::get_singleton()->get_filter();
return state;
}
@@ -3559,11 +3665,6 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
editor_data.notify_edited_scene_changed();
}
-void EditorNode::set_current_version(uint64_t p_version) {
- saved_version = p_version;
- editor_data.set_edited_scene_version(p_version);
-}
-
bool EditorNode::is_changing_scene() const {
return changing_scene;
}
@@ -3583,7 +3684,7 @@ void EditorNode::set_current_scene(int p_idx) {
editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx));
}
- call_deferred(SNAME("_clear_undo_history"));
+ get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx));
}
changing_scene = true;
@@ -3600,8 +3701,8 @@ void EditorNode::set_current_scene(int p_idx) {
Node *new_scene = editor_data.get_edited_scene_root();
- if (Object::cast_to<Popup>(new_scene)) {
- Object::cast_to<Popup>(new_scene)->show();
+ if (Popup *p = Object::cast_to<Popup>(new_scene)) {
+ p->show();
}
SceneTreeDock::get_singleton()->set_edited_scene(new_scene);
@@ -3619,6 +3720,7 @@ void EditorNode::set_current_scene(int p_idx) {
_edit_current(true);
_update_title();
+ _update_scene_tabs();
call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up.
}
@@ -3646,6 +3748,18 @@ void EditorNode::fix_dependencies(const String &p_for_file) {
int EditorNode::new_scene() {
int idx = editor_data.add_edited_scene(-1);
+ // Remove placeholder empty scene.
+ if (editor_data.get_edited_scene_count() > 1) {
+ for (int i = 0; i < editor_data.get_edited_scene_count() - 1; i++) {
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
+ if (!unsaved && editor_data.get_scene_path(i).is_empty()) {
+ editor_data.remove_scene(i);
+ idx--;
+ }
+ }
+ }
+ idx = MAX(idx, 0);
+
_scene_tab_changed(idx);
editor_data.clear_editor_states();
_update_scene_tabs();
@@ -3777,7 +3891,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
set_edited_scene(new_scene);
_get_scene_metadata(p_scene);
- saved_version = editor_data.get_undo_redo().get_version();
_update_title();
_update_scene_tabs();
_add_to_recent_scenes(lpath);
@@ -3820,6 +3933,37 @@ void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) {
InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource);
}
+bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
+ ERR_FAIL_COND_V(p_resource.is_null(), false);
+
+ String path = p_resource->get_path();
+ if (!path.is_resource_file()) {
+ // If the resource name contains '::', that means it is a subresource embedded in another resource.
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ // If the base resource is a packed scene, we treat it as read-only if it is not the currently edited scene.
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ return true;
+ }
+ } else {
+ // If a corresponding .import file exists for the base file, we assume it to be imported and should therefore treated as read-only.
+ if (FileAccess::exists(base + ".import")) {
+ return true;
+ }
+ }
+ }
+ } else {
+ // The resource is not a subresource, but if it has an .import file, it's imported so treat it as read only.
+ if (FileAccess::exists(path + ".import")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void EditorNode::request_instance_scene(const String &p_path) {
SceneTreeDock::get_singleton()->instantiate(p_path);
}
@@ -3828,6 +3972,10 @@ void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) {
SceneTreeDock::get_singleton()->instantiate_scenes(p_files);
}
+Ref<EditorUndoRedoManager> &EditorNode::get_undo_redo() {
+ return singleton->editor_data.get_undo_redo();
+}
+
void EditorNode::_inherit_request(String p_file) {
current_menu_option = FILE_NEW_INHERITED_SCENE;
_dialog_action(p_file);
@@ -3976,6 +4124,7 @@ void EditorNode::register_editor_types() {
GDREGISTER_CLASS(EditorSyntaxHighlighter);
GDREGISTER_ABSTRACT_CLASS(EditorInterface);
GDREGISTER_CLASS(EditorExportPlugin);
+ GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform);
GDREGISTER_CLASS(EditorResourceConversionPlugin);
GDREGISTER_CLASS(EditorSceneFormatImporter);
GDREGISTER_CLASS(EditorScenePostImportPlugin);
@@ -3988,6 +4137,7 @@ void EditorNode::register_editor_types() {
GDREGISTER_CLASS(EditorSpinSlider);
GDREGISTER_CLASS(EditorResourcePicker);
GDREGISTER_CLASS(EditorScriptPicker);
+ GDREGISTER_ABSTRACT_CLASS(EditorUndoRedoManager);
GDREGISTER_ABSTRACT_CLASS(FileSystemDock);
GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery);
@@ -4102,8 +4252,15 @@ void EditorNode::_pick_main_scene_custom_action(const String &p_custom_action_na
}
pick_main_scene->hide();
- current_menu_option = SETTINGS_PICK_MAIN_SCENE;
- _dialog_action(scene->get_scene_file_path());
+
+ if (!FileAccess::exists(scene->get_scene_file_path())) {
+ current_menu_option = FILE_SAVE_AND_RUN_MAIN_SCENE;
+ _menu_option_confirm(FILE_SAVE_AS_SCENE, true);
+ file->set_title(TTR("Save scene before running..."));
+ } else {
+ current_menu_option = SETTINGS_PICK_MAIN_SCENE;
+ _dialog_action(scene->get_scene_file_path());
+ }
}
}
@@ -4194,16 +4351,8 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
}
}
- const HashMap<String, Vector<EditorData::CustomType>> &p_map = EditorNode::get_editor_data().get_custom_types();
- for (const KeyValue<String, Vector<EditorData::CustomType>> &E : p_map) {
- const Vector<EditorData::CustomType> &ct = E.value;
- for (int i = 0; i < ct.size(); ++i) {
- if (ct[i].name == p_class) {
- if (ct[i].icon.is_valid()) {
- return ct[i].icon;
- }
- }
- }
+ if (const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_name(p_class)) {
+ return ctype->icon;
}
if (gui_base->has_theme_icon(p_class, SNAME("EditorIcons"))) {
@@ -4303,6 +4452,15 @@ void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog) {
Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
+void EditorNode::_begin_first_scan() {
+ Engine::get_singleton()->startup_benchmark_begin_measure("editor_scan_and_import");
+ EditorFileSystem::get_singleton()->scan();
+}
+void EditorNode::set_use_startup_benchmark(bool p_use_startup_benchmark, const String &p_startup_benchmark_file) {
+ use_startup_benchmark = p_use_startup_benchmark;
+ startup_benchmark_file = p_startup_benchmark_file;
+}
+
Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only) {
export_defer.preset = p_preset;
export_defer.path = p_path;
@@ -4444,7 +4602,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
}
if (nrect != dock_select_rect_over_idx) {
- dock_select->update();
+ dock_select->queue_redraw();
dock_select_rect_over_idx = nrect;
}
@@ -4470,7 +4628,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
dock_popup_selected_idx = nrect;
dock_slot[nrect]->set_current_tab(dock_slot[nrect]->get_tab_count() - 1);
dock_slot[nrect]->show();
- dock_select->update();
+ dock_select->queue_redraw();
_update_dock_containers();
@@ -4482,7 +4640,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
void EditorNode::_dock_popup_exit() {
dock_select_rect_over_idx = -1;
- dock_select->update();
+ dock_select->queue_redraw();
}
void EditorNode::_dock_pre_popup(int p_which) {
@@ -4500,7 +4658,7 @@ void EditorNode::_dock_move_left() {
}
dock_slot[dock_popup_selected_idx]->move_child(current, prev->get_index());
dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() - 1);
- dock_select->update();
+ dock_select->queue_redraw();
_edit_current();
_save_docks();
}
@@ -4513,7 +4671,7 @@ void EditorNode::_dock_move_right() {
}
dock_slot[dock_popup_selected_idx]->move_child(next, current->get_index());
dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() + 1);
- dock_select->update();
+ dock_select->queue_redraw();
_edit_current();
_save_docks();
}
@@ -4611,13 +4769,13 @@ void EditorNode::_save_docks() {
Ref<ConfigFile> config;
config.instantiate();
// Load and amend existing config if it exists.
- config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
_save_docks_to_config(config, "docks");
_save_open_scenes_to_config(config, "EditorNode");
editor_data.get_plugin_window_layout(config);
- config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
}
void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) {
@@ -4681,7 +4839,7 @@ void EditorNode::_dock_split_dragged(int ofs) {
void EditorNode::_load_docks() {
Ref<ConfigFile> config;
config.instantiate();
- Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
if (err != OK) {
// No config.
if (overridden_default_layout >= 0) {
@@ -4815,7 +4973,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
}
if (atidx == i) {
- node->raise();
+ node->move_to_front();
continue;
}
@@ -4914,7 +5072,7 @@ bool EditorNode::has_scenes_in_session() {
}
Ref<ConfigFile> config;
config.instantiate();
- Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
if (err != OK) {
return false;
}
@@ -4977,8 +5135,9 @@ void EditorNode::run_play_current() {
}
void EditorNode::run_play_custom(const String &p_custom) {
+ bool is_current = !run_current_filename.is_empty();
_menu_option_confirm(RUN_STOP, true);
- _run(false, p_custom);
+ _run(is_current, p_custom);
}
void EditorNode::run_stop() {
@@ -5113,9 +5272,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
return;
}
- bool unsaved = (p_tab == editor_data.get_edited_scene())
- ? saved_version != editor_data.get_undo_redo().get_version()
- : editor_data.get_scene_version(p_tab) != 0;
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab));
if (unsaved) {
save_confirmation->set_ok_button_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene"));
@@ -5227,23 +5384,10 @@ void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_p
void EditorNode::_scene_tab_changed(int p_tab) {
tab_preview_panel->hide();
- bool unsaved = (saved_version != editor_data.get_undo_redo().get_version());
-
if (p_tab == editor_data.get_edited_scene()) {
return; // Pointless.
}
-
- uint64_t next_scene_version = editor_data.get_scene_version(p_tab);
-
- editor_data.get_undo_redo().create_action(TTR("Switch Scene Tab"));
- editor_data.get_undo_redo().add_do_method(this, "set_current_version", unsaved ? saved_version : 0);
- editor_data.get_undo_redo().add_do_method(this, "set_current_scene", p_tab);
- editor_data.get_undo_redo().add_do_method(this, "set_current_version", next_scene_version == 0 ? editor_data.get_undo_redo().get_version() + 1 : next_scene_version);
-
- editor_data.get_undo_redo().add_undo_method(this, "set_current_version", next_scene_version);
- editor_data.get_undo_redo().add_undo_method(this, "set_current_scene", editor_data.get_edited_scene());
- editor_data.get_undo_redo().add_undo_method(this, "set_current_version", saved_version);
- editor_data.get_undo_redo().commit_action();
+ set_current_scene(p_tab);
}
Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) {
@@ -5254,7 +5398,7 @@ Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) {
tb->set_toggle_mode(true);
tb->set_focus_mode(Control::FOCUS_NONE);
bottom_panel_vb->add_child(p_item);
- bottom_panel_hb->raise();
+ bottom_panel_hb->move_to_front();
bottom_panel_hb_editors->add_child(tb);
p_item->set_v_size_flags(Control::SIZE_EXPAND_FILL);
p_item->hide();
@@ -5288,7 +5432,7 @@ void EditorNode::make_bottom_panel_item_visible(Control *p_item) {
void EditorNode::raise_bottom_panel_item(Control *p_item) {
for (int i = 0; i < bottom_panel_items.size(); i++) {
if (bottom_panel_items[i].control == p_item) {
- bottom_panel_items[i].button->raise();
+ bottom_panel_items[i].button->move_to_front();
SWAP(bottom_panel_items.write[i], bottom_panel_items.write[bottom_panel_items.size() - 1]);
break;
}
@@ -5336,7 +5480,7 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) {
// This is the debug panel which uses tabs, so the top section should be smaller.
bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), SNAME("EditorStyles")));
} else {
- bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
}
center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE);
center_split->set_collapsed(false);
@@ -5346,7 +5490,7 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) {
bottom_panel_raise->show();
} else {
- bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
bottom_panel_items[p_idx].button->set_pressed(false);
bottom_panel_items[p_idx].control->set_visible(false);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
@@ -5580,7 +5724,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
for (int i = 0; i < p_files.size(); i++) {
String from = p_files[i];
- String to = to_path.plus_file(from.get_file());
+ String to = to_path.path_join(from.get_file());
if (dir->dir_exists(from)) {
Vector<String> sub_files;
@@ -5595,7 +5739,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
continue;
}
- sub_files.push_back(from.plus_file(next_file));
+ sub_files.push_back(from.path_join(next_file));
next_file = sub_dir->get_next();
}
@@ -5629,7 +5773,7 @@ void EditorNode::reload_scene(const String &p_path) {
if (scene_idx == -1) {
if (get_edited_scene()) {
// Scene is not open, so at it might be instantiated. We'll refresh the whole scene later.
- editor_data.get_undo_redo().clear_history();
+ editor_data.get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
}
return;
}
@@ -5645,7 +5789,7 @@ void EditorNode::reload_scene(const String &p_path) {
// Adjust index so tab is back a the previous position.
editor_data.move_edited_scene_to_index(scene_idx);
- get_undo_redo()->clear_history();
+ get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(scene_idx));
// Recover the tab.
scene_tabs->set_current_tab(current_tab);
@@ -5823,13 +5967,13 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene);
ClassDB::bind_method("open_request", &EditorNode::open_request);
ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource);
+ ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only);
ClassDB::bind_method("_close_messages", &EditorNode::_close_messages);
ClassDB::bind_method("_show_messages", &EditorNode::_show_messages);
ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process);
ClassDB::bind_method("set_current_scene", &EditorNode::set_current_scene);
- ClassDB::bind_method("set_current_version", &EditorNode::set_current_version);
ClassDB::bind_method("_thumbnail_done", &EditorNode::_thumbnail_done);
ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state);
ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes);
@@ -6130,7 +6274,7 @@ EditorNode::EditorNode() {
rmp.instantiate();
EditorInspector::add_inspector_plugin(rmp);
- Ref<EditorInspectorShaderModePlugin> smp;
+ Ref<EditorInspectorVisualShaderModePlugin> smp;
smp.instantiate();
EditorInspector::add_inspector_plugin(smp);
}
@@ -6153,6 +6297,7 @@ EditorNode::EditorNode() {
add_child(editor_export);
// Exporters might need the theme.
+ EditorColorMap::create();
theme = create_custom_theme();
register_exporters();
@@ -6220,7 +6365,7 @@ EditorNode::EditorNode() {
main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 8);
main_vbox->add_theme_constant_override("separation", 8 * EDSCALE);
- menu_hb = memnew(HBoxContainer);
+ menu_hb = memnew(EditorTitleBar);
main_vbox->add_child(menu_hb);
left_l_hsplit = memnew(HSplitContainer);
@@ -6381,12 +6526,13 @@ EditorNode::EditorNode() {
tab_preview->set_position(Point2(2, 2) * EDSCALE);
tab_preview_panel->add_child(tab_preview);
+ tabbar_panel = memnew(PanelContainer);
+ tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer")));
+ srt->add_child(tabbar_panel);
tabbar_container = memnew(HBoxContainer);
- srt->add_child(tabbar_container);
+ tabbar_panel->add_child(tabbar_container);
scene_tabs = memnew(TabBar);
- scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles")));
- scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles")));
scene_tabs->set_select_with_rmb(true);
scene_tabs->add_tab("unsaved");
scene_tabs->set_tab_close_display_policy((TabBar::CloseButtonDisplayPolicy)EDITOR_GET("interface/scene_tabs/display_close_button").operator int());
@@ -6409,7 +6555,7 @@ EditorNode::EditorNode() {
scene_tab_add = memnew(Button);
scene_tab_add->set_flat(true);
- scene_tab_add->set_tooltip(TTR("Add a new scene."));
+ scene_tab_add->set_tooltip_text(TTR("Add a new scene."));
scene_tab_add->set_icon(gui_base->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
scene_tab_add->add_theme_color_override("icon_normal_color", Color(0.6f, 0.6f, 0.6f, 0.8f));
scene_tabs->add_child(scene_tab_add);
@@ -6422,10 +6568,10 @@ EditorNode::EditorNode() {
distraction_free = memnew(Button);
distraction_free->set_flat(true);
- ED_SHORTCUT_AND_COMMAND("editor/distraction_free_mode", TTR("Distraction Free Mode"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F11);
- ED_SHORTCUT_OVERRIDE("editor/distraction_free_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::D);
+ ED_SHORTCUT_AND_COMMAND("editor/distraction_free_mode", TTR("Distraction Free Mode"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F11);
+ ED_SHORTCUT_OVERRIDE("editor/distraction_free_mode", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::D);
distraction_free->set_shortcut(ED_GET_SHORTCUT("editor/distraction_free_mode"));
- distraction_free->set_tooltip(TTR("Toggle distraction-free mode."));
+ distraction_free->set_tooltip_text(TTR("Toggle distraction-free mode."));
distraction_free->connect("pressed", callable_mp(this, &EditorNode::_toggle_distraction_free_mode));
distraction_free->set_icon(gui_base->get_theme_icon(SNAME("DistractionFree"), SNAME("EditorIcons")));
distraction_free->set_toggle_mode(true);
@@ -6445,25 +6591,40 @@ EditorNode::EditorNode() {
scene_root->set_disable_input(true);
scene_root->set_as_audio_listener_2d(true);
- main_control = memnew(VBoxContainer);
- main_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- main_control->add_theme_constant_override("separation", 0);
- scene_root_parent->add_child(main_control);
+ main_screen_vbox = memnew(VBoxContainer);
+ main_screen_vbox->set_name("MainScreen");
+ main_screen_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_screen_vbox->add_theme_constant_override("separation", 0);
+ scene_root_parent->add_child(main_screen_vbox);
+
+ bool global_menu = !bool(EDITOR_GET("interface/editor/use_embedded_menu")) && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU);
+ bool can_expand = bool(EDITOR_GET("interface/editor/expand_to_title")) && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EXTEND_TO_TITLE);
+
+ if (can_expand) {
+ // Add spacer to avoid other controls under window minimize/maximize/close buttons (left side).
+ Control *menu_spacer = memnew(Control);
+ menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).x, 0));
+ menu_hb->add_child(menu_spacer);
+ }
- HBoxContainer *left_menu_hb = memnew(HBoxContainer);
- menu_hb->add_child(left_menu_hb);
+ main_menu = memnew(MenuBar);
+ menu_hb->add_child(main_menu);
+ main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
+ main_menu->set_flat(true);
+ main_menu->set_start_index(0); // Main menu, add to the start of global menu.
+ main_menu->set_prefer_global_menu(global_menu);
+ main_menu->set_switch_on_hover(true);
- file_menu = memnew(MenuButton);
- file_menu->set_flat(false);
- file_menu->set_switch_on_hover(true);
- file_menu->set_text(TTR("Scene"));
- file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(file_menu);
+ file_menu = memnew(PopupMenu);
+ file_menu->set_name(TTR("Scene"));
+ main_menu->add_child(file_menu);
+ main_menu->set_menu_tooltip(0, TTR("Operations with scene files."));
prev_scene = memnew(Button);
prev_scene->set_flat(true);
prev_scene->set_icon(gui_base->get_theme_icon(SNAME("PrevScene"), SNAME("EditorIcons")));
- prev_scene->set_tooltip(TTR("Go to previously opened scene."));
+ prev_scene->set_tooltip_text(TTR("Go to previously opened scene."));
prev_scene->set_disabled(true);
prev_scene->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(FILE_OPEN_PREV));
gui_base->add_child(prev_scene);
@@ -6520,92 +6681,82 @@ EditorNode::EditorNode() {
gui_base->add_child(warning);
warning->connect("custom_action", callable_mp(this, &EditorNode::_copy_warning));
- ED_SHORTCUT("editor/next_tab", TTR("Next Scene Tab"), KeyModifierMask::CMD + Key::TAB);
- ED_SHORTCUT("editor/prev_tab", TTR("Previous Scene Tab"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::TAB);
- ED_SHORTCUT("editor/filter_files", TTR("Focus FileSystem Filter"), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::P);
+ ED_SHORTCUT("editor/next_tab", TTR("Next Scene Tab"), KeyModifierMask::CMD_OR_CTRL + Key::TAB);
+ ED_SHORTCUT("editor/prev_tab", TTR("Previous Scene Tab"), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::TAB);
+ ED_SHORTCUT("editor/filter_files", TTR("Focus FileSystem Filter"), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::ALT + Key::P);
command_palette = EditorCommandPalette::get_singleton();
command_palette->set_title(TTR("Command Palette"));
gui_base->add_child(command_palette);
- PopupMenu *p;
-
- file_menu->set_tooltip(TTR("Operations with scene files."));
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_scene", TTR("New Scene"), KeyModifierMask::CMD_OR_CTRL + Key::N), FILE_NEW_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::N), FILE_NEW_INHERITED_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KeyModifierMask::CMD_OR_CTRL + Key::O), FILE_OPEN_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::T), FILE_OPEN_PREV);
+ file_menu->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
- p = file_menu->get_popup();
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD_OR_CTRL + Key::S), FILE_SAVE_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene_as", TTR("Save Scene As..."), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::S), FILE_SAVE_AS_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_all_scenes", TTR("Save All Scenes"), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::S), FILE_SAVE_ALL_SCENES);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_scene", TTR("New Scene"), KeyModifierMask::CMD + Key::N), FILE_NEW_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::N), FILE_NEW_INHERITED_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KeyModifierMask::CMD + Key::O), FILE_OPEN_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::T), FILE_OPEN_PREV);
- p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
+ file_menu->add_separator();
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD + Key::S), FILE_SAVE_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene_as", TTR("Save Scene As..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::S), FILE_SAVE_AS_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_all_scenes", TTR("Save All Scenes"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::S), FILE_SAVE_ALL_SCENES);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::O), FILE_QUICK_OPEN_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN_SCRIPT);
- p->add_separator();
-
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::O), FILE_QUICK_OPEN_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN_SCRIPT);
-
- p->add_separator();
+ file_menu->add_separator();
export_as_menu = memnew(PopupMenu);
export_as_menu->set_name("Export");
- p->add_child(export_as_menu);
- p->add_submenu_item(TTR("Export As..."), "Export");
+ file_menu->add_child(export_as_menu);
+ file_menu->add_submenu_item(TTR("Export As..."), "Export");
export_as_menu->add_shortcut(ED_SHORTCUT("editor/export_as_mesh_library", TTR("MeshLibrary...")), FILE_EXPORT_MESH_LIBRARY);
export_as_menu->connect("index_pressed", callable_mp(this, &EditorNode::_export_as_menu_option));
- p->add_separator();
- p->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true);
- p->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true);
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true);
+ file_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::W), FILE_CLOSE);
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::W), FILE_CLOSE);
recent_scenes = memnew(PopupMenu);
recent_scenes->set_name("RecentScenes");
- p->add_child(recent_scenes);
+ file_menu->add_child(recent_scenes);
recent_scenes->connect("id_pressed", callable_mp(this, &EditorNode::_open_recent_scene));
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD + Key::Q), FILE_QUIT, true);
-
- project_menu = memnew(MenuButton);
- project_menu->set_flat(false);
- project_menu->set_switch_on_hover(true);
- project_menu->set_tooltip(TTR("Miscellaneous project or scene-wide tools."));
- project_menu->set_text(TTR("Project"));
- project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(project_menu);
+ if (!global_menu || !OS::get_singleton()->has_feature("macos")) {
+ // On macOS "Quit" and "About" options are in the "app" menu.
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD_OR_CTRL + Key::Q), FILE_QUIT, true);
+ }
- p = project_menu->get_popup();
+ project_menu = memnew(PopupMenu);
+ project_menu->set_name(TTR("Project"));
+ main_menu->add_child(project_menu);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), Key::NONE, TTR("Project Settings")), RUN_SETTINGS);
- p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), Key::NONE, TTR("Project Settings")), RUN_SETTINGS);
+ project_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
vcs_actions_menu = VersionControlEditorPlugin::get_singleton()->get_version_control_actions_panel();
vcs_actions_menu->set_name("Version Control");
vcs_actions_menu->connect("index_pressed", callable_mp(this, &EditorNode::_version_control_menu_option));
- p->add_separator();
- p->add_child(vcs_actions_menu);
- p->add_submenu_item(TTR("Version Control"), "Version Control");
+ project_menu->add_separator();
+ project_menu->add_child(vcs_actions_menu);
+ project_menu->add_submenu_item(TTR("Version Control"), "Version Control");
vcs_actions_menu->add_item(TTR("Create Version Control Metadata"), RUN_VCS_METADATA);
- vcs_actions_menu->add_item(TTR("Set Up Version Control"), RUN_VCS_SETTINGS);
- vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN);
+ vcs_actions_menu->add_item(TTR("Version Control Settings"), RUN_VCS_SETTINGS);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT);
- p->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE);
- p->add_item(TTR("Open User Data Folder"), RUN_USER_DATA_FOLDER);
+ project_menu->add_separator();
+ project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT);
+ project_menu->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE);
+ project_menu->add_item(TTR("Open User Data Folder"), RUN_USER_DATA_FOLDER);
- p->add_separator();
- p->add_item(TTR("Customize Engine Build Configuration..."), TOOLS_BUILD_PROFILE_MANAGER);
- p->add_separator();
+ project_menu->add_separator();
+ project_menu->add_item(TTR("Customize Engine Build Configuration..."), TOOLS_BUILD_PROFILE_MANAGER);
+ project_menu->add_separator();
plugin_config_dialog = memnew(PluginConfigDialog);
plugin_config_dialog->connect("plugin_ready", callable_mp(this, &EditorNode::_on_plugin_ready));
@@ -6614,15 +6765,20 @@ EditorNode::EditorNode() {
tool_menu = memnew(PopupMenu);
tool_menu->set_name("Tools");
tool_menu->connect("index_pressed", callable_mp(this, &EditorNode::_tool_menu_option));
- p->add_child(tool_menu);
- p->add_submenu_item(TTR("Tools"), "Tools");
+ project_menu->add_child(tool_menu);
+ project_menu->add_submenu_item(TTR("Tools"), "Tools");
tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RELOAD_CURRENT_PROJECT);
- ED_SHORTCUT_AND_COMMAND("editor/quit_to_project_list", TTR("Quit to Project List"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::Q);
+ project_menu->add_separator();
+ project_menu->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RELOAD_CURRENT_PROJECT);
+ ED_SHORTCUT_AND_COMMAND("editor/quit_to_project_list", TTR("Quit to Project List"), KeyModifierMask::CTRL + KeyModifierMask::SHIFT + Key::Q);
ED_SHORTCUT_OVERRIDE("editor/quit_to_project_list", "macos", KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::Q);
- p->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
+ project_menu->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
+
+ // Spacer to center 2D / 3D / Script buttons.
+ Control *left_spacer = memnew(Control);
+ left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(left_spacer);
menu_hb->add_spacer();
@@ -6630,100 +6786,98 @@ EditorNode::EditorNode() {
menu_hb->add_child(main_editor_button_vb);
// Options are added and handled by DebuggerEditorPlugin.
- debug_menu = memnew(MenuButton);
- debug_menu->set_flat(false);
- debug_menu->set_switch_on_hover(true);
- debug_menu->set_text(TTR("Debug"));
- debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(debug_menu);
+ debug_menu = memnew(PopupMenu);
+ debug_menu->set_name(TTR("Debug"));
+ main_menu->add_child(debug_menu);
menu_hb->add_spacer();
- settings_menu = memnew(MenuButton);
- settings_menu->set_flat(false);
- settings_menu->set_switch_on_hover(true);
- settings_menu->set_text(TTR("Editor"));
- settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(settings_menu);
-
- p = settings_menu->get_popup();
+ settings_menu = memnew(PopupMenu);
+ settings_menu->set_name(TTR("Editor"));
+ main_menu->add_child(settings_menu);
ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings..."));
- ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::CMD + Key::COMMA);
- p->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES);
- p->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE);
- p->add_separator();
+ ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::META + Key::COMMA);
+ settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES);
+ settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE);
+ settings_menu->add_separator();
editor_layouts = memnew(PopupMenu);
editor_layouts->set_name("Layouts");
- p->add_child(editor_layouts);
+ settings_menu->add_child(editor_layouts);
editor_layouts->connect("id_pressed", callable_mp(this, &EditorNode::_layout_menu_option));
- p->add_submenu_item(TTR("Editor Layout"), "Layouts");
- p->add_separator();
+ settings_menu->add_submenu_item(TTR("Editor Layout"), "Layouts");
+ settings_menu->add_separator();
ED_SHORTCUT_AND_COMMAND("editor/take_screenshot", TTR("Take Screenshot"), KeyModifierMask::CTRL | Key::F12);
- ED_SHORTCUT_OVERRIDE("editor/take_screenshot", "macos", KeyModifierMask::CMD | Key::F12);
- p->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_SCREENSHOT);
+ ED_SHORTCUT_OVERRIDE("editor/take_screenshot", "macos", KeyModifierMask::META | Key::F12);
+ settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_SCREENSHOT);
- p->set_item_tooltip(-1, TTR("Screenshots are stored in the Editor Data/Settings Folder."));
+ settings_menu->set_item_tooltip(-1, TTR("Screenshots are stored in the Editor Data/Settings Folder."));
ED_SHORTCUT_AND_COMMAND("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KeyModifierMask::SHIFT | Key::F11);
- ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::F);
- p->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN);
+ ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::F);
+ settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN);
- p->add_separator();
+ settings_menu->add_separator();
if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) {
// Configuration and data folders are located in the same place (Windows/MacOS).
- p->add_item(TTR("Open Editor Data/Settings Folder"), SETTINGS_EDITOR_DATA_FOLDER);
+ settings_menu->add_item(TTR("Open Editor Data/Settings Folder"), SETTINGS_EDITOR_DATA_FOLDER);
} else {
// Separate configuration and data folders (Linux).
- p->add_item(TTR("Open Editor Data Folder"), SETTINGS_EDITOR_DATA_FOLDER);
- p->add_item(TTR("Open Editor Settings Folder"), SETTINGS_EDITOR_CONFIG_FOLDER);
+ settings_menu->add_item(TTR("Open Editor Data Folder"), SETTINGS_EDITOR_DATA_FOLDER);
+ settings_menu->add_item(TTR("Open Editor Settings Folder"), SETTINGS_EDITOR_CONFIG_FOLDER);
}
- p->add_separator();
+ settings_menu->add_separator();
- p->add_item(TTR("Manage Editor Features..."), SETTINGS_MANAGE_FEATURE_PROFILES);
- p->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES);
+ settings_menu->add_item(TTR("Manage Editor Features..."), SETTINGS_MANAGE_FEATURE_PROFILES);
+ settings_menu->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES);
- help_menu = memnew(MenuButton);
- help_menu->set_flat(false);
- help_menu->set_switch_on_hover(true);
- help_menu->set_text(TTR("Help"));
- help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(help_menu);
+ help_menu = memnew(PopupMenu);
+ help_menu->set_name(TTR("Help"));
+ main_menu->add_child(help_menu);
- p = help_menu->get_popup();
- p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
ED_SHORTCUT_AND_COMMAND("editor/editor_help", TTR("Search Help"), Key::F1);
ED_SHORTCUT_OVERRIDE("editor/editor_help", "macos", KeyModifierMask::ALT | Key::SPACE);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_GET_SHORTCUT("editor/editor_help"), HELP_SEARCH);
- p->add_separator();
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/online_docs", TTR("Online Documentation")), HELP_DOCS);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/q&a", TTR("Questions & Answers")), HELP_QA);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/community", TTR("Community")), HELP_COMMUNITY);
- p->add_separator();
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/about", TTR("About Godot")), HELP_ABOUT);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT);
-
- HBoxContainer *play_hb = memnew(HBoxContainer);
- menu_hb->add_child(play_hb);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_GET_SHORTCUT("editor/editor_help"), HELP_SEARCH);
+ help_menu->add_separator();
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/online_docs", TTR("Online Documentation")), HELP_DOCS);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/q&a", TTR("Questions & Answers")), HELP_QA);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/community", TTR("Community")), HELP_COMMUNITY);
+ help_menu->add_separator();
+ if (!global_menu || !OS::get_singleton()->has_feature("macos")) {
+ // On macOS "Quit" and "About" options are in the "app" menu.
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/about", TTR("About Godot")), HELP_ABOUT);
+ }
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT);
+
+ // Spacer to center 2D / 3D / Script buttons.
+ Control *right_spacer = memnew(Control);
+ right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(right_spacer);
+
+ launch_pad = memnew(PanelContainer);
+ launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles")));
+ menu_hb->add_child(launch_pad);
+
+ HBoxContainer *launch_pad_hb = memnew(HBoxContainer);
+ launch_pad->add_child(launch_pad_hb);
play_button = memnew(Button);
play_button->set_flat(true);
- play_hb->add_child(play_button);
+ launch_pad_hb->add_child(play_button);
play_button->set_toggle_mode(true);
- play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY));
- play_button->set_tooltip(TTR("Play the project."));
ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::CMD | Key::B);
+ ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::META | Key::B);
play_button->set_shortcut(ED_GET_SHORTCUT("editor/play"));
pause_button = memnew(Button);
@@ -6731,69 +6885,72 @@ EditorNode::EditorNode() {
pause_button->set_toggle_mode(true);
pause_button->set_icon(gui_base->get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
pause_button->set_focus_mode(Control::FOCUS_NONE);
- pause_button->set_tooltip(TTR("Pause the scene execution for debugging."));
+ pause_button->set_tooltip_text(TTR("Pause the scene execution for debugging."));
pause_button->set_disabled(true);
- play_hb->add_child(pause_button);
+ launch_pad_hb->add_child(pause_button);
ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), Key::F7);
- ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::Y);
+ ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_scene"));
stop_button = memnew(Button);
stop_button->set_flat(true);
- play_hb->add_child(stop_button);
+ launch_pad_hb->add_child(stop_button);
stop_button->set_focus_mode(Control::FOCUS_NONE);
stop_button->set_icon(gui_base->get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_STOP));
- stop_button->set_tooltip(TTR("Stop the scene."));
+ stop_button->set_tooltip_text(TTR("Stop the scene."));
stop_button->set_disabled(true);
ED_SHORTCUT("editor/stop", TTR("Stop"), Key::F8);
- ED_SHORTCUT_OVERRIDE("editor/stop", "macos", KeyModifierMask::CMD | Key::PERIOD);
+ ED_SHORTCUT_OVERRIDE("editor/stop", "macos", KeyModifierMask::META | Key::PERIOD);
stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop"));
run_native = memnew(EditorRunNative);
- play_hb->add_child(run_native);
+ launch_pad_hb->add_child(run_native);
run_native->connect("native_run", callable_mp(this, &EditorNode::_run_native));
play_scene_button = memnew(Button);
play_scene_button->set_flat(true);
- play_hb->add_child(play_scene_button);
+ launch_pad_hb->add_child(play_scene_button);
play_scene_button->set_toggle_mode(true);
play_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE));
- play_scene_button->set_tooltip(TTR("Play the edited scene."));
ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), Key::F6);
- ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::CMD | Key::R);
+ ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::META | Key::R);
play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_scene"));
play_custom_scene_button = memnew(Button);
play_custom_scene_button->set_flat(true);
- play_hb->add_child(play_custom_scene_button);
+ launch_pad_hb->add_child(play_custom_scene_button);
play_custom_scene_button->set_toggle_mode(true);
play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE));
- play_custom_scene_button->set_tooltip(TTR("Play custom scene"));
- ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::R);
+ _reset_play_buttons();
+
+ ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5);
+ ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene"));
+ write_movie_panel = memnew(PanelContainer);
+ write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles")));
+ launch_pad_hb->add_child(write_movie_panel);
+
write_movie_button = memnew(Button);
write_movie_button->set_flat(true);
write_movie_button->set_toggle_mode(true);
- play_hb->add_child(write_movie_button);
+ write_movie_panel->add_child(write_movie_button);
write_movie_button->set_pressed(false);
write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons")));
write_movie_button->set_focus_mode(Control::FOCUS_NONE);
- write_movie_button->set_tooltip(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file."));
+ write_movie_button->connect("toggled", callable_mp(this, &EditorNode::_write_movie_toggled));
+ write_movie_button->set_tooltip_text(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file."));
// This button behaves differently, so color it as such.
write_movie_button->add_theme_color_override("icon_normal_color", Color(1, 1, 1, 0.7));
- write_movie_button->add_theme_color_override("icon_pressed_color", gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ write_movie_button->add_theme_color_override("icon_pressed_color", Color(0, 0, 0, 0.84));
write_movie_button->add_theme_color_override("icon_hover_color", Color(1, 1, 1, 0.9));
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
@@ -6813,6 +6970,14 @@ EditorNode::EditorNode() {
right_menu_hb->add_child(rendering_driver);
+ if (can_expand) {
+ // Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side).
+ Control *menu_spacer = memnew(Control);
+ menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).y, 0));
+ menu_hb->add_child(menu_spacer);
+ }
+
// Only display the render drivers that are available for this display driver.
int display_driver_idx = OS::get_singleton()->get_display_driver_id();
Vector<String> render_drivers = DisplayServer::get_create_function_rendering_drivers(display_driver_idx);
@@ -6857,7 +7022,7 @@ EditorNode::EditorNode() {
right_menu_hb->add_child(update_spinner);
update_spinner->set_icon(gui_base->get_theme_icon(SNAME("Progress1"), SNAME("EditorIcons")));
update_spinner->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
- p = update_spinner->get_popup();
+ PopupMenu *p = update_spinner->get_popup();
p->add_radio_check_item(TTR("Update Continuously"), SETTINGS_UPDATE_CONTINUOUSLY);
p->add_radio_check_item(TTR("Update When Changed"), SETTINGS_UPDATE_WHEN_CHANGED);
p->add_separator();
@@ -6932,7 +7097,7 @@ EditorNode::EditorNode() {
// Bottom panels.
bottom_panel = memnew(PanelContainer);
- bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
center_split->add_child(bottom_panel);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
@@ -6968,7 +7133,7 @@ EditorNode::EditorNode() {
// Fade out the version label to be less prominent, but still readable.
version_btn->set_self_modulate(Color(1, 1, 1, 0.65));
version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
- version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->set_tooltip_text(TTR("Click to copy."));
version_btn->connect("pressed", callable_mp(this, &EditorNode::_version_button_pressed));
version_info_vbc->add_child(version_btn);
@@ -7077,11 +7242,11 @@ EditorNode::EditorNode() {
gui_base->add_child(file_script);
file_script->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
- file_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ file_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
file_menu->connect("about_to_popup", callable_mp(this, &EditorNode::_update_file_menu_opened));
- file_menu->get_popup()->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed));
+ file_menu->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed));
- settings_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ settings_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
file->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
file_templates->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
@@ -7189,6 +7354,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(GPUParticles2DEditorPlugin));
add_editor_plugin(memnew(LightOccluder2DEditorPlugin));
add_editor_plugin(memnew(Line2DEditorPlugin));
+ add_editor_plugin(memnew(NavigationLink2DEditorPlugin));
add_editor_plugin(memnew(NavigationPolygonEditorPlugin));
add_editor_plugin(memnew(Path2DEditorPlugin));
add_editor_plugin(memnew(Polygon2DEditorPlugin));
@@ -7229,7 +7395,7 @@ EditorNode::EditorNode() {
canvas_item_mat_convert.instantiate();
resource_conversion_plugins.push_back(canvas_item_mat_convert);
- Ref<ParticlesMaterialConversionPlugin> particles_mat_convert;
+ Ref<ParticleProcessMaterialConversionPlugin> particles_mat_convert;
particles_mat_convert.instantiate();
resource_conversion_plugins.push_back(particles_mat_convert);
@@ -7262,11 +7428,6 @@ EditorNode::EditorNode() {
editor_plugins_force_over = memnew(EditorPluginList);
editor_plugins_force_input_forwarding = memnew(EditorPluginList);
- Ref<EditorExportTextSceneToBinaryPlugin> export_text_to_binary_plugin;
- export_text_to_binary_plugin.instantiate();
-
- EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin);
-
Ref<GDExtensionExportPlugin> gdextension_export_plugin;
gdextension_export_plugin.instantiate();
@@ -7364,11 +7525,22 @@ EditorNode::EditorNode() {
screenshot_timer = memnew(Timer);
screenshot_timer->set_one_shot(true);
- screenshot_timer->set_wait_time(settings_menu->get_popup()->get_submenu_popup_delay() + 0.1f);
+ screenshot_timer->set_wait_time(settings_menu->get_submenu_popup_delay() + 0.1f);
screenshot_timer->connect("timeout", callable_mp(this, &EditorNode::_request_screenshot));
add_child(screenshot_timer);
screenshot_timer->set_owner(get_owner());
+ // Adjust spacers to center 2D / 3D / Script buttons.
+ int max_w = MAX(launch_pad_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
+ left_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - main_menu->get_minimum_size().x), 0));
+ right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
+
+ // Extend menu bar to window title.
+ if (can_expand) {
+ DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID);
+ menu_hb->set_can_move_window(true);
+ }
+
String exec = OS::get_singleton()->get_executable_path();
// Save editor executable path for third-party tools.
EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 0201e84eaf..df3d2ae0f8 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -35,6 +35,7 @@
#include "editor/editor_folding.h"
#include "editor/editor_native_shader_source_visualizer.h"
#include "editor/editor_run.h"
+#include "editor/editor_title_bar.h"
#include "editor/export/editor_export.h"
#include "editor/inspector_dock.h"
@@ -72,12 +73,14 @@ class EditorRun;
class EditorRunNative;
class EditorSettingsDialog;
class EditorToaster;
+class EditorUndoRedoManager;
class ExportTemplateManager;
class FileDialog;
class FileSystemDock;
class HSplitContainer;
class ImportDock;
class LinkButton;
+class MenuBar;
class MenuButton;
class NodeDock;
class OrphanResourcesDialog;
@@ -141,6 +144,7 @@ private:
FILE_SAVE_AS_SCENE,
FILE_SAVE_ALL_SCENES,
FILE_SAVE_AND_RUN,
+ FILE_SAVE_AND_RUN_MAIN_SCENE,
FILE_SHOW_IN_FILESYSTEM,
FILE_EXPORT_PROJECT,
FILE_EXPORT_MESH_LIBRARY,
@@ -181,7 +185,6 @@ private:
RUN_PROJECT_MANAGER,
RUN_VCS_METADATA,
RUN_VCS_SETTINGS,
- RUN_VCS_SHUT_DOWN,
SETTINGS_UPDATE_CONTINUOUSLY,
SETTINGS_UPDATE_WHEN_CHANGED,
SETTINGS_UPDATE_ALWAYS,
@@ -319,26 +322,29 @@ private:
HBoxContainer *bottom_hb = nullptr;
Control *vp_base = nullptr;
- HBoxContainer *menu_hb = nullptr;
- Control *main_control = nullptr;
- MenuButton *file_menu = nullptr;
- MenuButton *project_menu = nullptr;
- MenuButton *debug_menu = nullptr;
- MenuButton *settings_menu = nullptr;
- MenuButton *help_menu = nullptr;
+ EditorTitleBar *menu_hb = nullptr;
+ VBoxContainer *main_screen_vbox = nullptr;
+ MenuBar *main_menu = nullptr;
+ PopupMenu *file_menu = nullptr;
+ PopupMenu *project_menu = nullptr;
+ PopupMenu *debug_menu = nullptr;
+ PopupMenu *settings_menu = nullptr;
+ PopupMenu *help_menu = nullptr;
PopupMenu *tool_menu = nullptr;
PopupMenu *export_as_menu = nullptr;
Button *export_button = nullptr;
Button *prev_scene = nullptr;
+ Button *search_button = nullptr;
+ TextureProgressBar *audio_vu = nullptr;
+
+ PanelContainer *launch_pad = nullptr;
Button *play_button = nullptr;
Button *pause_button = nullptr;
Button *stop_button = nullptr;
- Button *run_settings_button = nullptr;
Button *play_scene_button = nullptr;
Button *play_custom_scene_button = nullptr;
- Button *search_button = nullptr;
+ PanelContainer *write_movie_panel = nullptr;
Button *write_movie_button = nullptr;
- TextureProgressBar *audio_vu = nullptr;
Timer *screenshot_timer = nullptr;
@@ -421,6 +427,7 @@ private:
int dock_popup_selected_idx = -1;
int dock_select_rect_over_idx = -1;
+ PanelContainer *tabbar_panel = nullptr;
HBoxContainer *tabbar_container = nullptr;
Button *distraction_free = nullptr;
Button *scene_tab_add = nullptr;
@@ -466,10 +473,9 @@ private:
String _tmp_import_path;
String external_file;
String open_navigate;
- String run_custom_filename;
- uint64_t saved_version = 1;
- uint64_t last_checked_version = 0;
+ String run_custom_filename;
+ String run_current_filename;
DynamicFontImportSettings *fontdata_import_settings = nullptr;
SceneImportSettings *scene_import_settings = nullptr;
@@ -577,8 +583,11 @@ private:
void _quick_run();
void _open_command_palette();
+ void _write_movie_toggled(bool p_enabled);
+
void _run(bool p_current = false, const String &p_custom = "");
void _run_native(const Ref<EditorExportPreset> &p_preset);
+ void _reset_play_buttons();
void _add_to_recent_scenes(const String &p_scene);
void _update_recent_scenes();
@@ -679,6 +688,10 @@ private:
void _bottom_panel_switch(bool p_enable, int p_idx);
void _bottom_panel_raise_toggled(bool);
+ void _begin_first_scan();
+ bool use_startup_benchmark = false;
+ String startup_benchmark_file;
+
protected:
friend class FileSystemDock;
@@ -702,7 +715,7 @@ public:
static EditorLog *get_log() { return singleton->log; }
static EditorData &get_editor_data() { return singleton->editor_data; }
static EditorFolding &get_editor_folding() { return singleton->editor_folding; }
- static UndoRedo *get_undo_redo() { return &singleton->editor_data.get_undo_redo(); }
+ static Ref<EditorUndoRedoManager> &get_undo_redo();
static HBoxContainer *get_menu_hb() { return singleton->menu_hb; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
@@ -771,9 +784,11 @@ public:
void open_request(const String &p_path);
void edit_foreign_resource(Ref<Resource> p_resource);
+ bool is_resource_read_only(Ref<Resource> p_resource);
+
bool is_changing_scene() const;
- Control *get_main_control();
+ VBoxContainer *get_main_screen_control();
SubViewport *get_scene_root() { return scene_root; } // Root of the scene being edited.
void set_edited_scene(Node *p_scene);
@@ -786,7 +801,6 @@ public:
bool is_scene_open(const String &p_path);
- void set_current_version(uint64_t p_version);
void set_current_scene(int p_idx);
void setup_color_picker(ColorPicker *picker);
@@ -813,6 +827,7 @@ public:
void _copy_warning(const String &p_str);
+ void set_use_startup_benchmark(bool p_use_startup_benchmark, const String &p_startup_benchmark_file);
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only);
Control *get_gui_base() { return gui_base; }
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index dc77b5fea9..d1f41dad84 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_data.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/multi_node_edit.h"
void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
if (p_depth > 8) {
@@ -72,7 +73,7 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
int index = sub_objects_menu->get_item_count();
sub_objects_menu->add_icon_item(icon, proper_name, objects.size());
- sub_objects_menu->set_item_horizontal_offset(index, p_depth * 10 * EDSCALE);
+ sub_objects_menu->set_item_indent(index, p_depth);
objects.push_back(obj->get_instance_id());
_add_children_to_popup(obj, p_depth + 1);
@@ -80,6 +81,11 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
}
void EditorPath::_show_popup() {
+ if (sub_objects_menu->is_visible()) {
+ sub_objects_menu->hide();
+ return;
+ }
+
sub_objects_menu->clear();
Size2 size = get_size();
@@ -116,14 +122,22 @@ void EditorPath::update_path() {
continue;
}
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
+ Ref<Texture2D> icon;
+ if (Object::cast_to<MultiNodeEdit>(obj)) {
+ icon = EditorNode::get_singleton()->get_class_icon(Object::cast_to<MultiNodeEdit>(obj)->get_edited_class_name());
+ } else {
+ icon = EditorNode::get_singleton()->get_object_icon(obj);
+ }
+
if (icon.is_valid()) {
current_object_icon->set_texture(icon);
}
if (i == history->get_path_size() - 1) {
String name;
- if (Object::cast_to<Resource>(obj)) {
+ if (obj->has_method("_get_editor_name")) {
+ name = obj->call("_get_editor_name");
+ } else if (Object::cast_to<Resource>(obj)) {
Resource *r = Object::cast_to<Resource>(obj);
if (r->get_path().is_resource_file()) {
name = r->get_path().get_file();
@@ -144,24 +158,24 @@ void EditorPath::update_path() {
name = obj->get_class();
}
- current_object_label->set_text(" " + name); // An extra space so the text is not too close of the icon.
- set_tooltip(obj->get_class());
+ current_object_label->set_text(name);
+ set_tooltip_text(obj->get_class());
}
}
}
void EditorPath::clear_path() {
set_disabled(true);
- set_tooltip("");
+ set_tooltip_text("");
current_object_label->set_text("");
current_object_icon->set_texture(nullptr);
- sub_objects_icon->set_visible(false);
+ sub_objects_icon->hide();
}
void EditorPath::enable_path() {
set_disabled(false);
- sub_objects_icon->set_visible(true);
+ sub_objects_icon->show();
}
void EditorPath::_id_pressed(int p_idx) {
@@ -181,7 +195,7 @@ void EditorPath::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
update_path();
- sub_objects_icon->set_texture(get_theme_icon(SNAME("select_arrow"), SNAME("Tree")));
+ sub_objects_icon->set_texture(get_theme_icon(SNAME("arrow"), SNAME("OptionButton")));
current_object_label->add_theme_font_override("font", get_theme_font(SNAME("main"), SNAME("EditorFonts")));
} break;
@@ -211,13 +225,12 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) {
main_hb->add_child(current_object_icon);
current_object_label = memnew(Label);
- current_object_label->set_clip_text(true);
- current_object_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT);
+ current_object_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
current_object_label->set_h_size_flags(SIZE_EXPAND_FILL);
main_hb->add_child(current_object_label);
sub_objects_icon = memnew(TextureRect);
- sub_objects_icon->set_visible(false);
+ sub_objects_icon->hide();
sub_objects_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
main_hb->add_child(sub_objects_icon);
@@ -226,5 +239,5 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) {
sub_objects_menu->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show));
sub_objects_menu->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed));
- set_tooltip(TTR("Open a list of sub-resources."));
+ set_tooltip_text(TTR("Open a list of sub-resources."));
}
diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp
index b6364e1ab7..54d4660cb6 100644
--- a/editor/editor_paths.cpp
+++ b/editor/editor_paths.cpp
@@ -67,19 +67,19 @@ String EditorPaths::get_self_contained_file() const {
}
String EditorPaths::get_export_templates_dir() const {
- return get_data_dir().plus_file(export_templates_folder);
+ return get_data_dir().path_join(export_templates_folder);
}
String EditorPaths::get_project_settings_dir() const {
- return get_project_data_dir().plus_file("editor");
+ return get_project_data_dir().path_join("editor");
}
String EditorPaths::get_text_editor_themes_dir() const {
- return get_config_dir().plus_file(text_editor_themes_folder);
+ return get_config_dir().path_join(text_editor_themes_folder);
}
String EditorPaths::get_script_templates_dir() const {
- return get_config_dir().plus_file(script_templates_folder);
+ return get_config_dir().path_join(script_templates_folder);
}
String EditorPaths::get_project_script_templates_dir() const {
@@ -87,7 +87,7 @@ String EditorPaths::get_project_script_templates_dir() const {
}
String EditorPaths::get_feature_profiles_dir() const {
- return get_config_dir().plus_file(feature_profiles_folder);
+ return get_config_dir().path_join(feature_profiles_folder);
}
void EditorPaths::create() {
@@ -119,8 +119,8 @@ EditorPaths::EditorPaths() {
String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
// On macOS, look outside .app bundle, since .app bundle is read-only.
- if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.plus_file("..").simplify_path().ends_with("Contents")) {
- exe_path = exe_path.plus_file("../../..").simplify_path();
+ if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.path_join("..").simplify_path().ends_with("Contents")) {
+ exe_path = exe_path.path_join("../../..").simplify_path();
}
{
Ref<DirAccess> d = DirAccess::create_for_path(exe_path);
@@ -141,24 +141,24 @@ EditorPaths::EditorPaths() {
if (self_contained) {
// editor is self contained, all in same folder
data_path = exe_path;
- data_dir = data_path.plus_file("editor_data");
+ data_dir = data_path.path_join("editor_data");
config_path = exe_path;
config_dir = data_dir;
cache_path = exe_path;
- cache_dir = data_dir.plus_file("cache");
+ cache_dir = data_dir.path_join("cache");
} else {
// Typically XDG_DATA_HOME or %APPDATA%.
data_path = OS::get_singleton()->get_data_path();
- data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ data_dir = data_path.path_join(OS::get_singleton()->get_godot_dir_name());
// Can be different from data_path e.g. on Linux or macOS.
config_path = OS::get_singleton()->get_config_path();
- config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ config_dir = config_path.path_join(OS::get_singleton()->get_godot_dir_name());
// Can be different from above paths, otherwise a subfolder of data_dir.
cache_path = OS::get_singleton()->get_cache_path();
if (cache_path == data_path) {
- cache_dir = data_dir.plus_file("cache");
+ cache_dir = data_dir.path_join("cache");
} else {
- cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ cache_dir = cache_path.path_join(OS::get_singleton()->get_godot_dir_name());
}
}
@@ -232,7 +232,7 @@ EditorPaths::EditorPaths() {
}
// Check that the project data directory '.gdignore' file exists
- String project_data_gdignore_file_path = project_data_dir.plus_file(".gdignore");
+ String project_data_gdignore_file_path = project_data_dir.path_join(".gdignore");
if (!FileAccess::exists(project_data_gdignore_file_path)) {
// Add an empty .gdignore file to avoid scan.
Ref<FileAccess> f = FileAccess::open(project_data_gdignore_file_path, FileAccess::WRITE);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 566c22f5a9..f3ac8f4ba0 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_paths.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/export/editor_export.h"
#include "editor/filesystem_dock.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
@@ -47,7 +48,7 @@
#include "scene/gui/popup_menu.h"
#include "servers/rendering_server.h"
-Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_size) {
+TypedArray<Texture2D> EditorInterface::_make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size) {
Vector<Ref<Mesh>> meshes;
for (int i = 0; i < p_meshes.size(); i++) {
@@ -55,7 +56,7 @@ Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_
}
Vector<Ref<Texture2D>> textures = make_mesh_previews(meshes, nullptr, p_preview_size);
- Array ret;
+ TypedArray<Texture2D> ret;
for (int i = 0; i < textures.size(); i++) {
ret.push_back(textures[i]);
}
@@ -155,8 +156,8 @@ void EditorInterface::set_main_screen_editor(const String &p_name) {
EditorNode::get_singleton()->select_editor_by_name(p_name);
}
-Control *EditorInterface::get_editor_main_control() {
- return EditorNode::get_singleton()->get_main_control();
+VBoxContainer *EditorInterface::get_editor_main_screen() {
+ return EditorNode::get_singleton()->get_main_screen_control();
}
void EditorInterface::edit_resource(const Ref<Resource> &p_resource) {
@@ -215,8 +216,8 @@ Node *EditorInterface::get_edited_scene_root() {
return EditorNode::get_singleton()->get_edited_scene();
}
-Array EditorInterface::get_open_scenes() const {
- Array ret;
+PackedStringArray EditorInterface::get_open_scenes() const {
+ PackedStringArray ret;
Vector<EditorData::EditedScene> scenes = EditorNode::get_editor_data().get_edited_scenes();
int scns_amount = scenes.size();
@@ -312,6 +313,13 @@ void EditorInterface::set_distraction_free_mode(bool p_enter) {
EditorNode::get_singleton()->set_distraction_free_mode(p_enter);
}
+void EditorInterface::restart_editor(bool p_save) {
+ if (p_save) {
+ EditorNode::get_singleton()->save_all_scenes();
+ }
+ EditorNode::get_singleton()->restart_editor();
+}
+
bool EditorInterface::is_distraction_free_mode_enabled() const {
return EditorNode::get_singleton()->is_distraction_free_mode_enabled();
}
@@ -344,7 +352,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &EditorInterface::get_edited_scene_root);
ClassDB::bind_method(D_METHOD("get_resource_previewer"), &EditorInterface::get_resource_previewer);
ClassDB::bind_method(D_METHOD("get_resource_filesystem"), &EditorInterface::get_resource_file_system);
- ClassDB::bind_method(D_METHOD("get_editor_main_control"), &EditorInterface::get_editor_main_control);
+ ClassDB::bind_method(D_METHOD("get_editor_main_screen"), &EditorInterface::get_editor_main_screen);
ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews);
ClassDB::bind_method(D_METHOD("select_file", "file"), &EditorInterface::select_file);
ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path);
@@ -360,6 +368,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene);
ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("restart_editor", "save"), &EditorInterface::restart_editor, DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor);
ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode);
@@ -445,7 +454,7 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C
CanvasItemEditor::get_singleton()->get_bottom_split()->add_child(p_control);
} break;
- case CONTAINER_PROPERTY_EDITOR_BOTTOM: {
+ case CONTAINER_INSPECTOR_BOTTOM: {
InspectorDock::get_singleton()->get_addon_area()->add_child(p_control);
} break;
@@ -498,7 +507,7 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
CanvasItemEditor::get_singleton()->get_bottom_split()->remove_child(p_control);
} break;
- case CONTAINER_PROPERTY_EDITOR_BOTTOM: {
+ case CONTAINER_INSPECTOR_BOTTOM: {
InspectorDock::get_singleton()->get_addon_area()->remove_child(p_control);
} break;
@@ -590,7 +599,7 @@ int EditorPlugin::update_overlays() const {
return count;
} else {
// This will update the normal viewport itself as well
- CanvasItemEditor::get_singleton()->get_viewport_control()->update();
+ CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw();
return 1;
}
}
@@ -885,7 +894,7 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_bottom_panel_item_visible", "item"), &EditorPlugin::make_bottom_panel_item_visible);
ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel);
- ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::_get_undo_redo);
+ ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::get_undo_redo);
ClassDB::bind_method(D_METHOD("add_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::add_undo_redo_inspector_hook_callback);
ClassDB::bind_method(D_METHOD("remove_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::remove_undo_redo_inspector_hook_callback);
ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout);
@@ -950,7 +959,7 @@ void EditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_LEFT);
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_RIGHT);
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_BOTTOM);
- BIND_ENUM_CONSTANT(CONTAINER_PROPERTY_EDITOR_BOTTOM);
+ BIND_ENUM_CONSTANT(CONTAINER_INSPECTOR_BOTTOM);
BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_LEFT);
BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_RIGHT);
@@ -965,6 +974,10 @@ void EditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(DOCK_SLOT_MAX);
}
+Ref<EditorUndoRedoManager> EditorPlugin::get_undo_redo() {
+ return undo_redo;
+}
+
EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS];
int EditorPlugins::creation_func_count = 0;
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 84c63d1021..fe01524bea 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -53,6 +53,7 @@ class EditorImportPlugin;
class EditorExportPlugin;
class EditorNode3DGizmoPlugin;
class EditorResourcePreview;
+class EditorUndoRedoManager;
class EditorFileSystem;
class EditorToolAddons;
class EditorPaths;
@@ -66,12 +67,12 @@ protected:
static void _bind_methods();
static EditorInterface *singleton;
- Array _make_mesh_previews(const Array &p_meshes, int p_preview_size);
+ TypedArray<Texture2D> _make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size);
public:
static EditorInterface *get_singleton() { return singleton; }
- Control *get_editor_main_control();
+ VBoxContainer *get_editor_main_screen();
void edit_resource(const Ref<Resource> &p_resource);
void edit_node(Node *p_node);
void edit_script(const Ref<Script> &p_script, int p_line = -1, int p_col = 0, bool p_grab_focus = true);
@@ -86,7 +87,7 @@ public:
String get_playing_scene() const;
Node *get_edited_scene_root();
- Array get_open_scenes() const;
+ PackedStringArray get_open_scenes() const;
ScriptEditor *get_script_editor();
EditorCommandPalette *get_command_palette() const;
@@ -116,6 +117,7 @@ public:
Error save_scene();
void save_scene_as(const String &p_scene, bool p_with_preview = true);
+ void restart_editor(bool p_save = true);
Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size);
@@ -129,9 +131,7 @@ public:
class EditorPlugin : public Node {
GDCLASS(EditorPlugin, Node);
friend class EditorData;
- UndoRedo *undo_redo = nullptr;
-
- UndoRedo *_get_undo_redo() { return undo_redo; }
+ Ref<EditorUndoRedoManager> undo_redo;
bool input_event_forwarding_always_enabled = false;
bool force_draw_over_forwarding_enabled = false;
@@ -144,7 +144,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- UndoRedo &get_undo_redo() { return *undo_redo; }
+ Ref<EditorUndoRedoManager> get_undo_redo();
void add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
void remove_custom_type(const String &p_type);
@@ -184,7 +184,7 @@ public:
CONTAINER_CANVAS_EDITOR_SIDE_LEFT,
CONTAINER_CANVAS_EDITOR_SIDE_RIGHT,
CONTAINER_CANVAS_EDITOR_BOTTOM,
- CONTAINER_PROPERTY_EDITOR_BOTTOM,
+ CONTAINER_INSPECTOR_BOTTOM,
CONTAINER_PROJECT_SETTING_TAB_LEFT,
CONTAINER_PROJECT_SETTING_TAB_RIGHT,
};
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index 5a010a66c1..a8df486381 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -102,7 +102,7 @@ void EditorPluginSettings::update_plugins() {
TreeItem *item = plugin_list->create_item(root);
item->set_text(0, name);
- item->set_tooltip(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description);
+ item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description);
item->set_metadata(0, path);
item->set_text(1, version);
item->set_metadata(1, script);
@@ -178,8 +178,8 @@ Vector<String> EditorPluginSettings::_get_plugins(const String &p_dir) {
continue;
}
- const String full_path = p_dir.plus_file(path);
- const String plugin_config = full_path.plus_file("plugin.cfg");
+ const String full_path = p_dir.path_join(path);
+ const String plugin_config = full_path.path_join("plugin.cfg");
if (FileAccess::exists(plugin_config)) {
plugins.push_back(plugin_config);
} else {
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index f434df3a1e..7364258a07 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -52,7 +52,7 @@ void EditorPropertyNil::update_property() {
EditorPropertyNil::EditorPropertyNil() {
Label *label = memnew(Label);
- label->set_text("[null]");
+ label->set_text("<null>");
add_child(label);
}
@@ -99,6 +99,10 @@ void EditorPropertyText::set_string_name(bool p_enabled) {
string_name = p_enabled;
}
+void EditorPropertyText::set_secret(bool p_enabled) {
+ text->set_secret(p_enabled);
+}
+
void EditorPropertyText::set_placeholder(const String &p_string) {
text->set_placeholder(p_string);
}
@@ -392,7 +396,7 @@ void EditorPropertyLocale::_locale_pressed() {
void EditorPropertyLocale::update_property() {
String locale_code = get_edited_object()->get(get_edited_property());
locale->set_text(locale_code);
- locale->set_tooltip(locale_code);
+ locale->set_tooltip_text(locale_code);
}
void EditorPropertyLocale::setup(const String &p_hint_text) {
@@ -481,7 +485,7 @@ void EditorPropertyPath::_path_pressed() {
void EditorPropertyPath::update_property() {
String full_path = get_edited_object()->get(get_edited_property());
path->set_text(full_path);
- path->set_tooltip(full_path);
+ path->set_tooltip_text(full_path);
}
void EditorPropertyPath::setup(const Vector<String> &p_extensions, bool p_folder, bool p_global) {
@@ -828,26 +832,35 @@ void EditorPropertyFlags::setup(const Vector<String> &p_options) {
bool first = true;
uint32_t current_val;
for (int i = 0; i < p_options.size(); i++) {
+ // An empty option is not considered a "flag".
String option = p_options[i].strip_edges();
- if (!option.is_empty()) {
- CheckBox *cb = memnew(CheckBox);
- cb->set_text(option);
- cb->set_clip_text(true);
- cb->connect("pressed", callable_mp(this, &EditorPropertyFlags::_flag_toggled).bind(i));
- add_focusable(cb);
- vbox->add_child(cb);
- flags.push_back(cb);
- Vector<String> text_split = p_options[i].split(":");
- if (text_split.size() != 1) {
- current_val = text_split[1].to_int();
- } else {
- current_val = 1 << i;
- }
- flag_values.push_back(current_val);
- if (first) {
- set_label_reference(cb);
- first = false;
- }
+ if (option.is_empty()) {
+ continue;
+ }
+ const int flag_index = flags.size(); // Index of the next element (added by the code below).
+
+ // Value for a flag can be explicitly overridden.
+ Vector<String> text_split = p_options[i].split(":");
+ if (text_split.size() != 1) {
+ current_val = text_split[1].to_int();
+ } else {
+ current_val = 1 << i;
+ }
+ flag_values.push_back(current_val);
+
+ // Create a CheckBox for the current flag.
+ CheckBox *cb = memnew(CheckBox);
+ cb->set_text(option);
+ cb->set_clip_text(true);
+ cb->connect("pressed", callable_mp(this, &EditorPropertyFlags::_flag_toggled).bind(flag_index));
+ add_focusable(cb);
+ vbox->add_child(cb);
+ flags.push_back(cb);
+
+ // Can't use `i == 0` because we want to find the first none-empty option.
+ if (first) {
+ set_label_reference(cb);
+ first = false;
}
}
}
@@ -947,7 +960,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
bool expand_was_hovered = expand_hovered;
expand_hovered = expand_rect.has_point(mm->get_position());
if (expand_hovered != expand_was_hovered) {
- update();
+ queue_redraw();
}
if (!expand_hovered) {
@@ -955,7 +968,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
if (flag_rects[i].has_point(mm->get_position())) {
// Used to highlight the hovered flag in the layers grid.
hovered_index = i;
- update();
+ queue_redraw();
return;
}
}
@@ -964,7 +977,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
// Remove highlight when no square is hovered.
if (hovered_index != -1) {
hovered_index = -1;
- update();
+ queue_redraw();
}
return;
@@ -982,11 +995,11 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) {
}
emit_signal(SNAME("flag_changed"), value);
- update();
+ queue_redraw();
} else if (expand_hovered) {
expanded = !expanded;
update_minimum_size();
- update();
+ queue_redraw();
}
}
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
@@ -1127,11 +1140,11 @@ void EditorPropertyLayersGrid::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
if (expand_hovered) {
expand_hovered = false;
- update();
+ queue_redraw();
}
if (hovered_index != -1) {
hovered_index = -1;
- update();
+ queue_redraw();
}
} break;
}
@@ -1139,7 +1152,7 @@ void EditorPropertyLayersGrid::_notification(int p_what) {
void EditorPropertyLayersGrid::set_flag(uint32_t p_flag) {
value = p_flag;
- update();
+ queue_redraw();
}
void EditorPropertyLayersGrid::_bind_methods() {
@@ -1272,7 +1285,7 @@ void EditorPropertyLayers::_menu_pressed(int p_menu) {
} else {
grid->value |= (1 << p_menu);
}
- grid->update();
+ grid->queue_redraw();
layers->set_item_checked(layers->get_item_index(p_menu), grid->value & (1 << p_menu));
_grid_changed(grid->value);
}
@@ -1378,7 +1391,7 @@ void EditorPropertyObjectID::update_property() {
edit->set_disabled(false);
edit->set_icon(EditorNode::get_singleton()->get_class_icon(type));
} else {
- edit->set_text(TTR("[Empty]"));
+ edit->set_text(TTR("<empty>"));
edit->set_disabled(true);
edit->set_icon(Ref<Texture2D>());
}
@@ -1458,7 +1471,7 @@ void EditorPropertyFloat::_value_changed(double val) {
}
if (angle_in_radians) {
- val = Math::deg2rad(val);
+ val = Math::deg_to_rad(val);
}
emit_changed(get_edited_property(), val);
}
@@ -1466,7 +1479,7 @@ void EditorPropertyFloat::_value_changed(double val) {
void EditorPropertyFloat::update_property() {
double val = get_edited_object()->get(get_edited_property());
if (angle_in_radians) {
- val = Math::rad2deg(val);
+ val = Math::rad_to_deg(val);
}
setting = true;
spin->set_value(val);
@@ -1519,13 +1532,13 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
// Ensure the easing doesn't appear as being dragged
dragging = false;
- easing_draw->update();
+ easing_draw->queue_redraw();
}
if (mb->get_button_index() == MouseButton::LEFT) {
dragging = mb->is_pressed();
// Update to display the correct dragging color
- easing_draw->update();
+ easing_draw->queue_redraw();
}
}
@@ -1565,7 +1578,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
val = CLAMP(val, -1'000'000, 1'000'000);
emit_changed(get_edited_property(), val);
- easing_draw->update();
+ easing_draw->queue_redraw();
}
}
@@ -1617,14 +1630,14 @@ void EditorPropertyEasing::_draw_easing() {
}
void EditorPropertyEasing::update_property() {
- easing_draw->update();
+ easing_draw->queue_redraw();
}
void EditorPropertyEasing::_set_preset(int p_preset) {
static const float preset_value[EASING_MAX] = { 0.0, 1.0, 2.0, 0.5, -2.0, -0.5 };
emit_changed(get_edited_property(), preset_value[p_preset]);
- easing_draw->update();
+ easing_draw->queue_redraw();
}
void EditorPropertyEasing::_setup_spin() {
@@ -1663,7 +1676,7 @@ void EditorPropertyEasing::_spin_focus_exited() {
spin->hide();
// Ensure the easing doesn't appear as being dragged
dragging = false;
- easing_draw->update();
+ easing_draw->queue_redraw();
}
void EditorPropertyEasing::setup(bool p_positive_only, bool p_flip) {
@@ -1988,9 +2001,9 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
v3.y = spin[1]->get_value();
v3.z = spin[2]->get_value();
if (angle_in_radians) {
- v3.x = Math::deg2rad(v3.x);
- v3.y = Math::deg2rad(v3.y);
- v3.z = Math::deg2rad(v3.z);
+ v3.x = Math::deg_to_rad(v3.x);
+ v3.y = Math::deg_to_rad(v3.y);
+ v3.z = Math::deg_to_rad(v3.z);
}
emit_changed(get_edited_property(), v3, p_name);
}
@@ -2022,9 +2035,9 @@ void EditorPropertyVector3::_update_ratio() {
void EditorPropertyVector3::update_using_vector(Vector3 p_vector) {
if (angle_in_radians) {
- p_vector.x = Math::rad2deg(p_vector.x);
- p_vector.y = Math::rad2deg(p_vector.y);
- p_vector.z = Math::rad2deg(p_vector.z);
+ p_vector.x = Math::rad_to_deg(p_vector.x);
+ p_vector.y = Math::rad_to_deg(p_vector.y);
+ p_vector.z = Math::rad_to_deg(p_vector.z);
}
setting = true;
spin[0]->set_value(p_vector.x);
@@ -2039,9 +2052,9 @@ Vector3 EditorPropertyVector3::get_vector() {
v3.y = spin[1]->get_value();
v3.z = spin[2]->get_value();
if (angle_in_radians) {
- v3.x = Math::deg2rad(v3.x);
- v3.y = Math::deg2rad(v3.y);
- v3.z = Math::deg2rad(v3.z);
+ v3.x = Math::deg_to_rad(v3.x);
+ v3.y = Math::deg_to_rad(v3.y);
+ v3.z = Math::deg_to_rad(v3.z);
}
return v3;
@@ -2613,8 +2626,47 @@ void EditorPropertyQuaternion::_set_read_only(bool p_read_only) {
for (int i = 0; i < 4; i++) {
spin[i]->set_read_only(p_read_only);
}
+ for (int i = 0; i < 3; i++) {
+ euler[i]->set_read_only(p_read_only);
+ }
};
+void EditorPropertyQuaternion::_edit_custom_value() {
+ if (edit_button->is_pressed()) {
+ edit_custom_bc->show();
+ for (int i = 0; i < 3; i++) {
+ euler[i]->grab_focus();
+ }
+ } else {
+ edit_custom_bc->hide();
+ for (int i = 0; i < 4; i++) {
+ spin[i]->grab_focus();
+ }
+ }
+ update_property();
+}
+
+void EditorPropertyQuaternion::_custom_value_changed(double val) {
+ if (setting) {
+ return;
+ }
+
+ edit_euler.x = euler[0]->get_value();
+ edit_euler.y = euler[1]->get_value();
+ edit_euler.z = euler[2]->get_value();
+
+ Vector3 v;
+ v.x = Math::deg_to_rad(edit_euler.x);
+ v.y = Math::deg_to_rad(edit_euler.y);
+ v.z = Math::deg_to_rad(edit_euler.z);
+
+ Quaternion temp_q = Quaternion(v);
+ spin[0]->set_value(temp_q.x);
+ spin[1]->set_value(temp_q.y);
+ spin[2]->set_value(temp_q.z);
+ spin[3]->set_value(temp_q.w);
+}
+
void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) {
if (setting) {
return;
@@ -2625,9 +2677,18 @@ void EditorPropertyQuaternion::_value_changed(double val, const String &p_name)
p.y = spin[1]->get_value();
p.z = spin[2]->get_value();
p.w = spin[3]->get_value();
+
emit_changed(get_edited_property(), p, p_name);
}
+bool EditorPropertyQuaternion::is_grabbing_euler() {
+ bool is_grabbing = false;
+ for (int i = 0; i < 3; i++) {
+ is_grabbing |= euler[i]->is_grabbing();
+ }
+ return is_grabbing;
+}
+
void EditorPropertyQuaternion::update_property() {
Quaternion val = get_edited_object()->get(get_edited_property());
setting = true;
@@ -2635,9 +2696,22 @@ void EditorPropertyQuaternion::update_property() {
spin[1]->set_value(val.y);
spin[2]->set_value(val.z);
spin[3]->set_value(val.w);
+ if (!is_grabbing_euler()) {
+ Vector3 v = val.normalized().get_euler_yxz();
+ edit_euler.x = Math::rad_to_deg(v.x);
+ edit_euler.y = Math::rad_to_deg(v.y);
+ edit_euler.z = Math::rad_to_deg(v.z);
+ euler[0]->set_value(edit_euler.x);
+ euler[1]->set_value(edit_euler.y);
+ euler[2]->set_value(edit_euler.z);
+ }
setting = false;
}
+void EditorPropertyQuaternion::_warning_pressed() {
+ warning_dialog->popup_centered();
+}
+
void EditorPropertyQuaternion::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
@@ -2646,6 +2720,13 @@ void EditorPropertyQuaternion::_notification(int p_what) {
for (int i = 0; i < 4; i++) {
spin[i]->add_theme_color_override("label_color", colors[i]);
}
+ for (int i = 0; i < 3; i++) {
+ euler[i]->add_theme_color_override("label_color", colors[i]);
+ }
+ edit_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ euler_label->add_theme_color_override(SNAME("font_color"), get_theme_color(SNAME("property_color"), SNAME("Editor")));
+ warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ warning->add_theme_color_override(SNAME("font_color"), get_theme_color(SNAME("warning_color"), SNAME("Editor")));
} break;
}
}
@@ -2653,7 +2734,7 @@ void EditorPropertyQuaternion::_notification(int p_what) {
void EditorPropertyQuaternion::_bind_methods() {
}
-void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix, bool p_hide_editor) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
@@ -2665,28 +2746,50 @@ void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step,
// a generic way to store 4 values, so we'll still respect the suffix.
spin[i]->set_suffix(p_suffix);
}
+
+ for (int i = 0; i < 3; i++) {
+ euler[i]->set_min(-360);
+ euler[i]->set_max(360);
+ euler[i]->set_step(0.1);
+ euler[i]->set_hide_slider(false);
+ euler[i]->set_allow_greater(true);
+ euler[i]->set_allow_lesser(true);
+ euler[i]->set_suffix(U"\u00B0");
+ }
+
+ if (p_hide_editor) {
+ edit_button->hide();
+ }
}
EditorPropertyQuaternion::EditorPropertyQuaternion() {
bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing");
- BoxContainer *bc;
-
+ VBoxContainer *bc = memnew(VBoxContainer);
+ edit_custom_bc = memnew(VBoxContainer);
+ BoxContainer *edit_custom_layout;
if (horizontal) {
- bc = memnew(HBoxContainer);
- add_child(bc);
+ default_layout = memnew(HBoxContainer);
+ edit_custom_layout = memnew(HBoxContainer);
set_bottom_editor(bc);
} else {
- bc = memnew(VBoxContainer);
- add_child(bc);
+ default_layout = memnew(VBoxContainer);
+ edit_custom_layout = memnew(VBoxContainer);
}
+ edit_custom_bc->hide();
+ add_child(bc);
+ edit_custom_bc->set_h_size_flags(SIZE_EXPAND_FILL);
+ default_layout->set_h_size_flags(SIZE_EXPAND_FILL);
+ edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL);
+ bc->add_child(default_layout);
+ bc->add_child(edit_custom_bc);
static const char *desc[4] = { "x", "y", "z", "w" };
for (int i = 0; i < 4; i++) {
spin[i] = memnew(EditorSpinSlider);
spin[i]->set_flat(true);
spin[i]->set_label(desc[i]);
- bc->add_child(spin[i]);
+ default_layout->add_child(spin[i]);
add_focusable(spin[i]);
spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_value_changed).bind(desc[i]));
if (horizontal) {
@@ -2694,6 +2797,41 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() {
}
}
+ warning = memnew(Button);
+ warning->set_text(TTR("Temporary Euler may be changed implicitly!"));
+ warning->set_clip_text(true);
+ warning->connect("pressed", callable_mp(this, &EditorPropertyQuaternion::_warning_pressed));
+ warning_dialog = memnew(AcceptDialog);
+ add_child(warning_dialog);
+ warning_dialog->set_text(TTR("Temporary Euler will not be stored in the object with the original value. Instead, it will be stored as Quaternion with irreversible conversion.\nThis is due to the fact that the result of Euler->Quaternion can be determined uniquely, but the result of Quaternion->Euler can be multi-existent."));
+
+ euler_label = memnew(Label);
+ euler_label->set_text("Temporary Euler");
+
+ edit_custom_bc->add_child(warning);
+ edit_custom_bc->add_child(edit_custom_layout);
+ edit_custom_layout->add_child(euler_label);
+
+ for (int i = 0; i < 3; i++) {
+ euler[i] = memnew(EditorSpinSlider);
+ euler[i]->set_flat(true);
+ euler[i]->set_label(desc[i]);
+ edit_custom_layout->add_child(euler[i]);
+ add_focusable(euler[i]);
+ euler[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_custom_value_changed));
+ if (horizontal) {
+ euler[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ }
+ }
+
+ edit_button = memnew(Button);
+ edit_button->set_flat(true);
+ edit_button->set_toggle_mode(true);
+ default_layout->add_child(edit_button);
+ edit_button->connect("pressed", callable_mp(this, &EditorPropertyQuaternion::_edit_custom_value));
+
+ add_focusable(edit_button);
+
if (!horizontal) {
set_label_reference(spin[0]); //show text and buttons around this
}
@@ -3386,14 +3524,14 @@ void EditorPropertyColor::update_property() {
// Add a tooltip to display each channel's values without having to click the ColorPickerButton
if (picker->is_editing_alpha()) {
- picker->set_tooltip(vformat(
+ picker->set_tooltip_text(vformat(
"R: %s\nG: %s\nB: %s\nA: %s",
rtos(color.r).pad_decimals(2),
rtos(color.g).pad_decimals(2),
rtos(color.b).pad_decimals(2),
rtos(color.a).pad_decimals(2)));
} else {
- picker->set_tooltip(vformat(
+ picker->set_tooltip_text(vformat(
"R: %s\nG: %s\nB: %s",
rtos(color.r).pad_decimals(2),
rtos(color.g).pad_decimals(2),
@@ -3551,7 +3689,7 @@ void EditorPropertyNodePath::update_property() {
p = get_edited_object()->get(get_edited_property());
}
- assign->set_tooltip(p);
+ assign->set_tooltip_text(p);
if (p == NodePath()) {
assign->set_icon(Ref<Texture2D>());
assign->set_text(TTR("Assign..."));
@@ -3653,20 +3791,24 @@ void EditorPropertyResource::_set_read_only(bool p_read_only) {
resource_picker->set_editable(!p_read_only);
};
-void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_edit) {
+void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_inspect) {
if (p_resource->is_built_in() && !p_resource->get_path().is_empty()) {
String parent = p_resource->get_path().get_slice("::", 0);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
- if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) {
- // If the resource belongs to another scene, edit it in that scene instead.
- EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource);
- return;
+ if (p_inspect) {
+ if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) {
+ // If the resource belongs to another (non-imported) scene, edit it in that scene instead.
+ if (!FileAccess::exists(parent + ".import")) {
+ EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource);
+ return;
+ }
+ }
}
}
- if (!p_edit && use_sub_inspector) {
+ if (!p_inspect && use_sub_inspector) {
bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());
get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold);
update_property();
@@ -3819,7 +3961,7 @@ void EditorPropertyResource::_update_property_bg() {
}
updating_theme = false;
- update();
+ queue_redraw();
}
void EditorPropertyResource::_update_preferred_shader() {
@@ -4040,8 +4182,8 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, const Varian
}
struct EditorPropertyRangeHint {
- bool greater = true;
- bool lesser = true;
+ bool or_greater = true;
+ bool or_less = true;
double min = -99999.0;
double max = 99999.0;
double step = 1.0;
@@ -4059,8 +4201,8 @@ static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const Stri
ERR_FAIL_COND_V_MSG(slices.size() < 2, hint,
vformat("Invalid PROPERTY_HINT_RANGE with hint \"%s\": Missing required min and/or max values.", p_hint_text));
- hint.greater = false; // If using ranged, assume false by default.
- hint.lesser = false;
+ hint.or_greater = false; // If using ranged, assume false by default.
+ hint.or_less = false;
hint.min = slices[0].to_float();
hint.max = slices[1].to_float();
@@ -4073,9 +4215,9 @@ static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const Stri
for (int i = 2; i < slices.size(); i++) {
String slice = slices[i].strip_edges();
if (slice == "or_greater") {
- hint.greater = true;
- } else if (slice == "or_lesser") {
- hint.lesser = true;
+ hint.or_greater = true;
+ } else if (slice == "or_less") {
+ hint.or_less = true;
} else if (slice == "no_slider") {
hint.hide_slider = true;
} else if (slice == "exp") {
@@ -4172,7 +4314,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.step, hint.greater, hint.lesser, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.step, hint.or_greater, hint.or_less, hint.suffix);
return editor;
}
@@ -4200,7 +4342,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyFloat *editor = memnew(EditorPropertyFloat);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
- editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.exp_range, hint.greater, hint.lesser, hint.suffix, hint.radians);
+ editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.exp_range, hint.or_greater, hint.or_less, hint.suffix, hint.radians);
return editor;
}
@@ -4279,6 +4421,9 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyText *editor = memnew(EditorPropertyText);
if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) {
editor->set_placeholder(p_hint_text);
+ } else if (p_hint == PROPERTY_HINT_PASSWORD) {
+ editor->set_secret(true);
+ editor->set_placeholder(p_hint_text);
}
return editor;
}
@@ -4357,7 +4502,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::QUATERNION: {
EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
- editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix, p_hint == PROPERTY_HINT_HIDE_QUATERNION_EDIT);
return editor;
} break;
case Variant::AABB: {
@@ -4403,6 +4548,9 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyText *editor = memnew(EditorPropertyText);
if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) {
editor->set_placeholder(p_hint_text);
+ } else if (p_hint == PROPERTY_HINT_PASSWORD) {
+ editor->set_secret(true);
+ editor->set_placeholder(p_hint_text);
}
editor->set_string_name(true);
return editor;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index c1dfb5cb1e..d6c9510634 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -67,6 +67,7 @@ public:
void set_string_name(bool p_enabled);
virtual void update_property() override;
void set_placeholder(const String &p_string);
+ void set_secret(bool p_enabled);
EditorPropertyText();
};
@@ -625,9 +626,26 @@ public:
class EditorPropertyQuaternion : public EditorProperty {
GDCLASS(EditorPropertyQuaternion, EditorProperty);
+ BoxContainer *default_layout = nullptr;
EditorSpinSlider *spin[4];
bool setting = false;
+
+ Button *warning = nullptr;
+ AcceptDialog *warning_dialog = nullptr;
+
+ Label *euler_label = nullptr;
+ VBoxContainer *edit_custom_bc = nullptr;
+ EditorSpinSlider *euler[3];
+ Button *edit_button = nullptr;
+
+ Vector3 edit_euler = Vector3();
+
void _value_changed(double p_val, const String &p_name);
+ void _edit_custom_value();
+ void _custom_value_changed(double p_val);
+ void _warning_pressed();
+
+ bool is_grabbing_euler();
protected:
virtual void _set_read_only(bool p_read_only) override;
@@ -636,7 +654,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String(), bool p_hide_editor = false);
EditorPropertyQuaternion();
};
@@ -835,7 +853,7 @@ class EditorPropertyResource : public EditorProperty {
bool updating_theme = false;
bool opened_editor = false;
- void _resource_selected(const Ref<Resource> &p_resource, bool p_edit);
+ void _resource_selected(const Ref<Resource> &p_resource, bool p_inspect);
void _resource_changed(const Ref<Resource> &p_resource);
void _viewport_selected(const NodePath &p_path);
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 9a83082d1e..ad84b30689 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -509,7 +509,7 @@ void EditorPropertyArray::_notification(int p_what) {
if (is_visible_in_tree()) {
if (_is_drop_valid(get_viewport()->gui_get_drag_data())) {
dropping = true;
- edit->update();
+ edit->queue_redraw();
}
}
} break;
@@ -517,7 +517,7 @@ void EditorPropertyArray::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (dropping) {
dropping = false;
- edit->update();
+ edit->queue_redraw();
}
} break;
}
@@ -1111,7 +1111,7 @@ void EditorPropertyDictionary::update_property() {
if (i < amount) {
String cs = key.get_construct_string();
prop->set_label(key.get_construct_string());
- prop->set_tooltip(cs);
+ prop->set_tooltip_text(cs);
change_index = i + offset;
} else if (i == amount) {
prop->set_label(TTR("New Key:"));
@@ -1361,7 +1361,7 @@ void EditorPropertyLocalizableString::update_property() {
String cs = key.get_construct_string();
prop->set_label(cs);
- prop->set_tooltip(cs);
+ prop->set_tooltip_text(cs);
remove_index = i + offset;
prop->set_selectable(false);
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 82aeebe14a..ae61418528 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -151,7 +151,7 @@ class EditorPropertyDictionary : public EditorProperty {
Button *edit = nullptr;
MarginContainer *container = nullptr;
VBoxContainer *property_vbox = nullptr;
- EditorSpinSlider *size_sliderv;
+ EditorSpinSlider *size_sliderv = nullptr;
Button *button_add_item = nullptr;
EditorPaginator *paginator = nullptr;
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 6c713de94a..a2dfa4f80e 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -106,6 +106,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["aabb"] = "AABB";
capitalize_string_remaps["adb"] = "ADB";
capitalize_string_remaps["ao"] = "AO";
+ capitalize_string_remaps["api"] = "API";
capitalize_string_remaps["apk"] = "APK";
capitalize_string_remaps["arm64-v8a"] = "arm64-v8a";
capitalize_string_remaps["armeabi-v7a"] = "armeabi-v7a";
@@ -172,6 +173,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["k1"] = "K1";
capitalize_string_remaps["k2"] = "K2";
capitalize_string_remaps["kb"] = "(KB)"; // Unit.
+ capitalize_string_remaps["lcd"] = "LCD";
capitalize_string_remaps["ldr"] = "LDR";
capitalize_string_remaps["lod"] = "LOD";
capitalize_string_remaps["lowpass"] = "Low-pass";
@@ -190,11 +192,14 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["opengl"] = "OpenGL";
capitalize_string_remaps["opentype"] = "OpenType";
capitalize_string_remaps["openxr"] = "OpenXR";
+ capitalize_string_remaps["osslsigncode"] = "osslsigncode";
capitalize_string_remaps["pck"] = "PCK";
capitalize_string_remaps["png"] = "PNG";
capitalize_string_remaps["po2"] = "(Power of 2)"; // Unit.
capitalize_string_remaps["pvrtc"] = "PVRTC";
capitalize_string_remaps["pvs"] = "PVS";
+ capitalize_string_remaps["rcedit"] = "rcedit";
+ capitalize_string_remaps["rcodesign"] = "rcodesign";
capitalize_string_remaps["rgb"] = "RGB";
capitalize_string_remaps["rid"] = "RID";
capitalize_string_remaps["rmb"] = "RMB";
@@ -204,6 +209,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["sdfgi"] = "SDFGI";
capitalize_string_remaps["sdk"] = "SDK";
capitalize_string_remaps["sec"] = "(sec)"; // Unit.
+ capitalize_string_remaps["signtool"] = "signtool";
capitalize_string_remaps["sms"] = "SMS";
capitalize_string_remaps["srgb"] = "sRGB";
capitalize_string_remaps["ssao"] = "SSAO";
@@ -236,6 +242,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["webp"] = "WebP";
capitalize_string_remaps["webrtc"] = "WebRTC";
capitalize_string_remaps["websocket"] = "WebSocket";
+ capitalize_string_remaps["wine"] = "wine";
capitalize_string_remaps["wifi"] = "Wi-Fi";
capitalize_string_remaps["x86"] = "x86";
capitalize_string_remaps["xr"] = "XR";
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index e5c1836205..5346052f4d 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -61,8 +61,8 @@ void EditorResourcePicker::_update_resource() {
if (edited_resource == Ref<Resource>()) {
assign_button->set_icon(Ref<Texture2D>());
- assign_button->set_text(TTR("[empty]"));
- assign_button->set_tooltip("");
+ assign_button->set_text(TTR("<empty>"));
+ assign_button->set_tooltip_text("");
} else {
assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object"));
@@ -73,14 +73,16 @@ void EditorResourcePicker::_update_resource() {
} else {
assign_button->set_text(edited_resource->get_class());
}
- assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class());
+ assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class());
// Preview will override the above, so called at the end.
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id());
}
} else if (edited_resource.is_valid()) {
- assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class());
+ assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class());
}
+
+ assign_button->set_disabled(!editable && !edited_resource.is_valid());
}
void EditorResourcePicker::_update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj) {
@@ -106,7 +108,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const
preview_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
- assign_button->set_custom_minimum_size(Size2(MIN(1, assign_button_min_size.x), MIN(thumbnail_size, assign_button_min_size.y)));
+ assign_button->set_custom_minimum_size(Size2(MAX(1, assign_button_min_size.x), MAX(thumbnail_size, assign_button_min_size.y)));
}
preview_rect->set_texture(p_preview);
@@ -171,35 +173,50 @@ void EditorResourcePicker::_update_menu_items() {
edit_menu->clear();
// Add options for creating specific subtypes of the base resource type.
- set_create_options(edit_menu);
+ if (is_editable()) {
+ set_create_options(edit_menu);
- // Add an option to load a resource from a file using the QuickOpen dialog.
- edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD);
+ // Add an option to load a resource from a file using the QuickOpen dialog.
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD);
- // Add an option to load a resource from a file using the regular file dialog.
- edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD);
+ // Add an option to load a resource from a file using the regular file dialog.
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD);
+ }
// Add options for changing existing value of the resource.
if (edited_resource.is_valid()) {
- edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_EDIT);
- edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR);
- edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
-
- // Check whether the resource has subresources.
- List<PropertyInfo> property_list;
- edited_resource->get_property_list(&property_list);
- bool has_subresources = false;
- for (PropertyInfo &p : property_list) {
- if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) {
- has_subresources = true;
- break;
- }
- }
- if (has_subresources) {
- edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique (Recursive)"), OBJ_MENU_MAKE_UNIQUE_RECURSIVE);
+ // Determine if the edited resource is part of another scene (foreign) which was imported
+ bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource);
+
+ // If the resource is determined to be foreign and imported, change the menu entry's description to 'inspect' rather than 'edit'
+ // since will only be able to view its properties in read-only mode.
+ if (is_edited_resource_foreign_import) {
+ // The 'Search' icon is a magnifying glass, which seems appropriate, but maybe a bespoke icon is preferred here.
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")), TTR("Inspect"), OBJ_MENU_INSPECT);
+ } else {
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_INSPECT);
}
- edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE);
+ if (is_editable()) {
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR);
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
+
+ // Check whether the resource has subresources.
+ List<PropertyInfo> property_list;
+ edited_resource->get_property_list(&property_list);
+ bool has_subresources = false;
+ for (PropertyInfo &p : property_list) {
+ if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) {
+ has_subresources = true;
+ break;
+ }
+ }
+ if (has_subresources) {
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique (Recursive)"), OBJ_MENU_MAKE_UNIQUE_RECURSIVE);
+ }
+
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE);
+ }
if (edited_resource->get_path().is_resource_file()) {
edit_menu->add_separator();
@@ -210,14 +227,16 @@ void EditorResourcePicker::_update_menu_items() {
// Add options to copy/paste resource.
Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
bool paste_valid = false;
- if (cb.is_valid()) {
- if (base_type.is_empty()) {
- paste_valid = true;
- } else {
- for (int i = 0; i < base_type.get_slice_count(","); i++) {
- if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
- paste_valid = true;
- break;
+ if (is_editable()) {
+ if (cb.is_valid()) {
+ if (base_type.is_empty()) {
+ paste_valid = true;
+ } else {
+ for (int i = 0; i < base_type.get_slice_count(","); i++) {
+ if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
+ paste_valid = true;
+ break;
+ }
}
}
}
@@ -236,7 +255,7 @@ void EditorResourcePicker::_update_menu_items() {
}
// Add options to convert existing resource to another type of resource.
- if (edited_resource.is_valid()) {
+ if (is_editable() && edited_resource.is_valid()) {
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource);
if (conversions.size()) {
edit_menu->add_separator();
@@ -295,7 +314,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
quick_open->set_title(TTR("Resource"));
} break;
- case OBJ_MENU_EDIT: {
+ case OBJ_MENU_INSPECT: {
if (edited_resource.is_valid()) {
emit_signal(SNAME("resource_selected"), edited_resource, true);
}
@@ -491,20 +510,21 @@ void EditorResourcePicker::_button_draw() {
}
void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) {
- if (!editable) {
- return;
- }
-
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
- _update_menu_items();
-
- Vector2 pos = get_screen_position() + mb->get_position();
- edit_menu->reset_size();
- edit_menu->set_position(pos);
- edit_menu->popup();
+ // Only attempt to update and show the menu if we have
+ // a valid resource or the Picker is editable, as
+ // there will otherwise be nothing to display.
+ if (edited_resource.is_valid() || is_editable()) {
+ _update_menu_items();
+
+ Vector2 pos = get_screen_position() + mb->get_position();
+ edit_menu->reset_size();
+ edit_menu->set_position(pos);
+ edit_menu->popup();
+ }
}
}
}
@@ -734,7 +754,7 @@ void EditorResourcePicker::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode");
- ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "edit")));
+ ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "inspect")));
ADD_SIGNAL(MethodInfo("resource_changed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
}
@@ -749,20 +769,20 @@ void EditorResourcePicker::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- draw_style_box(get_theme_stylebox(SNAME("bg"), SNAME("Tree")), Rect2(Point2(), get_size()));
+ draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("Tree")), Rect2(Point2(), get_size()));
} break;
case NOTIFICATION_DRAG_BEGIN: {
if (editable && _is_drop_valid(get_viewport()->gui_get_drag_data())) {
dropping = true;
- assign_button->update();
+ assign_button->queue_redraw();
}
} break;
case NOTIFICATION_DRAG_END: {
if (dropping) {
dropping = false;
- assign_button->update();
+ assign_button->queue_redraw();
}
} break;
}
@@ -866,7 +886,7 @@ void EditorResourcePicker::set_toggle_pressed(bool p_pressed) {
void EditorResourcePicker::set_editable(bool p_editable) {
editable = p_editable;
- assign_button->set_disabled(!editable);
+ assign_button->set_disabled(!editable && !edited_resource.is_valid());
edit_button->set_visible(editable);
}
@@ -1029,7 +1049,7 @@ void EditorAudioStreamPicker::_notification(int p_what) {
Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(audio_stream);
if (preview.is_valid()) {
if (preview->get_version() != last_preview_version) {
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
last_preview_version = preview->get_version();
}
}
@@ -1063,10 +1083,10 @@ void EditorAudioStreamPicker::_notification(int p_what) {
}
}
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
} else {
if (tagged_frame_offset_count != 0) {
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
}
tagged_frame_offset_count = 0;
}
@@ -1087,13 +1107,13 @@ void EditorAudioStreamPicker::_update_resource() {
set_assign_button_min_size(Size2(1, font->get_height(font_size) * 1.5));
}
- stream_preview_rect->update();
+ stream_preview_rect->queue_redraw();
}
void EditorAudioStreamPicker::_preview_draw() {
Ref<AudioStream> audio_stream = get_edited_resource();
if (!audio_stream.is_valid()) {
- get_assign_button()->set_text(TTR("[empty]"));
+ get_assign_button()->set_text(TTR("<empty>"));
return;
}
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index 3a4d5985bd..3d6127e656 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -63,7 +63,7 @@ class EditorResourcePicker : public HBoxContainer {
enum MenuOption {
OBJ_MENU_LOAD,
OBJ_MENU_QUICKLOAD,
- OBJ_MENU_EDIT,
+ OBJ_MENU_INSPECT,
OBJ_MENU_CLEAR,
OBJ_MENU_MAKE_UNIQUE,
OBJ_MENU_MAKE_UNIQUE_RECURSIVE,
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index c0ea2b743e..706b77c142 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -244,7 +244,7 @@ void EditorResourcePreview::_iterate() {
} else {
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ cache_base = temp_path.path_join("resthumb-" + cache_base);
//does not have it, try to load a cached thumbnail
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 6ce8625daa..b909129b18 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "main/main.h"
#include "servers/display_server.h"
EditorRun::Status EditorRun::get_status() const {
@@ -46,6 +47,10 @@ String EditorRun::get_running_scene() const {
Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_PROJECT)) {
+ args.push_back(a);
+ }
+
String resource_path = ProjectSettings::get_singleton()->get_resource_path();
if (!resource_path.is_empty()) {
args.push_back("--path");
@@ -105,10 +110,6 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
screen -= 3;
}
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
Rect2 screen_rect;
screen_rect.position = DisplayServer::get_singleton()->screen_get_position(screen);
screen_rect.size = DisplayServer::get_singleton()->screen_get_size(screen);
@@ -257,6 +258,11 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
}
}
+ // Pass the debugger stop shortcut to the running instance(s).
+ String shortcut;
+ VariantWriter::write_to_string(ED_GET_SHORTCUT("editor/stop"), shortcut);
+ OS::get_singleton()->set_environment("__GODOT_EDITOR_STOP_SHORTCUT__", shortcut);
+
printf("Running: %s", exec.utf8().get_data());
for (const String &E : args) {
printf(" %s", E.utf8().get_data());
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index d8b738be17..3e8f17085d 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -77,9 +77,9 @@ void EditorRunNative::_notification(int p_what) {
mb->get_popup()->clear();
mb->show();
if (dc == 1) {
- mb->set_tooltip(eep->get_option_tooltip(0));
+ mb->set_tooltip_text(eep->get_option_tooltip(0));
} else {
- mb->set_tooltip(eep->get_options_tooltip());
+ mb->set_tooltip_text(eep->get_options_tooltip());
for (int i = 0; i < dc; i++) {
mb->get_popup()->add_icon_item(eep->get_option_icon(i), eep->get_option_label(i));
mb->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(i));
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index 801a1a4641..e078bea037 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -113,18 +113,13 @@ class SectionedInspectorFilter : public Object {
}
}
- bool property_can_revert(const String &p_name) {
- return edited->call("property_can_revert", section + "/" + p_name);
+ bool _property_can_revert(const StringName &p_name) const {
+ return edited->property_can_revert(section + "/" + p_name);
}
- Variant property_get_revert(const String &p_name) {
- return edited->call("property_get_revert", section + "/" + p_name);
- }
-
-protected:
- static void _bind_methods() {
- ClassDB::bind_method("property_can_revert", &SectionedInspectorFilter::property_can_revert);
- ClassDB::bind_method("property_get_revert", &SectionedInspectorFilter::property_get_revert);
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const {
+ r_property = edited->property_get_revert(section + "/" + p_name);
+ return true;
}
public:
@@ -283,7 +278,7 @@ void SectionedInspector::update_category_list() {
const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style);
ms->set_text(0, text);
- ms->set_tooltip(0, tooltip);
+ ms->set_tooltip_text(0, tooltip);
ms->set_metadata(0, metasection);
ms->set_selectable(0, false);
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 80e77a1125..74445e6caa 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -406,6 +406,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/debug/enable_pseudolocalization", false);
set_restart_if_changed("interface/editor/debug/enable_pseudolocalization", true);
// Use pseudolocalization in editor.
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/use_embedded_menu", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/expand_to_title", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/custom_display_scale", 1.0, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/main_font_size", 14, "8,48,1")
@@ -413,7 +415,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/code_font_contextual_ligatures", 0, "Default,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set")
_initial_set("interface/editor/code_font_custom_opentype_features", "");
_initial_set("interface/editor/code_font_custom_variations", "");
- _initial_set("interface/editor/font_antialiased", true);
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_antialiasing", 1, "None,Grayscale,LCD sub-pixel")
#ifdef MACOS_ENABLED
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_hinting", 0, "Auto (None),None,Light,Normal")
#else
@@ -508,7 +510,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Appearance: Caret
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/caret/type", 0, "Line,Block")
_initial_set("text_editor/appearance/caret/caret_blink", true);
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/appearance/caret/caret_blink_speed", 0.5, "0.1,10,0.01")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/appearance/caret/caret_blink_interval", 0.5, "0.1,10,0.01")
_initial_set("text_editor/appearance/caret/highlight_current_line", true);
_initial_set("text_editor/appearance/caret/highlight_all_occurrences", true);
@@ -715,7 +717,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1")
// SSL
- EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/ssl/editor_ssl_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/tls/editor_tls_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
// Profiler
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1")
@@ -854,7 +856,7 @@ void EditorSettings::create() {
// Validate editor config file.
Ref<DirAccess> dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir());
String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
- config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name);
+ config_file_path = EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);
if (!dir->file_exists(config_file_name)) {
goto fail;
}
@@ -885,7 +887,7 @@ fail:
if (extra_config->has_section("init_projects")) {
Vector<String> list = extra_config->get_value("init_projects", "list");
for (int i = 0; i < list.size(); i++) {
- list.write[i] = exe_path.plus_file(list[i]);
+ list.write[i] = exe_path.path_join(list[i]);
}
extra_config->set_value("init_projects", "list", list);
}
@@ -962,8 +964,8 @@ void EditorSettings::save() {
}
}
-Array EditorSettings::get_changed_settings() const {
- Array arr;
+PackedStringArray EditorSettings::get_changed_settings() const {
+ PackedStringArray arr;
for (const String &setting : changed_settings) {
arr.push_back(setting);
}
@@ -1073,24 +1075,25 @@ Variant _EDITOR_GET(const String &p_setting) {
return EditorSettings::get_singleton()->get(p_setting);
}
-bool EditorSettings::property_can_revert(const String &p_setting) {
- if (!props.has(p_setting)) {
+bool EditorSettings::_property_can_revert(const StringName &p_name) const {
+ if (!props.has(p_name)) {
return false;
}
- if (!props[p_setting].has_default_value) {
+ if (!props[p_name].has_default_value) {
return false;
}
- return props[p_setting].initial != props[p_setting].variant;
+ return props[p_name].initial != props[p_name].variant;
}
-Variant EditorSettings::property_get_revert(const String &p_setting) {
- if (!props.has(p_setting) || !props[p_setting].has_default_value) {
- return Variant();
+bool EditorSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (!props.has(p_name) || !props[p_name].has_default_value) {
+ return false;
}
- return props[p_setting].initial;
+ r_property = props[p_name].initial;
+ return true;
}
void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
@@ -1103,7 +1106,7 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) {
Ref<ConfigFile> cf = memnew(ConfigFile);
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg");
Error err;
err = cf->load(path);
ERR_FAIL_COND_MSG(err != OK && err != ERR_FILE_NOT_FOUND, "Cannot load editor settings from file '" + path + "'.");
@@ -1114,7 +1117,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String
Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const {
Ref<ConfigFile> cf = memnew(ConfigFile);
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg");
Error err = cf->load(path);
if (err != OK) {
return p_default;
@@ -1126,9 +1129,9 @@ void EditorSettings::set_favorites(const Vector<String> &p_favorites) {
favorites = p_favorites;
String favorites_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
- favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs");
+ favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");
} else {
- favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites");
+ favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");
}
Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::WRITE);
if (f.is_valid()) {
@@ -1146,9 +1149,9 @@ void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) {
recent_dirs = p_recent_dirs;
String recent_dirs_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
- recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs");
+ recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");
} else {
- recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs");
+ recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");
}
Ref<FileAccess> f = FileAccess::open(recent_dirs_file, FileAccess::WRITE);
if (f.is_valid()) {
@@ -1166,11 +1169,11 @@ void EditorSettings::load_favorites_and_recent_dirs() {
String favorites_file;
String recent_dirs_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
- favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs");
- recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs");
+ favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");
+ recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");
} else {
- favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites");
- recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs");
+ favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");
+ recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");
}
Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::READ);
if (f.is_valid()) {
@@ -1233,7 +1236,7 @@ void EditorSettings::load_text_editor_theme() {
return; // sorry for "Settings changed" console spam
}
- String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet");
+ String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet");
Ref<ConfigFile> cf = memnew(ConfigFile);
Error err = cf->load(theme_path);
@@ -1270,7 +1273,7 @@ bool EditorSettings::import_text_editor_theme(String p_file) {
Ref<DirAccess> d = DirAccess::open(EditorPaths::get_singleton()->get_text_editor_themes_dir());
if (d.is_valid()) {
- d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file.get_file()));
+ d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file.get_file()));
return true;
}
}
@@ -1283,7 +1286,7 @@ bool EditorSettings::save_text_editor_theme() {
if (_is_default_text_editor_theme(p_file.get_file().to_lower())) {
return false;
}
- String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet");
+ String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet");
return _save_text_editor_theme(theme_path);
}
@@ -1336,7 +1339,7 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c
}
String EditorSettings::get_editor_layouts_config() const {
- return EditorPaths::get_singleton()->get_config_dir().plus_file("editor_layouts.cfg");
+ return EditorPaths::get_singleton()->get_config_dir().path_join("editor_layouts.cfg");
}
float EditorSettings::get_auto_display_scale() const {
@@ -1464,9 +1467,10 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
#ifdef MACOS_ENABLED
// Use Cmd+Backspace as a general replacement for Delete shortcuts on macOS
if (keycode == Key::KEY_DELETE) {
- keycode = KeyModifierMask::CMD | Key::BACKSPACE;
+ keycode = KeyModifierMask::META | Key::BACKSPACE;
}
#endif
+
Ref<InputEventKey> ie;
if (keycode != Key::NONE) {
ie = InputEventKey::create_reference(keycode);
@@ -1474,8 +1478,11 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
}
}
- // Directly override the existing shortcut.
- sc->set_events(events);
+ // Override the existing shortcut only if it wasn't customized by the user (i.e. still "original").
+ if (Shortcut::is_event_array_equal(sc->get_events(), sc->get_meta("original"))) {
+ sc->set_events(events);
+ }
+
sc->set_meta("original", events.duplicate(true));
}
@@ -1494,7 +1501,7 @@ Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, cons
#ifdef MACOS_ENABLED
// Use Cmd+Backspace as a general replacement for Delete shortcuts on macOS
if (keycode == Key::KEY_DELETE) {
- keycode = KeyModifierMask::CMD | Key::BACKSPACE;
+ keycode = KeyModifierMask::META | Key::BACKSPACE;
}
#endif
@@ -1530,7 +1537,7 @@ Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, cons
return sc;
}
-void EditorSettings::set_builtin_action_override(const String &p_name, const Array &p_events) {
+void EditorSettings::set_builtin_action_override(const String &p_name, const TypedArray<InputEvent> &p_events) {
List<Ref<InputEvent>> event_list;
// Override the whole list, since events may have their order changed or be added, removed or edited.
@@ -1621,8 +1628,6 @@ void EditorSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_setting", "name"), &EditorSettings::get_setting);
ClassDB::bind_method(D_METHOD("erase", "property"), &EditorSettings::erase);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value", "update_current"), &EditorSettings::set_initial_value);
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &EditorSettings::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert);
ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind);
ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index 5faeec88c8..4dcf3a9cad 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -100,6 +100,8 @@ private:
void _initial_set(const StringName &p_name, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_list) const;
void _add_property_info_bind(const Dictionary &p_info);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
void _load_defaults(Ref<ConfigFile> p_extra_config = Ref<ConfigFile>());
void _load_godot2_text_editor_theme();
@@ -138,10 +140,8 @@ public:
_set_only(p_setting, p_value);
}
}
- bool property_can_revert(const String &p_setting);
- Variant property_get_revert(const String &p_setting);
void add_property_hint(const PropertyInfo &p_hint);
- Array get_changed_settings() const;
+ PackedStringArray get_changed_settings() const;
bool check_changed_settings_in_group(const String &p_setting_prefix) const;
void mark_setting_changed(const String &p_setting);
@@ -175,7 +175,7 @@ public:
Ref<Shortcut> get_shortcut(const String &p_name) const;
void get_shortcut_list(List<String> *r_shortcuts);
- void set_builtin_action_override(const String &p_name, const Array &p_events);
+ void set_builtin_action_override(const String &p_name, const TypedArray<InputEvent> &p_events);
const Array get_builtin_action_overrides(const String &p_name) const;
void notify_changes();
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 08ff63551f..ec67cde112 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_property_name_processor.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/margin_container.h"
void EditorSettingsDialog::ok_pressed() {
@@ -124,9 +125,9 @@ void EditorSettingsDialog::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr);
- undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr);
- undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
+ undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr);
+ undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr);
+ undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -174,7 +175,7 @@ void EditorSettingsDialog::shortcut_input(const Ref<InputEvent> &p_event) {
handled = true;
}
- if (k->get_keycode_with_modifiers() == (KeyModifierMask::CMD | Key::F)) {
+ if (k->is_match(InputEventKey::create_reference(KeyModifierMask::CMD_OR_CTRL | Key::F))) {
_focus_current_search_box();
handled = true;
}
@@ -192,7 +193,7 @@ void EditorSettingsDialog::_update_icons() {
shortcut_search_box->set_clear_button_enabled(true);
restart_close_button->set_icon(shortcuts->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
- restart_container->add_theme_style_override("panel", shortcuts->get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ restart_container->add_theme_style_override("panel", shortcuts->get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
restart_icon->set_texture(shortcuts->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
restart_label->add_theme_color_override("font_color", shortcuts->get_theme_color(SNAME("warning_color"), SNAME("Editor")));
}
@@ -439,7 +440,7 @@ void EditorSettingsDialog::_update_shortcuts() {
const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style);
section->set_text(0, item_name);
- section->set_tooltip(0, tooltip);
+ section->set_tooltip_text(0, tooltip);
section->set_selectable(0, false);
section->set_selectable(1, false);
section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
@@ -680,7 +681,7 @@ void EditorSettingsDialog::_bind_methods() {
EditorSettingsDialog::EditorSettingsDialog() {
set_title(TTR("Editor Settings"));
- undo_redo = memnew(UndoRedo);
+ undo_redo = EditorNode::get_undo_redo();
tabs = memnew(TabContainer);
tabs->set_theme_type_variation("TabContainerOdd");
@@ -776,5 +777,4 @@ EditorSettingsDialog::EditorSettingsDialog() {
}
EditorSettingsDialog::~EditorSettingsDialog() {
- memdelete(undo_redo);
}
diff --git a/editor/editor_settings_dialog.h b/editor/editor_settings_dialog.h
index a1ea54c6fb..87ed6a77eb 100644
--- a/editor/editor_settings_dialog.h
+++ b/editor/editor_settings_dialog.h
@@ -40,6 +40,8 @@
#include "scene/gui/tab_container.h"
#include "scene/gui/texture_rect.h"
+class EditorUndoRedoManager;
+
class EditorSettingsDialog : public AcceptDialog {
GDCLASS(EditorSettingsDialog, AcceptDialog);
@@ -73,7 +75,7 @@ class EditorSettingsDialog : public AcceptDialog {
Timer *timer = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void cancel_pressed() override;
virtual void ok_pressed() override;
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 20e9d7a3df..4cd046e811 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -42,7 +42,7 @@ String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
#else
Key key = Key::CTRL;
#endif
- return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers. Hold Shift for more precise changes."), find_keycode_name(key));
+ return TS->format_number(rtos(get_value())) + "\n\n" + vformat(TTR("Hold %s to round to integers.\nHold Shift for more precise changes."), find_keycode_name(key));
}
return TS->format_number(rtos(get_value()));
}
@@ -82,7 +82,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
if (grabbing_spinner) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
Input::get_singleton()->warp_mouse(grabbing_spinner_mouse_pos);
- update();
+ queue_redraw();
} else {
_focus_entered();
}
@@ -93,7 +93,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
} else if (mb->get_button_index() == MouseButton::WHEEL_UP || mb->get_button_index() == MouseButton::WHEEL_DOWN) {
if (grabber->is_visible()) {
- call_deferred(SNAME("update"));
+ call_deferred(SNAME("queue_redraw"));
}
}
}
@@ -121,7 +121,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
pre_grab_value = get_max();
}
- if (mm->is_command_pressed()) {
+ if (mm->is_command_or_control_pressed()) {
// If control was just pressed, don't make the value do a huge jump in magnitude.
if (grabbing_spinner_dist_cache != 0) {
pre_grab_value += grabbing_spinner_dist_cache * get_step();
@@ -137,7 +137,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
bool new_hover = (mm->get_position().x > updown_offset);
if (new_hover != hover_updown) {
hover_updown = new_hover;
- update();
+ queue_redraw();
}
}
}
@@ -149,8 +149,16 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
+ if (read_only) {
+ return;
+ }
+
Ref<InputEventMouseButton> mb = p_event;
+ if (is_read_only()) {
+ return;
+ }
+
if (grabbing_grabber) {
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::WHEEL_UP) {
@@ -186,13 +194,13 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(Math::is_zero_approx(scale_x));
float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range) / scale_x;
set_as_ratio(grabbing_ratio + grabbing_ofs);
- update();
+ queue_redraw();
}
}
void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && k->is_pressed()) {
+ if (k.is_valid() && k->is_pressed() && !is_read_only()) {
double step = get_step();
double real_step = step;
if (step < 1) {
@@ -459,12 +467,12 @@ void EditorSpinSlider::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER: {
mouse_over_spin = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
mouse_over_spin = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -494,7 +502,7 @@ Size2 EditorSpinSlider::get_minimum_size() const {
void EditorSpinSlider::set_hide_slider(bool p_hide) {
hide_slider = p_hide;
- update();
+ queue_redraw();
}
bool EditorSpinSlider::is_hiding_slider() const {
@@ -503,7 +511,7 @@ bool EditorSpinSlider::is_hiding_slider() const {
void EditorSpinSlider::set_label(const String &p_label) {
label = p_label;
- update();
+ queue_redraw();
}
String EditorSpinSlider::get_label() const {
@@ -512,7 +520,7 @@ String EditorSpinSlider::get_label() const {
void EditorSpinSlider::set_suffix(const String &p_suffix) {
suffix = p_suffix;
- update();
+ queue_redraw();
}
String EditorSpinSlider::get_suffix() const {
@@ -579,17 +587,17 @@ void EditorSpinSlider::_value_focus_exited() {
void EditorSpinSlider::_grabber_mouse_entered() {
mouse_over_grabber = true;
- update();
+ queue_redraw();
}
void EditorSpinSlider::_grabber_mouse_exited() {
mouse_over_grabber = false;
- update();
+ queue_redraw();
}
void EditorSpinSlider::set_read_only(bool p_enable) {
read_only = p_enable;
- update();
+ queue_redraw();
}
bool EditorSpinSlider::is_read_only() const {
@@ -598,13 +606,17 @@ bool EditorSpinSlider::is_read_only() const {
void EditorSpinSlider::set_flat(bool p_enable) {
flat = p_enable;
- update();
+ queue_redraw();
}
bool EditorSpinSlider::is_flat() const {
return flat;
}
+bool EditorSpinSlider::is_grabbing() const {
+ return grabbing_grabber || grabbing_spinner;
+}
+
void EditorSpinSlider::_focus_entered() {
_ensure_input_popup();
Rect2 gr = get_screen_rect();
diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h
index f0adf5b7a1..afcaa3e4b6 100644
--- a/editor/editor_spin_slider.h
+++ b/editor/editor_spin_slider.h
@@ -110,6 +110,8 @@ public:
void set_flat(bool p_enable);
bool is_flat() const;
+ bool is_grabbing() const;
+
void setup_and_show() { _focus_entered(); }
LineEdit *get_line_edit();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index a3086a2ccf..9e983839f9 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -32,7 +32,6 @@
#include "core/error/error_macros.h"
#include "core/io/resource_loader.h"
-#include "core/variant/dictionary.h"
#include "editor/editor_fonts.h"
#include "editor/editor_icons.gen.h"
#include "editor/editor_scale.h"
@@ -43,27 +42,130 @@
#include "modules/svg/image_loader_svg.h"
#endif
+HashMap<Color, Color> EditorColorMap::editor_color_map;
+
+void EditorColorMap::add_color_pair(const String p_from_color, const String p_to_color) {
+ editor_color_map[Color::html(p_from_color)] = Color::html(p_to_color);
+}
+
+void EditorColorMap::create() {
+ // Some of the colors below are listed for completeness sake.
+ // This can be a basis for proper palette validation later.
+
+ // Convert: FROM TO
+ add_color_pair("#478cbf", "#478cbf"); // Godot Blue
+ add_color_pair("#414042", "#414042"); // Godot Gray
+
+ add_color_pair("#ffffff", "#414141"); // Pure white
+ add_color_pair("#000000", "#bfbfbf"); // Pure black
+ // Keep pure RGB colors as is, but list them for explicitly.
+ add_color_pair("#ff0000", "#ff0000"); // Pure red
+ add_color_pair("#00ff00", "#00ff00"); // Pure green
+ add_color_pair("#0000ff", "#0000ff"); // Pure blue
+
+ // GUI Colors
+ add_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
+ add_color_pair("#fefefe", "#fefefe"); // Forced light color
+ add_color_pair("#808080", "#808080"); // GUI disabled color
+ add_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
+ add_color_pair("#699ce8", "#699ce8"); // GUI highlight color
+ add_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
+
+ add_color_pair("#c38ef1", "#a85de9"); // Animation
+ add_color_pair("#fc7f7f", "#cd3838"); // Spatial
+ add_color_pair("#8da5f3", "#3d64dd"); // 2D
+ add_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
+ add_color_pair("#8eef97", "#2fa139"); // Control
+
+ add_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
+ add_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
+ add_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
+
+ // Rainbow
+ add_color_pair("#ff4545", "#ff2929"); // Red
+ add_color_pair("#ffe345", "#ffe337"); // Yellow
+ add_color_pair("#80ff45", "#74ff34"); // Green
+ add_color_pair("#45ffa2", "#2cff98"); // Aqua
+ add_color_pair("#45d7ff", "#22ccff"); // Blue
+ add_color_pair("#8045ff", "#702aff"); // Purple
+ add_color_pair("#ff4596", "#ff2781"); // Pink
+
+ // Audio gradients
+ add_color_pair("#e1da5b", "#d6cf4b"); // Yellow
+
+ add_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
+ add_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
+ add_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
+
+ add_color_pair("#f70000", "#c91616"); // Color track red
+ add_color_pair("#eec315", "#d58c0b"); // Color track orange
+ add_color_pair("#dbee15", "#b7d10a"); // Color track yellow
+ add_color_pair("#288027", "#218309"); // Color track green
+
+ // Resource groups
+ add_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
+ add_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
+ add_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
+
+ // Animation editor tracks
+ // The property track icon color is set by the common icon color.
+ add_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
+ add_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
+ add_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
+ add_color_pair("#3cf34e", "#16a827"); // Call Method track
+ add_color_pair("#2877f6", "#236be6"); // Bezier Curve track
+ add_color_pair("#eae440", "#9f9722"); // Audio Playback track
+ add_color_pair("#a448f0", "#9853ce"); // Animation Playback track
+ add_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
+
+ // Control layouts
+ add_color_pair("#d6d6d6", "#474747"); // Highlighted part
+ add_color_pair("#474747", "#d6d6d6"); // Background part
+ add_color_pair("#919191", "#6e6e6e"); // Border part
+
+ // TileSet editor icons
+ add_color_pair("#fce00e", "#aa8d24"); // New Single Tile
+ add_color_pair("#0e71fc", "#0350bd"); // New Autotile
+ add_color_pair("#c6ced4", "#828f9b"); // New Atlas
+
+ // Visual script
+ add_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
+ add_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
+ add_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
+ add_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
+ add_color_pair("#4593ec", "#4690e7"); // VisualScript String
+ add_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
+ add_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
+ add_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
+ add_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
+ add_color_pair("#f74949", "#f77070"); // VisualScript Plane
+ add_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
+ add_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
+ add_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
+ add_color_pair("#f68f45", "#f49047"); // VisualScript Transform
+ add_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
+ add_color_pair("#41ec80", "#2ce573"); // VisualScript RID
+ add_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
+ add_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
+ // Visual shaders
+ add_color_pair("#77ce57", "#67c046"); // Vector funcs
+ add_color_pair("#ea686c", "#d95256"); // Vector transforms
+ add_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
+ add_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+}
+
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
Ref<StyleBoxTexture> style(memnew(StyleBoxTexture));
style->set_texture(p_texture);
- style->set_margin_size(SIDE_LEFT, p_left * EDSCALE);
- style->set_margin_size(SIDE_RIGHT, p_right * EDSCALE);
- style->set_margin_size(SIDE_BOTTOM, p_bottom * EDSCALE);
- style->set_margin_size(SIDE_TOP, p_top * EDSCALE);
- style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
+ style->set_margin_size_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE);
+ style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
style->set_draw_center(p_draw_center);
return style;
}
static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty));
- style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
+ style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
return style;
}
@@ -71,12 +173,9 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left =
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
// Adjust level of detail based on the corners' effective sizes.
- style->set_corner_detail(Math::ceil(1.5 * p_corner_width * EDSCALE));
+ style->set_corner_detail(Math::ceil(0.8 * p_corner_width * EDSCALE));
style->set_corner_radius_all(p_corner_width * EDSCALE);
- style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
+ style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
// Work around issue about antialiased edges being blurrier (GH-35279).
style->set_anti_aliased(false);
return style;
@@ -113,7 +212,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
#ifdef MODULE_SVG_ENABLED
// See also `generate_icon()` in `scene/resources/default_theme.cpp`.
-static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, float p_saturation = 1.0, Dictionary p_convert_colors = Dictionary()) {
+static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float p_saturation, const HashMap<Color, Color> &p_convert_colors = HashMap<Color, Color>()) {
Ref<Image> img = memnew(Image);
// Upsample icon generation only if the editor scale isn't an integer multiplier.
@@ -121,8 +220,7 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color,
// with integer editor scales.
const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale);
ImageLoaderSVG img_loader;
- img_loader.set_replace_colors(p_convert_colors);
- img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_color);
+ img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors);
if (p_saturation != 1.0) {
img->adjust_bcs(1.0, 1.0, p_saturation);
}
@@ -132,126 +230,18 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color,
}
#endif
-#ifndef ADD_CONVERT_COLOR
-#define ADD_CONVERT_COLOR(dictionary, old_color, new_color) dictionary[Color::html(old_color)] = Color::html(new_color)
-#endif
-
void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false, float p_icon_saturation = 1.0) {
#ifdef MODULE_SVG_ENABLED
- // The default icon theme is designed to be used for a dark theme.
- // This dictionary stores Color values to convert to other colors
- // for better readability on a light theme.
- // Godot Color values are used to avoid the ambiguity of strings
- // (where "#ffffff", "fff", and "white" are all equivalent).
- Dictionary dark_icon_color_dictionary;
+ HashMap<Color, Color> icon_color_map;
// The names of the icons to never convert, even if one of their colors
// are contained in the dictionary above.
HashSet<StringName> exceptions;
- // Some of the colors below are listed for completeness sake.
- // This can be a basis for proper palette validation later.
if (!p_dark_theme) {
- // Convert color: FROM TO
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#478cbf", "#478cbf"); // Godot Blue
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#414042", "#414042"); // Godot Gray
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#414141"); // Pure white
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#000000", "#bfbfbf"); // Pure black
- // Keep pure RGB colors as is, but list them for explicitly.
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff0000", "#ff0000"); // Pure red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#00ff00", "#00ff00"); // Pure green
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0000ff", "#0000ff"); // Pure blue
-
- // GUI Colors
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // Common icon color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fefefe", "#fefefe"); // Forced light color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#808080", "#808080"); // GUI disabled color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b3b3b3", "#363636"); // GUI disabled light color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#699ce8", "#699ce8"); // GUI highlight color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f9f9f9", "#606060"); // Scrollbar grabber highlight color
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c38ef1", "#a85de9"); // Animation
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fc7f7f", "#cd3838"); // Spatial
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8da5f3", "#3d64dd"); // 2D
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4b70ea", "#1a3eac"); // 2D Dark
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8eef97", "#2fa139"); // Control
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5fb2ff", "#0079f0"); // Selection (blue)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#003e7a", "#2b74bb"); // Selection (darker blue)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f7f5cf", "#615f3a"); // Gizmo (yellow)
-
- // Rainbow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4545", "#ff2929"); // Red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffe345", "#ffe337"); // Yellow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#80ff45", "#74ff34"); // Green
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45ffa2", "#2cff98"); // Aqua
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45d7ff", "#22ccff"); // Blue
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8045ff", "#702aff"); // Purple
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4596", "#ff2781"); // Pink
-
- // Audio gradients
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1da5b", "#d6cf4b"); // Yellow
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#62aeff", "#1678e0"); // Frozen gradient top
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#75d1e6", "#41acc5"); // Frozen gradient middle
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#84ffee", "#49ccba"); // Frozen gradient bottom
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f70000", "#c91616"); // Color track red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eec315", "#d58c0b"); // Color track orange
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#dbee15", "#b7d10a"); // Color track yellow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#288027", "#218309"); // Color track green
-
- // Resource groups
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffca5f", "#fea900"); // Mesh resource (orange)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#2998ff", "#68b6ff"); // Shape resource (blue)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a2d2ff", "#4998e3"); // Shape resource (light blue)
-
- // Animation editor tracks
- // The property track icon color is set by the common icon color.
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea7940", "#bd5e2c"); // 3D Position track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff2b88", "#bd165f"); // 3D Rotation track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eac840", "#bd9d1f"); // 3D Scale track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#3cf34e", "#16a827"); // Call Method track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#2877f6", "#236be6"); // Bezier Curve track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae440", "#9f9722"); // Audio Playback track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a448f0", "#9853ce"); // Animation Playback track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5ad5c4", "#0a9c88"); // Blend Shape track
-
- // Control layouts
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#d6d6d6", "#474747"); // Highlighted part
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#474747", "#d6d6d6"); // Background part
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#919191", "#6e6e6e"); // Border part
-
- // TileSet editor icons
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fce00e", "#aa8d24"); // New Single Tile
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0e71fc", "#0350bd"); // New Autotile
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c6ced4", "#828f9b"); // New Atlas
-
- // Visual script
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ecad", "#25e3a0"); // VisualScript variant
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#6f91f0", "#6d8eeb"); // VisualScript bool
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5abbef", "#4fb2e9"); // VisualScript int
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#35d4f4", "#27ccf0"); // VisualScript float
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4593ec", "#4690e7"); // VisualScript String
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ac73f1", "#ad76ee"); // VisualScript Vector2
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f1738f", "#ee758e"); // VisualScript Rect2
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#de66f0", "#dc6aed"); // VisualScript Vector3
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b9ec41", "#96ce1a"); // VisualScript Transform2D
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f74949", "#f77070"); // VisualScript Plane
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ec418e", "#ec69a3"); // VisualScript Quat
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ee5677", "#ee7991"); // VisualScript AABB
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1ec41", "#b2bb19"); // VisualScript Basis
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f68f45", "#f49047"); // VisualScript Transform
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#417aec", "#6993ec"); // VisualScript NodePath
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ec80", "#2ce573"); // VisualScript RID
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#55f3e3", "#12d5c3"); // VisualScript Object
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#54ed9e", "#57e99f"); // VisualScript Dictionary
- // Visual shaders
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#77ce57", "#67c046"); // Vector funcs
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea686c", "#d95256"); // Vector transforms
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eac968", "#d9b64f"); // Textures and cubemaps
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#cf68ea", "#c050dd"); // Functions and expressions
+ for (KeyValue<Color, Color> &E : EditorColorMap::get()) {
+ icon_color_map[E.key] = E.value;
+ }
exceptions.insert("EditorPivot");
exceptions.insert("EditorHandle");
@@ -291,18 +281,18 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
const Color error_color = p_theme->get_color(SNAME("error_color"), SNAME("Editor"));
const Color success_color = p_theme->get_color(SNAME("success_color"), SNAME("Editor"));
const Color warning_color = p_theme->get_color(SNAME("warning_color"), SNAME("Editor"));
- dark_icon_color_dictionary[Color::html("#ff5f5f")] = error_color;
- dark_icon_color_dictionary[Color::html("#5fff97")] = success_color;
- dark_icon_color_dictionary[Color::html("#ffdd65")] = warning_color;
+ icon_color_map[Color::html("#ff5f5f")] = error_color;
+ icon_color_map[Color::html("#5fff97")] = success_color;
+ icon_color_map[Color::html("#ffdd65")] = warning_color;
// Use the accent color for some icons (checkbox, radio, toggle, etc.).
- Dictionary accent_color_icon_color_dictionary;
+ HashMap<Color, Color> accent_color_map;
HashSet<StringName> accent_color_icons;
const Color accent_color = p_theme->get_color(SNAME("accent_color"), SNAME("Editor"));
- accent_color_icon_color_dictionary[Color::html("699ce8")] = accent_color;
+ accent_color_map[Color::html("699ce8")] = accent_color;
if (accent_color.get_luminance() > 0.75) {
- accent_color_icon_color_dictionary[Color::html("ffffff")] = Color(0.2, 0.2, 0.2);
+ accent_color_map[Color::html("ffffff")] = Color(0.2, 0.2, 0.2);
}
accent_color_icons.insert("GuiChecked");
@@ -318,7 +308,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
Ref<ImageTexture> icon;
if (accent_color_icons.has(editor_icons_names[i])) {
- icon = editor_generate_icon(i, true, EDSCALE, 1.0, accent_color_icon_color_dictionary);
+ icon = editor_generate_icon(i, EDSCALE, 1.0, accent_color_map);
} else {
float saturation = p_icon_saturation;
@@ -327,7 +317,11 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
}
const int is_exception = exceptions.has(editor_icons_names[i]);
- icon = editor_generate_icon(i, !is_exception, EDSCALE, saturation, dark_icon_color_dictionary);
+ if (is_exception) {
+ icon = editor_generate_icon(i, EDSCALE, saturation);
+ } else {
+ icon = editor_generate_icon(i, EDSCALE, saturation, icon_color_map);
+ }
}
p_theme->set_icon(editor_icons_names[i], SNAME("EditorIcons"), icon);
@@ -342,7 +336,13 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
for (int i = 0; i < editor_bg_thumbs_count; i++) {
const int index = editor_bg_thumbs_indices[i];
const int is_exception = exceptions.has(editor_icons_names[index]);
- const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter, dark_icon_color_dictionary);
+
+ Ref<ImageTexture> icon;
+ if (!p_dark_theme && !is_exception) {
+ icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+ } else {
+ icon = editor_generate_icon(index, scale, force_filter);
+ }
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
}
@@ -351,7 +351,13 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
for (int i = 0; i < editor_md_thumbs_count; i++) {
const int index = editor_md_thumbs_indices[i];
const bool is_exception = exceptions.has(editor_icons_names[index]);
- const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter, dark_icon_color_dictionary);
+
+ Ref<ImageTexture> icon;
+ if (!p_dark_theme && !is_exception) {
+ icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+ } else {
+ icon = editor_generate_icon(index, scale, force_filter);
+ }
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
}
@@ -458,6 +464,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color font_color = mono_color.lerp(base_color, 0.25);
const Color font_hover_color = mono_color.lerp(base_color, 0.125);
const Color font_focus_color = mono_color.lerp(base_color, 0.125);
+ const Color font_hover_pressed_color = font_hover_color.lerp(accent_color, 0.74);
const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3);
const Color font_readonly_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.65);
const Color font_placeholder_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.6);
@@ -518,8 +525,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color warning_color = Color(1, 0.87, 0.4);
Color error_color = Color(1, 0.47, 0.42);
Color property_color = font_color.lerp(Color(0.5, 0.5, 0.5), 0.5);
- Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
- Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
+ Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
+ Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
if (!dark_theme) {
// Darken some colors to be readable on a light background
@@ -574,7 +581,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_default = make_flat_stylebox(base_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size, corner_width);
style_default->set_border_width_all(border_width);
style_default->set_border_color(base_color);
- style_default->set_draw_center(true);
// Button and widgets
const float extra_spacing = EDITOR_GET("interface/theme/additional_spacing");
@@ -582,10 +588,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Vector2 widget_default_margin = Vector2(extra_spacing + 6, extra_spacing + default_margin_size + 1) * EDSCALE;
Ref<StyleBoxFlat> style_widget = style_default->duplicate();
- style_widget->set_default_margin(SIDE_LEFT, widget_default_margin.x);
- style_widget->set_default_margin(SIDE_TOP, widget_default_margin.y);
- style_widget->set_default_margin(SIDE_RIGHT, widget_default_margin.x);
- style_widget->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
+ style_widget->set_default_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y);
style_widget->set_bg_color(dark_color_1);
style_widget->set_border_color(dark_color_2);
@@ -608,14 +611,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Style for windows, popups, etc..
Ref<StyleBoxFlat> style_popup = style_default->duplicate();
const int popup_margin_size = default_margin_size * EDSCALE * 3;
- style_popup->set_default_margin(SIDE_LEFT, popup_margin_size);
- style_popup->set_default_margin(SIDE_TOP, popup_margin_size);
- style_popup->set_default_margin(SIDE_RIGHT, popup_margin_size);
- style_popup->set_default_margin(SIDE_BOTTOM, popup_margin_size);
+ style_popup->set_default_margin_all(popup_margin_size);
style_popup->set_border_color(contrast_color_1);
const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1);
style_popup->set_shadow_color(shadow_color);
style_popup->set_shadow_size(4 * EDSCALE);
+ // Popups are separate windows by default in the editor. Windows currently don't support per-pixel transparency
+ // in 4.0, and even if it was, it may not always work in practice (e.g. running with compositing disabled).
+ style_popup->set_corner_radius_all(0);
Ref<StyleBoxLine> style_popup_separator(memnew(StyleBoxLine));
style_popup_separator->set_color(separator_color);
@@ -637,45 +640,41 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// TabBar
- Ref<StyleBoxFlat> style_tab_selected = style_widget->duplicate();
+ Ref<StyleBoxFlat> style_tab_base = style_widget->duplicate();
- // Add a highlight line at the top of the selected tab.
- style_tab_selected->set_border_width_all(0);
- style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x - border_width);
- style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * EDSCALE));
- // Make the highlight line prominent, but not too prominent as to not be distracting.
- Color tab_highlight = dark_color_2.lerp(accent_color, 0.75);
- style_tab_selected->set_border_color(tab_highlight);
+ style_tab_base->set_border_width_all(0);
// Don't round the top corners to avoid creating a small blank space between the tabs and the main panel.
// This also makes the top highlight look better.
- style_tab_selected->set_corner_radius_all(0);
-
- // Prevent visible artifacts and cover the top-left rounded corner of the panel below the tab if selected
- // We can't prevent them with both rounded corners and non-zero border width, though
- style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width);
+ style_tab_base->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
+ style_tab_base->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
// When using a border width greater than 0, visually line up the left of the selected tab with the underlying panel.
- style_tab_selected->set_expand_margin_size(SIDE_LEFT, -border_width);
+ style_tab_base->set_expand_margin_size(SIDE_LEFT, -border_width);
+
+ style_tab_base->set_default_margin(SIDE_LEFT, widget_default_margin.x + 5 * EDSCALE);
+ style_tab_base->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 5 * EDSCALE);
+ style_tab_base->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
+ style_tab_base->set_default_margin(SIDE_TOP, widget_default_margin.y);
+
+ Ref<StyleBoxFlat> style_tab_selected = style_tab_base->duplicate();
- style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE);
- style_tab_selected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE);
- style_tab_selected->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
- style_tab_selected->set_default_margin(SIDE_TOP, widget_default_margin.y);
style_tab_selected->set_bg_color(base_color);
+ // Add a highlight line at the top of the selected tab.
+ style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * EDSCALE));
+ // Make the highlight line prominent, but not too prominent as to not be distracting.
+ Color tab_highlight = dark_color_2.lerp(accent_color, 0.75);
+ style_tab_selected->set_border_color(tab_highlight);
+ style_tab_selected->set_corner_radius_all(0);
- Ref<StyleBoxFlat> style_tab_unselected = style_tab_selected->duplicate();
- style_tab_unselected->set_bg_color(dark_color_1);
+ Ref<StyleBoxFlat> style_tab_unselected = style_tab_base->duplicate();
style_tab_unselected->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_unselected->set_bg_color(dark_color_1);
// Add some spacing between unselected tabs to make them easier to distinguish from each other
style_tab_unselected->set_border_color(Color(0, 0, 0, 0));
- style_tab_unselected->set_border_width(SIDE_LEFT, Math::round(1 * EDSCALE));
- style_tab_unselected->set_border_width(SIDE_RIGHT, Math::round(1 * EDSCALE));
- style_tab_unselected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE);
- style_tab_unselected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE);
- Ref<StyleBoxFlat> style_tab_disabled = style_tab_selected->duplicate();
- style_tab_disabled->set_bg_color(disabled_bg_color);
+ Ref<StyleBoxFlat> style_tab_disabled = style_tab_base->duplicate();
style_tab_disabled->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_disabled->set_bg_color(disabled_bg_color);
style_tab_disabled->set_border_color(disabled_bg_color);
// Editor background
@@ -721,8 +720,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("ScriptEditorPanel", "EditorStyles", make_empty_stylebox(default_margin_size, 0, default_margin_size, default_margin_size));
theme->set_stylebox("ScriptEditor", "EditorStyles", make_empty_stylebox(0, 0, 0, 0));
- // Play button group
- theme->set_stylebox("PlayButtonPanel", "EditorStyles", style_empty);
+ // Launch Pad and Play buttons
+ Ref<StyleBoxFlat> style_launch_pad = make_flat_stylebox(dark_color_1, 2 * EDSCALE, 0, 2 * EDSCALE, 0, corner_width);
+ style_launch_pad->set_corner_radius_all(corner_radius * EDSCALE);
+ theme->set_stylebox("LaunchPadNormal", "EditorStyles", style_launch_pad);
+ Ref<StyleBoxFlat> style_launch_pad_movie = style_launch_pad->duplicate();
+ style_launch_pad_movie->set_bg_color(accent_color * Color(1, 1, 1, 0.1));
+ style_launch_pad_movie->set_border_color(accent_color);
+ style_launch_pad_movie->set_border_width_all(Math::round(2 * EDSCALE));
+ theme->set_stylebox("LaunchPadMovieMode", "EditorStyles", style_launch_pad_movie);
+
+ theme->set_stylebox("MovieWriterButtonNormal", "EditorStyles", make_empty_stylebox(0, 0, 0, 0));
+ Ref<StyleBoxFlat> style_write_movie_button = style_widget_pressed->duplicate();
+ style_write_movie_button->set_bg_color(accent_color);
+ style_write_movie_button->set_corner_radius_all(corner_radius * EDSCALE);
+ style_write_movie_button->set_default_margin(SIDE_TOP, 0);
+ style_write_movie_button->set_default_margin(SIDE_BOTTOM, 0);
+ style_write_movie_button->set_default_margin(SIDE_LEFT, 0);
+ style_write_movie_button->set_default_margin(SIDE_RIGHT, 0);
+ style_write_movie_button->set_expand_margin_size(SIDE_RIGHT, 2 * EDSCALE);
+ theme->set_stylebox("MovieWriterButtonPressed", "EditorStyles", style_write_movie_button);
theme->set_stylebox("normal", "MenuButton", style_menu);
theme->set_stylebox("hover", "MenuButton", style_widget_hover);
@@ -732,6 +749,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "MenuButton", font_color);
theme->set_color("font_hover_color", "MenuButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "MenuButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "MenuButton", font_focus_color);
theme->set_stylebox("MenuHover", "EditorStyles", style_widget_hover);
@@ -745,6 +763,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "Button", font_color);
theme->set_color("font_hover_color", "Button", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "Button", font_hover_pressed_color);
theme->set_color("font_focus_color", "Button", font_focus_color);
theme->set_color("font_pressed_color", "Button", accent_color);
theme->set_color("font_disabled_color", "Button", font_disabled_color);
@@ -788,6 +807,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
editor_log_button_pressed->set_border_color(accent_color);
theme->set_stylebox("pressed", "EditorLogFilterButton", editor_log_button_pressed);
+ // MenuBar
+ theme->set_stylebox("normal", "MenuBar", style_widget);
+ theme->set_stylebox("hover", "MenuBar", style_widget_hover);
+ theme->set_stylebox("pressed", "MenuBar", style_widget_pressed);
+ theme->set_stylebox("focus", "MenuBar", style_widget_focus);
+ theme->set_stylebox("disabled", "MenuBar", style_widget_disabled);
+
+ theme->set_color("font_color", "MenuBar", font_color);
+ theme->set_color("font_hover_color", "MenuBar", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "MenuBar", font_hover_pressed_color);
+ theme->set_color("font_focus_color", "MenuBar", font_focus_color);
+ theme->set_color("font_pressed_color", "MenuBar", accent_color);
+ theme->set_color("font_disabled_color", "MenuBar", font_disabled_color);
+
+ theme->set_color("icon_normal_color", "MenuBar", icon_normal_color);
+ theme->set_color("icon_hover_color", "MenuBar", icon_hover_color);
+ theme->set_color("icon_focus_color", "MenuBar", icon_focus_color);
+ theme->set_color("icon_pressed_color", "MenuBar", icon_pressed_color);
+ theme->set_color("icon_disabled_color", "MenuBar", icon_disabled_color);
+
// OptionButton
Ref<StyleBoxFlat> style_option_button_focus = style_widget_focus->duplicate();
Ref<StyleBoxFlat> style_option_button_normal = style_widget->duplicate();
@@ -814,6 +853,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "OptionButton", font_color);
theme->set_color("font_hover_color", "OptionButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "OptionButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "OptionButton", font_focus_color);
theme->set_color("font_pressed_color", "OptionButton", accent_color);
theme->set_color("font_disabled_color", "OptionButton", font_disabled_color);
@@ -836,18 +876,19 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("hover", "CheckButton", style_menu);
theme->set_stylebox("hover_pressed", "CheckButton", style_menu);
- theme->set_icon("on", "CheckButton", theme->get_icon(SNAME("GuiToggleOn"), SNAME("EditorIcons")));
- theme->set_icon("on_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabled"), SNAME("EditorIcons")));
- theme->set_icon("off", "CheckButton", theme->get_icon(SNAME("GuiToggleOff"), SNAME("EditorIcons")));
- theme->set_icon("off_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabled"), SNAME("EditorIcons")));
+ theme->set_icon("checked", "CheckButton", theme->get_icon(SNAME("GuiToggleOn"), SNAME("EditorIcons")));
+ theme->set_icon("checked_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabled"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked", "CheckButton", theme->get_icon(SNAME("GuiToggleOff"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabled"), SNAME("EditorIcons")));
- theme->set_icon("on_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnMirrored"), SNAME("EditorIcons")));
- theme->set_icon("on_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabledMirrored"), SNAME("EditorIcons")));
- theme->set_icon("off_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffMirrored"), SNAME("EditorIcons")));
- theme->set_icon("off_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabledMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("checked_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("checked_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabledMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffMirrored"), SNAME("EditorIcons")));
+ theme->set_icon("unchecked_disabled_mirrored", "CheckButton", theme->get_icon(SNAME("GuiToggleOffDisabledMirrored"), SNAME("EditorIcons")));
theme->set_color("font_color", "CheckButton", font_color);
theme->set_color("font_hover_color", "CheckButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "CheckButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "CheckButton", font_focus_color);
theme->set_color("font_pressed_color", "CheckButton", accent_color);
theme->set_color("font_disabled_color", "CheckButton", font_disabled_color);
@@ -859,14 +900,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("icon_disabled_color", "CheckButton", icon_disabled_color);
theme->set_constant("h_separation", "CheckButton", 8 * EDSCALE);
- theme->set_constant("check_v_adjust", "CheckButton", 0 * EDSCALE);
+ theme->set_constant("check_v_offset", "CheckButton", 0 * EDSCALE);
// Checkbox
Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate();
- sb_checkbox->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
- sb_checkbox->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
- sb_checkbox->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
- sb_checkbox->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE);
+ sb_checkbox->set_default_margin_all(default_margin_size * EDSCALE);
theme->set_stylebox("normal", "CheckBox", sb_checkbox);
theme->set_stylebox("pressed", "CheckBox", sb_checkbox);
@@ -884,6 +922,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "CheckBox", font_color);
theme->set_color("font_hover_color", "CheckBox", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "CheckBox", font_hover_pressed_color);
theme->set_color("font_focus_color", "CheckBox", font_focus_color);
theme->set_color("font_pressed_color", "CheckBox", accent_color);
theme->set_color("font_disabled_color", "CheckBox", font_disabled_color);
@@ -895,7 +934,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("icon_disabled_color", "CheckBox", icon_disabled_color);
theme->set_constant("h_separation", "CheckBox", 8 * EDSCALE);
- theme->set_constant("check_v_adjust", "CheckBox", 0 * EDSCALE);
+ theme->set_constant("check_v_offset", "CheckBox", 0 * EDSCALE);
// PopupDialog
theme->set_stylebox("panel", "PopupDialog", style_popup);
@@ -905,10 +944,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn
// on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted,
// and it looks weird. 1px solves this.
- style_popup_menu->set_default_margin(SIDE_LEFT, EDSCALE);
- style_popup_menu->set_default_margin(SIDE_TOP, 2 * EDSCALE);
- style_popup_menu->set_default_margin(SIDE_RIGHT, EDSCALE);
- style_popup_menu->set_default_margin(SIDE_BOTTOM, 2 * EDSCALE);
+ style_popup_menu->set_default_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE);
// Always display a border for PopupMenus so they can be distinguished from their background.
style_popup_menu->set_border_width_all(EDSCALE);
style_popup_menu->set_border_color(dark_color_2);
@@ -964,10 +1000,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
sub_inspector_bg->set_bg_color(dark_color_1.lerp(si_base_color, 0.08));
sub_inspector_bg->set_border_width_all(2 * EDSCALE);
sub_inspector_bg->set_border_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8));
- sub_inspector_bg->set_default_margin(SIDE_LEFT, 4 * EDSCALE);
- sub_inspector_bg->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
- sub_inspector_bg->set_default_margin(SIDE_BOTTOM, 4 * EDSCALE);
- sub_inspector_bg->set_default_margin(SIDE_TOP, 4 * EDSCALE);
+ sub_inspector_bg->set_default_margin_all(4 * EDSCALE);
sub_inspector_bg->set_corner_radius(CORNER_TOP_LEFT, 0);
sub_inspector_bg->set_corner_radius(CORNER_TOP_RIGHT, 0);
@@ -1035,7 +1068,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Make Trees easier to distinguish from other controls by using a darker background color.
style_tree_bg->set_bg_color(dark_color_1.lerp(dark_color_2, 0.5));
style_tree_bg->set_border_color(dark_color_3);
- theme->set_stylebox("bg", "Tree", style_tree_bg);
+ theme->set_stylebox("panel", "Tree", style_tree_bg);
// Tree
theme->set_icon("checked", "Tree", theme->get_icon(SNAME("GuiChecked"), SNAME("EditorIcons")));
@@ -1046,7 +1079,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("arrow_collapsed_mirrored", "Tree", theme->get_icon(SNAME("GuiTreeArrowLeft"), SNAME("EditorIcons")));
theme->set_icon("updown", "Tree", theme->get_icon(SNAME("GuiTreeUpdown"), SNAME("EditorIcons")));
theme->set_icon("select_arrow", "Tree", theme->get_icon(SNAME("GuiDropdown"), SNAME("EditorIcons")));
- theme->set_stylebox("bg_focus", "Tree", style_widget_focus);
+ theme->set_stylebox("focus", "Tree", style_widget_focus);
theme->set_stylebox("custom_button", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_pressed", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_hover", "Tree", style_widget);
@@ -1137,21 +1170,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_itemlist_cursor->set_draw_center(false);
style_itemlist_cursor->set_border_width_all(border_width);
style_itemlist_cursor->set_border_color(highlight_color);
+ theme->set_stylebox("panel", "ItemList", style_itemlist_bg);
+ theme->set_stylebox("focus", "ItemList", style_widget_focus);
theme->set_stylebox("cursor", "ItemList", style_itemlist_cursor);
theme->set_stylebox("cursor_unfocused", "ItemList", style_itemlist_cursor);
theme->set_stylebox("selected_focus", "ItemList", style_tree_focus);
theme->set_stylebox("selected", "ItemList", style_tree_selected);
- theme->set_stylebox("bg_focus", "ItemList", style_widget_focus);
- theme->set_stylebox("bg", "ItemList", style_itemlist_bg);
theme->set_color("font_color", "ItemList", font_color);
theme->set_color("font_selected_color", "ItemList", mono_color);
theme->set_color("guide_color", "ItemList", guide_color);
- theme->set_constant("v_separation", "ItemList", widget_default_margin.y - EDSCALE);
+ theme->set_constant("v_separation", "ItemList", force_even_vsep * 0.5 * EDSCALE);
theme->set_constant("h_separation", "ItemList", 6 * EDSCALE);
theme->set_constant("icon_margin", "ItemList", 6 * EDSCALE);
theme->set_constant("line_separation", "ItemList", 3 * EDSCALE);
// TabBar & TabContainer
+ Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(dark_color_1, 0, 0, 0, 0, corner_radius * EDSCALE);
+ style_tabbar_background->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
+ style_tabbar_background->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
+ theme->set_stylebox("tabbar_background", "TabContainer", style_tabbar_background);
+
theme->set_stylebox("tab_selected", "TabContainer", style_tab_selected);
theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected);
theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled);
@@ -1160,8 +1198,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("tab_disabled", "TabBar", style_tab_disabled);
theme->set_stylebox("button_pressed", "TabBar", style_menu);
theme->set_stylebox("button_highlight", "TabBar", style_menu);
- theme->set_stylebox("SceneTabFG", "EditorStyles", style_tab_selected);
- theme->set_stylebox("SceneTabBG", "EditorStyles", style_tab_unselected);
theme->set_color("font_selected_color", "TabContainer", font_color);
theme->set_color("font_unselected_color", "TabContainer", font_disabled_color);
theme->set_color("font_selected_color", "TabBar", font_color);
@@ -1181,22 +1217,25 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("decrement_highlight", "TabContainer", theme->get_icon(SNAME("GuiScrollArrowLeftHl"), SNAME("EditorIcons")));
theme->set_icon("drop_mark", "TabContainer", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons")));
theme->set_icon("drop_mark", "TabBar", theme->get_icon(SNAME("GuiTabDropMark"), SNAME("EditorIcons")));
+ theme->set_constant("side_margin", "TabContainer", 0);
theme->set_constant("h_separation", "TabBar", 4 * EDSCALE);
- // Content of each tab
+ // Content of each tab.
Ref<StyleBoxFlat> style_content_panel = style_default->duplicate();
style_content_panel->set_border_color(dark_color_3);
style_content_panel->set_border_width_all(border_width);
- // compensate the border
- style_content_panel->set_default_margin(SIDE_TOP, (2 + margin_size_extra) * EDSCALE);
- style_content_panel->set_default_margin(SIDE_RIGHT, margin_size_extra * EDSCALE);
- style_content_panel->set_default_margin(SIDE_BOTTOM, margin_size_extra * EDSCALE);
- style_content_panel->set_default_margin(SIDE_LEFT, margin_size_extra * EDSCALE);
- // Display border to visually split the body of the container from its possible backgrounds.
- style_content_panel->set_border_width(Side::SIDE_TOP, Math::round(2 * EDSCALE));
- style_content_panel->set_border_color(dark_color_2);
+ style_content_panel->set_border_width(Side::SIDE_TOP, 0);
+ style_content_panel->set_corner_radius(CORNER_TOP_LEFT, 0);
+ style_content_panel->set_corner_radius(CORNER_TOP_RIGHT, 0);
+ // Compensate for the border.
+ style_content_panel->set_default_margin_individual(margin_size_extra * EDSCALE, (2 + margin_size_extra) * EDSCALE, margin_size_extra * EDSCALE, margin_size_extra * EDSCALE);
theme->set_stylebox("panel", "TabContainer", style_content_panel);
+ // Bottom panel.
+ Ref<StyleBoxFlat> style_bottom_panel = style_content_panel->duplicate();
+ style_bottom_panel->set_corner_radius_all(corner_radius * EDSCALE);
+ theme->set_stylebox("BottomPanel", "EditorStyles", style_bottom_panel);
+
// TabContainerOdd can be used on tabs against the base color background (e.g. nested tabs).
theme->set_type_variation("TabContainerOdd", "TabContainer");
@@ -1210,10 +1249,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// This stylebox is used in 3d and 2d viewports (no borders).
Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate();
- style_content_panel_vp->set_default_margin(SIDE_LEFT, border_width * 2);
- style_content_panel_vp->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
- style_content_panel_vp->set_default_margin(SIDE_RIGHT, border_width * 2);
- style_content_panel_vp->set_default_margin(SIDE_BOTTOM, border_width * 2);
+ style_content_panel_vp->set_default_margin_individual(border_width * 2, default_margin_size * EDSCALE, border_width * 2, border_width * 2);
theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp);
// This stylebox is used by preview tabs in the Theme Editor.
@@ -1262,7 +1298,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("focus", "LineEdit", style_widget_focus);
theme->set_stylebox("read_only", "LineEdit", style_line_edit_disabled);
theme->set_icon("clear", "LineEdit", theme->get_icon(SNAME("GuiClose"), SNAME("EditorIcons")));
- theme->set_color("read_only", "LineEdit", font_disabled_color);
theme->set_color("font_color", "LineEdit", font_color);
theme->set_color("font_selected_color", "LineEdit", mono_color);
theme->set_color("font_uneditable_color", "LineEdit", font_readonly_color);
@@ -1276,7 +1311,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("normal", "TextEdit", style_line_edit);
theme->set_stylebox("focus", "TextEdit", style_widget_focus);
theme->set_stylebox("read_only", "TextEdit", style_line_edit_disabled);
- theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon(SNAME("GuiTab"), SNAME("EditorIcons")));
theme->set_icon("space", "TextEdit", theme->get_icon(SNAME("GuiSpace"), SNAME("EditorIcons")));
theme->set_color("font_color", "TextEdit", font_color);
@@ -1286,12 +1320,17 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("selection_color", "TextEdit", selection_color);
theme->set_constant("line_spacing", "TextEdit", 4 * EDSCALE);
+ theme->set_icon("h_grabber", "SplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons")));
+ theme->set_icon("v_grabber", "SplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons")));
theme->set_icon("grabber", "VSplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons")));
theme->set_icon("grabber", "HSplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons")));
theme->set_constant("separation", "HSplitContainer", default_margin_size * 2 * EDSCALE);
theme->set_constant("separation", "VSplitContainer", default_margin_size * 2 * EDSCALE);
+ theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * EDSCALE);
+ theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * EDSCALE);
+
// Containers
theme->set_constant("separation", "BoxContainer", default_margin_size * EDSCALE);
theme->set_constant("separation", "HBoxContainer", default_margin_size * EDSCALE);
@@ -1351,6 +1390,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// AcceptDialog
theme->set_stylebox("panel", "AcceptDialog", style_window_title);
+ theme->set_constant("buttons_separation", "AcceptDialog", 8 * EDSCALE);
// HScrollBar
Ref<Texture2D> empty_icon = memnew(ImageTexture);
@@ -1439,6 +1479,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("focus", "LinkButton", style_empty);
theme->set_color("font_color", "LinkButton", font_color);
theme->set_color("font_hover_color", "LinkButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "LinkButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "LinkButton", font_focus_color);
theme->set_color("font_pressed_color", "LinkButton", accent_color);
theme->set_color("font_disabled_color", "LinkButton", font_disabled_color);
@@ -1448,26 +1489,34 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// is only relevant for default tooltips.
Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate();
style_tooltip->set_shadow_size(0);
- style_tooltip->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE * 0.5);
- style_tooltip->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE * 0.5);
+ style_tooltip->set_default_margin_all(default_margin_size * EDSCALE * 0.5);
style_tooltip->set_bg_color(dark_color_3 * Color(0.8, 0.8, 0.8, 0.9));
style_tooltip->set_border_width_all(0);
theme->set_color("font_color", "TooltipLabel", font_hover_color);
- theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0));
+ theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0));
theme->set_stylebox("panel", "TooltipPanel", style_tooltip);
// PopupPanel
theme->set_stylebox("panel", "PopupPanel", style_popup);
+ Ref<StyleBoxFlat> control_editor_popup_style = style_popup->duplicate();
+ control_editor_popup_style->set_shadow_size(0);
+ control_editor_popup_style->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_border_width_all(0);
+
+ theme->set_stylebox("panel", "ControlEditorPopupPanel", control_editor_popup_style);
+ theme->set_type_variation("ControlEditorPopupPanel", "PopupPanel");
+
// SpinBox
theme->set_icon("updown", "SpinBox", theme->get_icon(SNAME("GuiSpinboxUpdown"), SNAME("EditorIcons")));
theme->set_icon("updown_disabled", "SpinBox", theme->get_icon(SNAME("GuiSpinboxUpdownDisabled"), SNAME("EditorIcons")));
// ProgressBar
- theme->set_stylebox("bg", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressBar"), SNAME("EditorIcons")), 4, 4, 4, 4, 0, 0, 0, 0));
- theme->set_stylebox("fg", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressFill"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 1, 2, 1));
+ theme->set_stylebox("background", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressBar"), SNAME("EditorIcons")), 4, 4, 4, 4, 0, 0, 0, 0));
+ theme->set_stylebox("fill", "ProgressBar", make_stylebox(theme->get_icon(SNAME("GuiProgressFill"), SNAME("EditorIcons")), 6, 6, 6, 6, 2, 1, 2, 1));
theme->set_color("font_color", "ProgressBar", font_color);
// GraphEdit
@@ -1567,6 +1616,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
graphsbcomment->set_border_width(SIDE_TOP, 24 * EDSCALE);
graphsbcommentselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsb->set_corner_detail(corner_radius * EDSCALE);
+ graphsbselected->set_corner_detail(corner_radius * EDSCALE);
+ graphsbcomment->set_corner_detail(corner_radius * EDSCALE);
+ graphsbcommentselected->set_corner_detail(corner_radius * EDSCALE);
+
theme->set_stylebox("frame", "GraphNode", graphsb);
theme->set_stylebox("selected_frame", "GraphNode", graphsbselected);
theme->set_stylebox("comment", "GraphNode", graphsbcomment);
@@ -1608,7 +1662,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("toggle_hidden", "FileDialog", theme->get_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
// Use a different color for folder icons to make them easier to distinguish from files.
// On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color.
- theme->set_color("folder_icon_modulate", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(accent_color, 0.7));
+ theme->set_color("folder_icon_color", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(accent_color, 0.7));
theme->set_color("files_disabled", "FileDialog", font_disabled_color);
// ColorPicker
@@ -1817,14 +1871,14 @@ Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {
return theme;
}
-Ref<ImageTexture> create_unscaled_default_project_icon() {
-#ifdef MODULE_SVG_ENABLED
+/**
+ * Returns the SVG code for the default project icon.
+ */
+String get_default_project_icon() {
for (int i = 0; i < editor_icons_count; i++) {
- // ESCALE should never affect size of the icon
if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0) {
- return editor_generate_icon(i, false, 1.0);
+ return String(editor_icons_sources[i]);
}
}
-#endif
- return Ref<ImageTexture>(memnew(ImageTexture));
+ return String();
}
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 95184b9d4a..37db8160fa 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -34,10 +34,24 @@
#include "scene/resources/texture.h"
#include "scene/resources/theme.h"
+// The default icon theme is designed to be used for a dark theme. This map stores
+// Color values to convert to other colors for better readability on a light theme.
+class EditorColorMap {
+ // Godot Color values are used to avoid the ambiguity of strings
+ // (where "#ffffff", "fff", and "white" are all equivalent).
+ static HashMap<Color, Color> editor_color_map;
+
+public:
+ static void create();
+ static void add_color_pair(const String p_from_color, const String p_to_color);
+
+ static HashMap<Color, Color> &get() { return editor_color_map; };
+};
+
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
Ref<Theme> create_custom_theme(Ref<Theme> p_theme = nullptr);
-Ref<ImageTexture> create_unscaled_default_project_icon();
+String get_default_project_icon();
#endif // EDITOR_THEMES_H
diff --git a/editor/editor_title_bar.cpp b/editor/editor_title_bar.cpp
new file mode 100644
index 0000000000..06dcea1f8a
--- /dev/null
+++ b/editor/editor_title_bar.cpp
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* editor_title_bar.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 "editor/editor_title_bar.h"
+
+void EditorTitleBar::input(const Ref<InputEvent> &p_event) {
+ if (!can_move) {
+ return;
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && moving) {
+ if ((mm->get_button_mask() & MouseButton::LEFT) == MouseButton::LEFT) {
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w) {
+ Point2 mouse = DisplayServer::get_singleton()->mouse_get_position();
+ w->set_position(mouse - click_pos);
+ }
+ } else {
+ moving = false;
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && has_point(mb->get_position())) {
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ click_pos = DisplayServer::get_singleton()->mouse_get_position() - w->get_position();
+ moving = true;
+ } else {
+ moving = false;
+ }
+ }
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) {
+ if (DisplayServer::get_singleton()->window_maximize_on_title_dbl_click()) {
+ if (w->get_mode() == Window::MODE_WINDOWED) {
+ w->set_mode(Window::MODE_MAXIMIZED);
+ } else if (w->get_mode() == Window::MODE_MAXIMIZED) {
+ w->set_mode(Window::MODE_WINDOWED);
+ }
+ } else if (DisplayServer::get_singleton()->window_minimize_on_title_dbl_click()) {
+ w->set_mode(Window::MODE_MINIMIZED);
+ }
+ moving = false;
+ }
+ }
+ }
+}
+
+void EditorTitleBar::set_can_move_window(bool p_enabled) {
+ can_move = p_enabled;
+ set_process_input(can_move);
+}
+
+bool EditorTitleBar::get_can_move_window() const {
+ return can_move;
+}
diff --git a/editor/editor_title_bar.h b/editor/editor_title_bar.h
new file mode 100644
index 0000000000..ad6ec37ac9
--- /dev/null
+++ b/editor/editor_title_bar.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* editor_title_bar.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 EDITOR_TITLE_BAR_H
+#define EDITOR_TITLE_BAR_H
+
+#include "scene/gui/box_container.h"
+#include "scene/main/window.h"
+
+class EditorTitleBar : public HBoxContainer {
+ GDCLASS(EditorTitleBar, HBoxContainer);
+
+ Point2i click_pos;
+ bool moving = false;
+ bool can_move = false;
+
+protected:
+ virtual void input(const Ref<InputEvent> &p_event) override;
+ static void _bind_methods(){};
+
+public:
+ void set_can_move_window(bool p_enabled);
+ bool get_can_move_window() const;
+};
+
+#endif // EDITOR_TITLE_BAR_H
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 050cde6069..6a5242f0c6 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -62,7 +62,7 @@ void EditorToaster::_notification(int p_what) {
if (toasts[element.key].remaining_time < 0) {
close(element.key);
}
- element.key->update();
+ element.key->queue_redraw();
}
} else {
// Reset the timers when hovered.
@@ -71,7 +71,7 @@ void EditorToaster::_notification(int p_what) {
continue;
}
toasts[element.key].remaining_time = element.value.duration;
- element.key->update();
+ element.key->queue_redraw();
}
}
@@ -101,7 +101,7 @@ void EditorToaster::_notification(int p_what) {
if (needs_update) {
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
} break;
@@ -132,8 +132,8 @@ void EditorToaster::_notification(int p_what) {
error_panel_style_progress->set_bg_color(get_theme_color(SNAME("base_color"), SNAME("Editor")).lightened(0.03));
error_panel_style_progress->set_border_color(get_theme_color(SNAME("error_color"), SNAME("Editor")));
- main_button->update();
- disable_notifications_button->update();
+ main_button->queue_redraw();
+ disable_notifications_button->queue_redraw();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -236,11 +236,11 @@ void EditorToaster::_auto_hide_or_free_toasts() {
}
if (toasts.is_empty()) {
- main_button->set_tooltip(TTR("No notifications."));
+ main_button->set_tooltip_text(TTR("No notifications."));
main_button->set_modulate(Color(0.5, 0.5, 0.5));
main_button->set_disabled(true);
} else {
- main_button->set_tooltip(TTR("Show notifications."));
+ main_button->set_tooltip_text(TTR("Show notifications."));
main_button->set_modulate(Color(1, 1, 1));
main_button->set_disabled(false);
}
@@ -284,7 +284,7 @@ void EditorToaster::_draw_button() {
void EditorToaster::_draw_progress(Control *panel) {
if (toasts.has(panel) && toasts[panel].remaining_time > 0 && toasts[panel].duration > 0) {
Size2 size = panel->get_size();
- size.x *= MIN(1, Math::range_lerp(toasts[panel].remaining_time, 0, toasts[panel].duration, 0, 2));
+ size.x *= MIN(1, Math::remap(toasts[panel].remaining_time, 0, toasts[panel].duration, 0, 2));
Ref<StyleBoxFlat> stylebox;
switch (toasts[panel].severity) {
@@ -334,14 +334,14 @@ void EditorToaster::_repop_old() {
if (needs_update) {
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
}
Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_time, String p_tooltip) {
// Create the panel according to the severity.
PanelContainer *panel = memnew(PanelContainer);
- panel->set_tooltip(p_tooltip);
+ panel->set_tooltip_text(p_tooltip);
switch (p_severity) {
case SEVERITY_INFO:
panel->add_theme_style_override("panel", info_panel_style_background);
@@ -389,7 +389,7 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_
_auto_hide_or_free_toasts();
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
return panel;
}
@@ -438,7 +438,7 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t
_auto_hide_or_free_toasts();
_update_vbox_position();
_update_disable_notifications_button();
- main_button->update();
+ main_button->queue_redraw();
}
// Retrieve the label back then update the text.
@@ -498,10 +498,7 @@ EditorToaster::EditorToaster() {
Ref<StyleBoxFlat> boxes[] = { info_panel_style_background, warning_panel_style_background, error_panel_style_background };
for (int i = 0; i < 3; i++) {
- boxes[i]->set_default_margin(SIDE_LEFT, int(stylebox_radius * 2.5));
- boxes[i]->set_default_margin(SIDE_RIGHT, int(stylebox_radius * 2.5));
- boxes[i]->set_default_margin(SIDE_TOP, 3);
- boxes[i]->set_default_margin(SIDE_BOTTOM, 3);
+ boxes[i]->set_default_margin_individual(int(stylebox_radius * 2.5), 3, int(stylebox_radius * 2.5), 3);
}
// Theming (progress).
@@ -518,7 +515,7 @@ EditorToaster::EditorToaster() {
// Main button.
main_button = memnew(Button);
- main_button->set_tooltip(TTR("No notifications."));
+ main_button->set_tooltip_text(TTR("No notifications."));
main_button->set_modulate(Color(0.5, 0.5, 0.5));
main_button->set_disabled(true);
main_button->set_flat(true);
@@ -534,7 +531,7 @@ EditorToaster::EditorToaster() {
add_child(disable_notifications_panel);
disable_notifications_button = memnew(Button);
- disable_notifications_button->set_tooltip(TTR("Silence the notifications."));
+ disable_notifications_button->set_tooltip_text(TTR("Silence the notifications."));
disable_notifications_button->set_flat(true);
disable_notifications_button->connect("pressed", callable_mp(this, &EditorToaster::_set_notifications_enabled).bind(false));
disable_notifications_panel->add_child(disable_notifications_button);
diff --git a/editor/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp
index eb4df3b630..eb38e203a5 100644
--- a/editor/editor_translation_parser.cpp
+++ b/editor/editor_translation_parser.cpp
@@ -38,8 +38,8 @@
EditorTranslationParser *EditorTranslationParser::singleton = nullptr;
Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) {
- Array ids;
- Array ids_ctx_plural;
+ TypedArray<String> ids;
+ TypedArray<Array> ids_ctx_plural;
if (GDVIRTUAL_CALL(_parse_file, p_path, ids, ids_ctx_plural)) {
// Add user's extracted translatable messages.
diff --git a/editor/editor_translation_parser.h b/editor/editor_translation_parser.h
index bd770250f9..0fe166a0b0 100644
--- a/editor/editor_translation_parser.h
+++ b/editor/editor_translation_parser.h
@@ -35,6 +35,7 @@
#include "core/object/gdvirtual.gen.inc"
#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
+#include "core/variant/typed_array.h"
class EditorTranslationParserPlugin : public RefCounted {
GDCLASS(EditorTranslationParserPlugin, RefCounted);
@@ -42,7 +43,7 @@ class EditorTranslationParserPlugin : public RefCounted {
protected:
static void _bind_methods();
- GDVIRTUAL3(_parse_file, String, Array, Array)
+ GDVIRTUAL3(_parse_file, String, TypedArray<String>, TypedArray<Array>)
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
public:
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
new file mode 100644
index 0000000000..eca2b3143b
--- /dev/null
+++ b/editor/editor_undo_redo_manager.cpp
@@ -0,0 +1,442 @@
+/*************************************************************************/
+/* editor_undo_redo_manager.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 "editor_undo_redo_manager.h"
+
+#include "core/io/resource.h"
+#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "editor/editor_log.h"
+#include "editor/editor_node.h"
+#include "scene/main/node.h"
+
+EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) {
+ if (!history_map.has(p_idx)) {
+ History history;
+ history.undo_redo = memnew(UndoRedo);
+ history.id = p_idx;
+ history_map[p_idx] = history;
+
+ EditorNode::get_singleton()->get_log()->register_undo_redo(history.undo_redo);
+ EditorDebuggerNode::get_singleton()->register_undo_redo(history.undo_redo);
+ }
+ return history_map[p_idx];
+}
+
+UndoRedo *EditorUndoRedoManager::get_history_undo_redo(int p_idx) const {
+ ERR_FAIL_COND_V(!history_map.has(p_idx), nullptr);
+ return history_map[p_idx].undo_redo;
+}
+
+int EditorUndoRedoManager::get_history_id_for_object(Object *p_object) const {
+ int history_id = INVALID_HISTORY;
+
+ if (Node *node = Object::cast_to<Node>(p_object)) {
+ Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
+
+ if (edited_scene && (node == edited_scene || edited_scene->is_ancestor_of(node))) {
+ int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id();
+ if (idx > 0) {
+ history_id = idx;
+ }
+ }
+ }
+
+ if (Resource *res = Object::cast_to<Resource>(p_object)) {
+ if (res->is_built_in()) {
+ if (res->get_path().is_empty()) {
+ int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id();
+ if (idx > 0) {
+ history_id = idx;
+ }
+ } else {
+ int idx = EditorNode::get_singleton()->get_editor_data().get_scene_history_id_from_path(res->get_path().get_slice("::", 0));
+ if (idx > 0) {
+ history_id = idx;
+ }
+ }
+ }
+ }
+
+ if (history_id == INVALID_HISTORY) {
+ if (pending_action.history_id != INVALID_HISTORY) {
+ history_id = pending_action.history_id;
+ } else {
+ history_id = GLOBAL_HISTORY;
+ }
+ }
+ return history_id;
+}
+
+EditorUndoRedoManager::History &EditorUndoRedoManager::get_history_for_object(Object *p_object) {
+ int history_id = get_history_id_for_object(p_object);
+ ERR_FAIL_COND_V_MSG(pending_action.history_id != INVALID_HISTORY && history_id != pending_action.history_id, get_or_create_history(pending_action.history_id), vformat("UndoRedo history mismatch: expected %d, got %d.", pending_action.history_id, history_id));
+
+ History &history = get_or_create_history(history_id);
+ if (pending_action.history_id == INVALID_HISTORY) {
+ pending_action.history_id = history_id;
+ history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode);
+ }
+
+ return history;
+}
+
+void EditorUndoRedoManager::create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode) {
+ pending_action.action_name = p_name;
+ pending_action.timestamp = OS::get_singleton()->get_unix_time();
+ pending_action.merge_mode = p_mode;
+
+ if (p_history_id != INVALID_HISTORY) {
+ pending_action.history_id = p_history_id;
+ History &history = get_or_create_history(p_history_id);
+ history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode);
+ }
+}
+
+void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context) {
+ create_action_for_history(p_name, INVALID_HISTORY, p_mode);
+
+ if (p_custom_context) {
+ // This assigns context to pending action.
+ get_history_for_object(p_custom_context);
+ }
+}
+
+void EditorUndoRedoManager::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_do_methodp(p_object, p_method, p_args, p_argcount);
+}
+
+void EditorUndoRedoManager::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_undo_methodp(p_object, p_method, p_args, p_argcount);
+}
+
+void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return;
+ }
+
+ if (p_args[0]->get_type() != Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return;
+ }
+
+ if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ Object *object = *p_args[0];
+ StringName method = *p_args[1];
+
+ add_do_methodp(object, method, p_args + 2, p_argcount - 2);
+}
+
+void EditorUndoRedoManager::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return;
+ }
+
+ if (p_args[0]->get_type() != Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return;
+ }
+
+ if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ Object *object = *p_args[0];
+ StringName method = *p_args[1];
+
+ add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
+}
+
+void EditorUndoRedoManager::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_do_property(p_object, p_property, p_value);
+}
+
+void EditorUndoRedoManager::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_undo_property(p_object, p_property, p_value);
+}
+
+void EditorUndoRedoManager::add_do_reference(Object *p_object) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_do_reference(p_object);
+}
+
+void EditorUndoRedoManager::add_undo_reference(Object *p_object) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_undo_reference(p_object);
+}
+
+void EditorUndoRedoManager::commit_action(bool p_execute) {
+ ERR_FAIL_COND(pending_action.history_id == INVALID_HISTORY);
+ is_committing = true;
+
+ History &history = get_or_create_history(pending_action.history_id);
+ history.undo_redo->commit_action(p_execute);
+ history.redo_stack.clear();
+
+ if (!history.undo_stack.is_empty()) {
+ const Action &prev_action = history.undo_stack.back()->get();
+ if (pending_action.merge_mode != UndoRedo::MERGE_DISABLE && pending_action.merge_mode == prev_action.merge_mode && pending_action.action_name == prev_action.action_name) {
+ // Discard action if it should be merged (UndoRedo handles merging internally).
+ pending_action = Action();
+ is_committing = false;
+ return;
+ }
+ }
+
+ history.undo_stack.push_back(pending_action);
+ pending_action = Action();
+ is_committing = false;
+}
+
+bool EditorUndoRedoManager::is_committing_action() const {
+ return is_committing;
+}
+
+bool EditorUndoRedoManager::undo() {
+ if (!has_undo()) {
+ return false;
+ }
+
+ History *selected_history = nullptr;
+ double global_timestamp = 0;
+
+ // Pick the history with greatest last action timestamp (either global or current scene).
+ {
+ History &history = get_or_create_history(GLOBAL_HISTORY);
+ if (!history.undo_stack.is_empty()) {
+ selected_history = &history;
+ global_timestamp = history.undo_stack.back()->get().timestamp;
+ }
+ }
+
+ {
+ History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) {
+ selected_history = &history;
+ }
+ }
+
+ if (selected_history) {
+ Action action = selected_history->undo_stack.back()->get();
+ selected_history->undo_stack.pop_back();
+ selected_history->redo_stack.push_back(action);
+ return selected_history->undo_redo->undo();
+ }
+ return false;
+}
+
+bool EditorUndoRedoManager::redo() {
+ if (!has_redo()) {
+ return false;
+ }
+
+ History *selected_history = nullptr;
+ double global_timestamp = INFINITY;
+
+ // Pick the history with lowest last action timestamp (either global or current scene).
+ {
+ History &history = get_or_create_history(GLOBAL_HISTORY);
+ if (!history.redo_stack.is_empty()) {
+ selected_history = &history;
+ global_timestamp = history.redo_stack.back()->get().timestamp;
+ }
+ }
+
+ {
+ History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ if (!history.redo_stack.is_empty() && history.redo_stack.back()->get().timestamp < global_timestamp) {
+ selected_history = &history;
+ }
+ }
+
+ if (selected_history) {
+ Action action = selected_history->redo_stack.back()->get();
+ selected_history->redo_stack.pop_back();
+ selected_history->undo_stack.push_back(action);
+ return selected_history->undo_redo->redo();
+ }
+ return false;
+}
+
+void EditorUndoRedoManager::set_history_as_saved(int p_id) {
+ History &history = get_or_create_history(p_id);
+ history.saved_version = history.undo_redo->get_version();
+}
+
+void EditorUndoRedoManager::set_history_as_unsaved(int p_id) {
+ History &history = get_or_create_history(p_id);
+ history.saved_version = -1;
+}
+
+bool EditorUndoRedoManager::is_history_unsaved(int p_id) {
+ History &history = get_or_create_history(p_id);
+ return history.undo_redo->get_version() != history.saved_version;
+}
+
+bool EditorUndoRedoManager::has_undo() {
+ for (const KeyValue<int, History> &E : history_map) {
+ if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.undo_stack.is_empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool EditorUndoRedoManager::has_redo() {
+ for (const KeyValue<int, History> &E : history_map) {
+ if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.redo_stack.is_empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void EditorUndoRedoManager::clear_history(bool p_increase_version, int p_idx) {
+ if (p_idx != INVALID_HISTORY) {
+ get_or_create_history(p_idx).undo_redo->clear_history(p_increase_version);
+ if (!p_increase_version) {
+ set_history_as_saved(p_idx);
+ }
+ return;
+ }
+
+ for (const KeyValue<int, History> &E : history_map) {
+ E.value.undo_redo->clear_history(p_increase_version);
+ set_history_as_saved(E.key);
+ }
+}
+
+String EditorUndoRedoManager::get_current_action_name() {
+ if (has_undo()) {
+ History *selected_history = nullptr;
+ double global_timestamp = 0;
+
+ // Pick the history with greatest last action timestamp (either global or current scene).
+ {
+ History &history = get_or_create_history(GLOBAL_HISTORY);
+ if (!history.undo_stack.is_empty()) {
+ selected_history = &history;
+ global_timestamp = history.undo_stack.back()->get().timestamp;
+ }
+ }
+
+ {
+ History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) {
+ selected_history = &history;
+ }
+ }
+
+ if (selected_history) {
+ return selected_history->undo_redo->get_current_action_name();
+ }
+ }
+ return "";
+}
+
+void EditorUndoRedoManager::discard_history(int p_idx, bool p_erase_from_map) {
+ ERR_FAIL_COND(!history_map.has(p_idx));
+ History &history = history_map[p_idx];
+
+ if (history.undo_redo) {
+ memdelete(history.undo_redo);
+ history.undo_redo = nullptr;
+ }
+
+ if (p_erase_from_map) {
+ history_map.erase(p_idx);
+ }
+}
+
+void EditorUndoRedoManager::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "custom_context"), &EditorUndoRedoManager::create_action, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr));
+ ClassDB::bind_method(D_METHOD("commit_action", "execute"), &EditorUndoRedoManager::commit_action, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("is_committing_action"), &EditorUndoRedoManager::is_committing_action);
+
+ {
+ MethodInfo mi;
+ mi.name = "add_do_method";
+ mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
+ mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &EditorUndoRedoManager::_add_do_method, mi, varray(), false);
+ }
+
+ {
+ MethodInfo mi;
+ mi.name = "add_undo_method";
+ mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
+ mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &EditorUndoRedoManager::_add_undo_method, mi, varray(), false);
+ }
+
+ ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &EditorUndoRedoManager::add_do_property);
+ ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &EditorUndoRedoManager::add_undo_property);
+ ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &EditorUndoRedoManager::add_do_reference);
+ ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &EditorUndoRedoManager::add_undo_reference);
+
+ ClassDB::bind_method(D_METHOD("get_object_history_id", "object"), &EditorUndoRedoManager::get_history_id_for_object);
+ ClassDB::bind_method(D_METHOD("get_history_undo_redo", "id"), &EditorUndoRedoManager::get_history_undo_redo);
+
+ BIND_ENUM_CONSTANT(GLOBAL_HISTORY);
+ BIND_ENUM_CONSTANT(INVALID_HISTORY);
+}
+
+EditorUndoRedoManager::~EditorUndoRedoManager() {
+ for (const KeyValue<int, History> &E : history_map) {
+ discard_history(E.key, false);
+ }
+}
diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h
new file mode 100644
index 0000000000..c4d85daa22
--- /dev/null
+++ b/editor/editor_undo_redo_manager.h
@@ -0,0 +1,134 @@
+/*************************************************************************/
+/* editor_undo_redo_manager.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 EDITOR_UNDO_REDO_MANAGER_H
+#define EDITOR_UNDO_REDO_MANAGER_H
+
+#include "core/object/class_db.h"
+#include "core/object/ref_counted.h"
+#include "core/object/undo_redo.h"
+
+class EditorUndoRedoManager : public RefCounted {
+ GDCLASS(EditorUndoRedoManager, RefCounted);
+
+public:
+ enum SpecialHistory {
+ GLOBAL_HISTORY = 0,
+ INVALID_HISTORY = -99,
+ };
+
+private:
+ struct Action {
+ int history_id = INVALID_HISTORY;
+ double timestamp = 0;
+ String action_name;
+ UndoRedo::MergeMode merge_mode = UndoRedo::MERGE_DISABLE;
+ };
+
+ struct History {
+ int id = INVALID_HISTORY;
+ UndoRedo *undo_redo = nullptr;
+ uint64_t saved_version = 1;
+ List<Action> undo_stack;
+ List<Action> redo_stack;
+ };
+
+ HashMap<int, History> history_map;
+ Action pending_action;
+
+ bool is_committing = false;
+
+protected:
+ static void _bind_methods();
+
+public:
+ History &get_or_create_history(int p_idx);
+ UndoRedo *get_history_undo_redo(int p_idx) const;
+ int get_history_id_for_object(Object *p_object) const;
+ History &get_history_for_object(Object *p_object);
+
+ void create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE);
+ void create_action(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, Object *p_custom_context = nullptr);
+
+ void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+ void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ template <typename... VarArgs>
+ void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+
+ void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
+ void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
+ void add_do_reference(Object *p_object);
+ void add_undo_reference(Object *p_object);
+
+ void commit_action(bool p_execute = true);
+ bool is_committing_action() const;
+
+ bool undo();
+ bool redo();
+ void clear_history(bool p_increase_version = true, int p_idx = INVALID_HISTORY);
+
+ void set_history_as_saved(int p_idx);
+ void set_history_as_unsaved(int p_idx);
+ bool is_history_unsaved(int p_idx);
+ bool has_undo();
+ bool has_redo();
+
+ String get_current_action_name();
+
+ void discard_history(int p_idx, bool p_erase_from_map = true);
+ ~EditorUndoRedoManager();
+};
+
+VARIANT_ENUM_CAST(EditorUndoRedoManager::SpecialHistory);
+
+#endif // EDITOR_UNDO_REDO_MANAGER_H
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index 3f2012cc16..d22c7bd149 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -30,132 +30,371 @@
#include "editor_vcs_interface.h"
+#include "editor_node.h"
+
+#define UNIMPLEMENTED() ERR_PRINT(vformat("Unimplemented virtual function in EditorVCSInterface based plugin: %s", __func__))
+
EditorVCSInterface *EditorVCSInterface::singleton = nullptr;
-void EditorVCSInterface::_bind_methods() {
- // Proxy end points that act as fallbacks to unavailability of a function in the VCS addon
- ClassDB::bind_method(D_METHOD("_initialize", "project_root_path"), &EditorVCSInterface::_initialize);
- ClassDB::bind_method(D_METHOD("_is_vcs_initialized"), &EditorVCSInterface::_is_vcs_initialized);
- ClassDB::bind_method(D_METHOD("_get_vcs_name"), &EditorVCSInterface::_get_vcs_name);
- ClassDB::bind_method(D_METHOD("_shut_down"), &EditorVCSInterface::_shut_down);
- ClassDB::bind_method(D_METHOD("_get_project_name"), &EditorVCSInterface::_get_project_name);
- ClassDB::bind_method(D_METHOD("_get_modified_files_data"), &EditorVCSInterface::_get_modified_files_data);
- ClassDB::bind_method(D_METHOD("_commit", "msg"), &EditorVCSInterface::_commit);
- ClassDB::bind_method(D_METHOD("_get_file_diff", "file_path"), &EditorVCSInterface::_get_file_diff);
- ClassDB::bind_method(D_METHOD("_stage_file", "file_path"), &EditorVCSInterface::_stage_file);
- ClassDB::bind_method(D_METHOD("_unstage_file", "file_path"), &EditorVCSInterface::_unstage_file);
+void EditorVCSInterface::popup_error(String p_msg) {
+ // TRANSLATORS: %s refers to the name of a version control system (e.g. "Git").
+ EditorNode::get_singleton()->show_warning(p_msg.strip_edges(), vformat(TTR("%s Error"), get_vcs_name()));
+}
- ClassDB::bind_method(D_METHOD("is_addon_ready"), &EditorVCSInterface::is_addon_ready);
+bool EditorVCSInterface::initialize(String p_project_path) {
+ bool result = false;
+ if (!GDVIRTUAL_CALL(_initialize, p_project_path, result)) {
+ UNIMPLEMENTED();
+ return false;
+ }
+ return result;
+}
- // API methods that redirect calls to the proxy end points
- ClassDB::bind_method(D_METHOD("initialize", "project_root_path"), &EditorVCSInterface::initialize);
- ClassDB::bind_method(D_METHOD("is_vcs_initialized"), &EditorVCSInterface::is_vcs_initialized);
- ClassDB::bind_method(D_METHOD("get_modified_files_data"), &EditorVCSInterface::get_modified_files_data);
- ClassDB::bind_method(D_METHOD("stage_file", "file_path"), &EditorVCSInterface::stage_file);
- ClassDB::bind_method(D_METHOD("unstage_file", "file_path"), &EditorVCSInterface::unstage_file);
- ClassDB::bind_method(D_METHOD("commit", "msg"), &EditorVCSInterface::commit);
- ClassDB::bind_method(D_METHOD("get_file_diff", "file_path"), &EditorVCSInterface::get_file_diff);
- ClassDB::bind_method(D_METHOD("shut_down"), &EditorVCSInterface::shut_down);
- ClassDB::bind_method(D_METHOD("get_project_name"), &EditorVCSInterface::get_project_name);
- ClassDB::bind_method(D_METHOD("get_vcs_name"), &EditorVCSInterface::get_vcs_name);
+void EditorVCSInterface::set_credentials(String p_username, String p_password, String p_ssh_public_key, String p_ssh_private_key, String p_ssh_passphrase) {
+ if (!GDVIRTUAL_CALL(_set_credentials, p_username, p_password, p_ssh_public_key, p_ssh_private_key, p_ssh_passphrase)) {
+ UNIMPLEMENTED();
+ }
}
-bool EditorVCSInterface::_initialize(String p_project_root_path) {
- WARN_PRINT("Selected VCS addon does not implement an initialization function. This warning will be suppressed.");
- return true;
+List<String> EditorVCSInterface::get_remotes() {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_remotes, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<String> remotes;
+ for (int i = 0; i < result.size(); i++) {
+ remotes.push_back(result[i]);
+ }
+ return remotes;
}
-bool EditorVCSInterface::_is_vcs_initialized() {
- return false;
+List<EditorVCSInterface::StatusFile> EditorVCSInterface::get_modified_files_data() {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_modified_files_data, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<EditorVCSInterface::StatusFile> status_files;
+ for (int i = 0; i < result.size(); i++) {
+ status_files.push_back(_convert_status_file(result[i]));
+ }
+ return status_files;
}
-Dictionary EditorVCSInterface::_get_modified_files_data() {
- return Dictionary();
+void EditorVCSInterface::stage_file(String p_file_path) {
+ if (!GDVIRTUAL_CALL(_stage_file, p_file_path)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::_stage_file(String p_file_path) {
+void EditorVCSInterface::unstage_file(String p_file_path) {
+ if (!GDVIRTUAL_CALL(_unstage_file, p_file_path)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::_unstage_file(String p_file_path) {
+void EditorVCSInterface::discard_file(String p_file_path) {
+ if (!GDVIRTUAL_CALL(_discard_file, p_file_path)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::_commit(String p_msg) {
+void EditorVCSInterface::commit(String p_msg) {
+ if (!GDVIRTUAL_CALL(_commit, p_msg)) {
+ UNIMPLEMENTED();
+ }
}
-Array EditorVCSInterface::_get_file_diff(String p_file_path) {
- return Array();
+List<EditorVCSInterface::DiffFile> EditorVCSInterface::get_diff(String p_identifier, TreeArea p_area) {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_diff, p_identifier, int(p_area), result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<DiffFile> diff_files;
+ for (int i = 0; i < result.size(); i++) {
+ diff_files.push_back(_convert_diff_file(result[i]));
+ }
+ return diff_files;
}
-bool EditorVCSInterface::_shut_down() {
- return false;
+List<EditorVCSInterface::Commit> EditorVCSInterface::get_previous_commits(int p_max_commits) {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_previous_commits, p_max_commits, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<EditorVCSInterface::Commit> commits;
+ for (int i = 0; i < result.size(); i++) {
+ commits.push_back(_convert_commit(result[i]));
+ }
+ return commits;
}
-String EditorVCSInterface::_get_project_name() {
- return String();
+List<String> EditorVCSInterface::get_branch_list() {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_branch_list, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<String> branch_list;
+ for (int i = 0; i < result.size(); i++) {
+ branch_list.push_back(result[i]);
+ }
+ return branch_list;
}
-String EditorVCSInterface::_get_vcs_name() {
- return "";
+void EditorVCSInterface::create_branch(String p_branch_name) {
+ if (!GDVIRTUAL_CALL(_create_branch, p_branch_name)) {
+ UNIMPLEMENTED();
+ }
}
-bool EditorVCSInterface::initialize(String p_project_root_path) {
- is_initialized = call("_initialize", p_project_root_path);
- return is_initialized;
+void EditorVCSInterface::create_remote(String p_remote_name, String p_remote_url) {
+ if (!GDVIRTUAL_CALL(_create_remote, p_remote_name, p_remote_url)) {
+ UNIMPLEMENTED();
+ }
}
-bool EditorVCSInterface::is_vcs_initialized() {
- return call("_is_vcs_initialized");
+void EditorVCSInterface::remove_branch(String p_branch_name) {
+ if (!GDVIRTUAL_CALL(_remove_branch, p_branch_name)) {
+ UNIMPLEMENTED();
+ }
}
-Dictionary EditorVCSInterface::get_modified_files_data() {
- return call("_get_modified_files_data");
+void EditorVCSInterface::remove_remote(String p_remote_name) {
+ if (!GDVIRTUAL_CALL(_remove_remote, p_remote_name)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::stage_file(String p_file_path) {
- if (is_addon_ready()) {
- call("_stage_file", p_file_path);
+String EditorVCSInterface::get_current_branch_name() {
+ String result;
+ if (!GDVIRTUAL_CALL(_get_current_branch_name, result)) {
+ UNIMPLEMENTED();
+ return "";
}
+ return result;
}
-void EditorVCSInterface::unstage_file(String p_file_path) {
- if (is_addon_ready()) {
- call("_unstage_file", p_file_path);
+bool EditorVCSInterface::checkout_branch(String p_branch_name) {
+ bool result = false;
+ if (!GDVIRTUAL_CALL(_checkout_branch, p_branch_name, result)) {
+ UNIMPLEMENTED();
}
+ return result;
}
-bool EditorVCSInterface::is_addon_ready() {
- return is_initialized;
+void EditorVCSInterface::pull(String p_remote) {
+ if (!GDVIRTUAL_CALL(_pull, p_remote)) {
+ UNIMPLEMENTED();
+ }
}
-void EditorVCSInterface::commit(String p_msg) {
- if (is_addon_ready()) {
- call("_commit", p_msg);
+void EditorVCSInterface::push(String p_remote, bool p_force) {
+ if (!GDVIRTUAL_CALL(_push, p_remote, p_force)) {
+ UNIMPLEMENTED();
}
}
-Array EditorVCSInterface::get_file_diff(String p_file_path) {
- if (is_addon_ready()) {
- return call("_get_file_diff", p_file_path);
+void EditorVCSInterface::fetch(String p_remote) {
+ if (!GDVIRTUAL_CALL(_fetch, p_remote)) {
+ UNIMPLEMENTED();
}
- return Array();
}
-bool EditorVCSInterface::shut_down() {
- return call("_shut_down");
+List<EditorVCSInterface::DiffHunk> EditorVCSInterface::get_line_diff(String p_file_path, String p_text) {
+ TypedArray<Dictionary> result;
+ if (!GDVIRTUAL_CALL(_get_line_diff, p_file_path, p_text, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ List<DiffHunk> diff_hunks;
+ for (int i = 0; i < result.size(); i++) {
+ diff_hunks.push_back(_convert_diff_hunk(result[i]));
+ }
+ return diff_hunks;
}
-String EditorVCSInterface::get_project_name() {
- return call("_get_project_name");
+bool EditorVCSInterface::shut_down() {
+ bool result = false;
+ if (!GDVIRTUAL_CALL(_shut_down, result)) {
+ UNIMPLEMENTED();
+ return false;
+ }
+ return result;
}
String EditorVCSInterface::get_vcs_name() {
- return call("_get_vcs_name");
+ String result;
+ if (!GDVIRTUAL_CALL(_get_vcs_name, result)) {
+ UNIMPLEMENTED();
+ return {};
+ }
+ return result;
+}
+
+Dictionary EditorVCSInterface::create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status) {
+ Dictionary diff_line;
+ diff_line["new_line_no"] = p_new_line_no;
+ diff_line["old_line_no"] = p_old_line_no;
+ diff_line["content"] = p_content;
+ diff_line["status"] = p_status;
+
+ return diff_line;
+}
+
+Dictionary EditorVCSInterface::create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines) {
+ Dictionary diff_hunk;
+ diff_hunk["new_lines"] = p_new_lines;
+ diff_hunk["old_lines"] = p_old_lines;
+ diff_hunk["new_start"] = p_new_start;
+ diff_hunk["old_start"] = p_old_start;
+ diff_hunk["diff_lines"] = TypedArray<Dictionary>();
+ return diff_hunk;
+}
+
+Dictionary EditorVCSInterface::add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, TypedArray<Dictionary> p_line_diffs) {
+ p_diff_hunk["diff_lines"] = p_line_diffs;
+ return p_diff_hunk;
+}
+
+Dictionary EditorVCSInterface::create_diff_file(String p_new_file, String p_old_file) {
+ Dictionary file_diff;
+ file_diff["new_file"] = p_new_file;
+ file_diff["old_file"] = p_old_file;
+ file_diff["diff_hunks"] = TypedArray<Dictionary>();
+ return file_diff;
+}
+
+Dictionary EditorVCSInterface::create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes) {
+ Dictionary commit_info;
+ commit_info["message"] = p_msg;
+ commit_info["author"] = p_author;
+ commit_info["unix_timestamp"] = p_unix_timestamp;
+ commit_info["offset_minutes"] = p_offset_minutes;
+ commit_info["id"] = p_id;
+ return commit_info;
}
-EditorVCSInterface::EditorVCSInterface() {
+Dictionary EditorVCSInterface::add_diff_hunks_into_diff_file(Dictionary p_diff_file, TypedArray<Dictionary> p_diff_hunks) {
+ p_diff_file["diff_hunks"] = p_diff_hunks;
+ return p_diff_file;
}
-EditorVCSInterface::~EditorVCSInterface() {
+Dictionary EditorVCSInterface::create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area) {
+ Dictionary sf;
+ sf["file_path"] = p_file_path;
+ sf["change_type"] = p_change;
+ sf["area"] = p_area;
+ return sf;
+}
+
+EditorVCSInterface::DiffLine EditorVCSInterface::_convert_diff_line(Dictionary p_diff_line) {
+ DiffLine d;
+ d.new_line_no = p_diff_line["new_line_no"];
+ d.old_line_no = p_diff_line["old_line_no"];
+ d.content = p_diff_line["content"];
+ d.status = p_diff_line["status"];
+ return d;
+}
+
+EditorVCSInterface::DiffHunk EditorVCSInterface::_convert_diff_hunk(Dictionary p_diff_hunk) {
+ DiffHunk dh;
+ dh.new_lines = p_diff_hunk["new_lines"];
+ dh.old_lines = p_diff_hunk["old_lines"];
+ dh.new_start = p_diff_hunk["new_start"];
+ dh.old_start = p_diff_hunk["old_start"];
+ TypedArray<Dictionary> diff_lines = p_diff_hunk["diff_lines"];
+ for (int i = 0; i < diff_lines.size(); i++) {
+ DiffLine dl = _convert_diff_line(diff_lines[i]);
+ dh.diff_lines.push_back(dl);
+ }
+ return dh;
+}
+
+EditorVCSInterface::DiffFile EditorVCSInterface::_convert_diff_file(Dictionary p_diff_file) {
+ DiffFile df;
+ df.new_file = p_diff_file["new_file"];
+ df.old_file = p_diff_file["old_file"];
+ TypedArray<Dictionary> diff_hunks = p_diff_file["diff_hunks"];
+ for (int i = 0; i < diff_hunks.size(); i++) {
+ DiffHunk dh = _convert_diff_hunk(diff_hunks[i]);
+ df.diff_hunks.push_back(dh);
+ }
+ return df;
+}
+
+EditorVCSInterface::Commit EditorVCSInterface::_convert_commit(Dictionary p_commit) {
+ EditorVCSInterface::Commit c;
+ c.msg = p_commit["message"];
+ c.author = p_commit["author"];
+ c.unix_timestamp = p_commit["unix_timestamp"];
+ c.offset_minutes = p_commit["offset_minutes"];
+ c.id = p_commit["id"];
+ return c;
+}
+
+EditorVCSInterface::StatusFile EditorVCSInterface::_convert_status_file(Dictionary p_status_file) {
+ StatusFile sf;
+ sf.file_path = p_status_file["file_path"];
+ sf.change_type = (ChangeType)(int)p_status_file["change_type"];
+ sf.area = (TreeArea)(int)p_status_file["area"];
+ return sf;
+}
+
+void EditorVCSInterface::_bind_methods() {
+ // Proxy end points that implement the VCS specific operations that the editor demands.
+ GDVIRTUAL_BIND(_initialize, "project_path");
+ GDVIRTUAL_BIND(_set_credentials, "username", "password", "ssh_public_key_path", "ssh_private_key_path", "ssh_passphrase");
+ GDVIRTUAL_BIND(_get_modified_files_data);
+ GDVIRTUAL_BIND(_stage_file, "file_path");
+ GDVIRTUAL_BIND(_unstage_file, "file_path");
+ GDVIRTUAL_BIND(_discard_file, "file_path");
+ GDVIRTUAL_BIND(_commit, "msg");
+ GDVIRTUAL_BIND(_get_diff, "identifier", "area");
+ GDVIRTUAL_BIND(_shut_down);
+ GDVIRTUAL_BIND(_get_vcs_name);
+ GDVIRTUAL_BIND(_get_previous_commits, "max_commits");
+ GDVIRTUAL_BIND(_get_branch_list);
+ GDVIRTUAL_BIND(_get_remotes);
+ GDVIRTUAL_BIND(_create_branch, "branch_name");
+ GDVIRTUAL_BIND(_remove_branch, "branch_name");
+ GDVIRTUAL_BIND(_create_remote, "remote_name", "remote_url");
+ GDVIRTUAL_BIND(_remove_remote, "remote_name");
+ GDVIRTUAL_BIND(_get_current_branch_name);
+ GDVIRTUAL_BIND(_checkout_branch, "branch_name");
+ GDVIRTUAL_BIND(_pull, "remote");
+ GDVIRTUAL_BIND(_push, "remote", "force");
+ GDVIRTUAL_BIND(_fetch, "remote");
+ GDVIRTUAL_BIND(_get_line_diff, "file_path", "text");
+
+ ClassDB::bind_method(D_METHOD("create_diff_line", "new_line_no", "old_line_no", "content", "status"), &EditorVCSInterface::create_diff_line);
+ ClassDB::bind_method(D_METHOD("create_diff_hunk", "old_start", "new_start", "old_lines", "new_lines"), &EditorVCSInterface::create_diff_hunk);
+ ClassDB::bind_method(D_METHOD("create_diff_file", "new_file", "old_file"), &EditorVCSInterface::create_diff_file);
+ ClassDB::bind_method(D_METHOD("create_commit", "msg", "author", "id", "unix_timestamp", "offset_minutes"), &EditorVCSInterface::create_commit);
+ ClassDB::bind_method(D_METHOD("create_status_file", "file_path", "change_type", "area"), &EditorVCSInterface::create_status_file);
+ ClassDB::bind_method(D_METHOD("add_diff_hunks_into_diff_file", "diff_file", "diff_hunks"), &EditorVCSInterface::add_diff_hunks_into_diff_file);
+ ClassDB::bind_method(D_METHOD("add_line_diffs_into_diff_hunk", "diff_hunk", "line_diffs"), &EditorVCSInterface::add_line_diffs_into_diff_hunk);
+ ClassDB::bind_method(D_METHOD("popup_error", "msg"), &EditorVCSInterface::popup_error);
+
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_UNMERGED);
+
+ BIND_ENUM_CONSTANT(TREE_AREA_COMMIT);
+ BIND_ENUM_CONSTANT(TREE_AREA_STAGED);
+ BIND_ENUM_CONSTANT(TREE_AREA_UNSTAGED);
}
EditorVCSInterface *EditorVCSInterface::get_singleton() {
@@ -168,16 +407,16 @@ void EditorVCSInterface::set_singleton(EditorVCSInterface *p_singleton) {
void EditorVCSInterface::create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir) {
if (p_vcs_metadata_type == VCSMetadata::GIT) {
- Ref<FileAccess> f = FileAccess::open(p_dir.plus_file(".gitignore"), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(p_dir.path_join(".gitignore"), FileAccess::WRITE);
if (f.is_null()) {
- ERR_FAIL_MSG(TTR("Couldn't create .gitignore in project path."));
+ ERR_FAIL_MSG("Couldn't create .gitignore in project path.");
} else {
f->store_line("# Godot 4+ specific ignores");
f->store_line(".godot/");
}
- f = FileAccess::open(p_dir.plus_file(".gitattributes"), FileAccess::WRITE);
+ f = FileAccess::open(p_dir.path_join(".gitattributes"), FileAccess::WRITE);
if (f.is_null()) {
- ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path."));
+ ERR_FAIL_MSG("Couldn't create .gitattributes in project path.");
} else {
f->store_line("# Normalize EOL for all files that Git considers text files.");
f->store_line("* text=auto eol=lf");
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index 6a6fca7eba..5d4901cefa 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -32,30 +32,103 @@
#define EDITOR_VCS_INTERFACE_H
#include "core/object/class_db.h"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language_extension.h"
#include "core/string/ustring.h"
-#include "scene/gui/panel_container.h"
+#include "core/variant/type_info.h"
class EditorVCSInterface : public Object {
GDCLASS(EditorVCSInterface, Object)
- bool is_initialized = false;
+public:
+ enum ChangeType {
+ CHANGE_TYPE_NEW = 0,
+ CHANGE_TYPE_MODIFIED = 1,
+ CHANGE_TYPE_RENAMED = 2,
+ CHANGE_TYPE_DELETED = 3,
+ CHANGE_TYPE_TYPECHANGE = 4,
+ CHANGE_TYPE_UNMERGED = 5
+ };
+
+ enum TreeArea {
+ TREE_AREA_COMMIT = 0,
+ TREE_AREA_STAGED = 1,
+ TREE_AREA_UNSTAGED = 2
+ };
+
+ struct DiffLine {
+ int new_line_no;
+ int old_line_no;
+ String content;
+ String status;
+
+ String old_text;
+ String new_text;
+ };
+
+ struct DiffHunk {
+ int new_start;
+ int old_start;
+ int new_lines;
+ int old_lines;
+ List<DiffLine> diff_lines;
+ };
+
+ struct DiffFile {
+ String new_file;
+ String old_file;
+ List<DiffHunk> diff_hunks;
+ };
+
+ struct Commit {
+ String author;
+ String msg;
+ String id;
+ int64_t unix_timestamp;
+ int64_t offset_minutes;
+ };
+
+ struct StatusFile {
+ TreeArea area;
+ ChangeType change_type;
+ String file_path;
+ };
protected:
static EditorVCSInterface *singleton;
static void _bind_methods();
- // Implemented by addons as end points for the proxy functions
- virtual bool _initialize(String p_project_root_path);
- virtual bool _is_vcs_initialized();
- virtual Dictionary _get_modified_files_data();
- virtual void _stage_file(String p_file_path);
- virtual void _unstage_file(String p_file_path);
- virtual void _commit(String p_msg);
- virtual Array _get_file_diff(String p_file_path);
- virtual bool _shut_down();
- virtual String _get_project_name();
- virtual String _get_vcs_name();
+ DiffLine _convert_diff_line(Dictionary p_diff_line);
+ DiffHunk _convert_diff_hunk(Dictionary p_diff_hunk);
+ DiffFile _convert_diff_file(Dictionary p_diff_file);
+ Commit _convert_commit(Dictionary p_commit);
+ StatusFile _convert_status_file(Dictionary p_status_file);
+
+ // Proxy endpoints for extensions to implement
+ GDVIRTUAL1R(bool, _initialize, String);
+ GDVIRTUAL5(_set_credentials, String, String, String, String, String);
+ GDVIRTUAL0R(TypedArray<Dictionary>, _get_modified_files_data);
+ GDVIRTUAL1(_stage_file, String);
+ GDVIRTUAL1(_unstage_file, String);
+ GDVIRTUAL1(_discard_file, String);
+ GDVIRTUAL1(_commit, String);
+ GDVIRTUAL2R(TypedArray<Dictionary>, _get_diff, String, int);
+ GDVIRTUAL0R(bool, _shut_down);
+ GDVIRTUAL0R(String, _get_vcs_name);
+ GDVIRTUAL1R(TypedArray<Dictionary>, _get_previous_commits, int);
+ GDVIRTUAL0R(TypedArray<Dictionary>, _get_branch_list);
+ GDVIRTUAL0R(TypedArray<Dictionary>, _get_remotes);
+ GDVIRTUAL1(_create_branch, String);
+ GDVIRTUAL1(_remove_branch, String);
+ GDVIRTUAL2(_create_remote, String, String);
+ GDVIRTUAL1(_remove_remote, String);
+ GDVIRTUAL0R(String, _get_current_branch_name);
+ GDVIRTUAL1R(bool, _checkout_branch, String);
+ GDVIRTUAL1(_pull, String);
+ GDVIRTUAL2(_push, String, bool);
+ GDVIRTUAL1(_fetch, String);
+ GDVIRTUAL2R(TypedArray<Dictionary>, _get_line_diff, String, String);
public:
static EditorVCSInterface *get_singleton();
@@ -67,22 +140,44 @@ public:
};
static void create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir);
- bool is_addon_ready();
-
- // Proxy functions to the editor for use
- bool initialize(String p_project_root_path);
- bool is_vcs_initialized();
- Dictionary get_modified_files_data();
+ // Proxies to the editor for use
+ bool initialize(String p_project_path);
+ void set_credentials(String p_username, String p_password, String p_ssh_public_key_path, String p_ssh_private_key_path, String p_ssh_passphrase);
+ List<StatusFile> get_modified_files_data();
void stage_file(String p_file_path);
void unstage_file(String p_file_path);
+ void discard_file(String p_file_path);
void commit(String p_msg);
- Array get_file_diff(String p_file_path);
+ List<DiffFile> get_diff(String p_identifier, TreeArea p_area);
bool shut_down();
- String get_project_name();
String get_vcs_name();
+ List<Commit> get_previous_commits(int p_max_commits);
+ List<String> get_branch_list();
+ List<String> get_remotes();
+ void create_branch(String p_branch_name);
+ void remove_branch(String p_branch_name);
+ void create_remote(String p_remote_name, String p_remote_url);
+ void remove_remote(String p_remote_name);
+ String get_current_branch_name();
+ bool checkout_branch(String p_branch_name);
+ void pull(String p_remote);
+ void push(String p_remote, bool p_force);
+ void fetch(String p_remote);
+ List<DiffHunk> get_line_diff(String p_file_path, String p_text);
- EditorVCSInterface();
- virtual ~EditorVCSInterface();
+ // Helper functions to create and convert Dictionary into data structures
+ Dictionary create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status);
+ Dictionary create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines);
+ Dictionary create_diff_file(String p_new_file, String p_old_file);
+ Dictionary create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes);
+ Dictionary create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area);
+ Dictionary add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, TypedArray<Dictionary> p_line_diffs);
+ Dictionary add_diff_hunks_into_diff_file(Dictionary p_diff_file, TypedArray<Dictionary> p_diff_hunks);
+
+ void popup_error(String p_msg);
};
+VARIANT_ENUM_CAST(EditorVCSInterface::ChangeType);
+VARIANT_ENUM_CAST(EditorVCSInterface::TreeArea);
+
#endif // EDITOR_VCS_INTERFACE_H
diff --git a/editor/editor_zoom_widget.cpp b/editor/editor_zoom_widget.cpp
index e4beea5e5f..88e99d9b30 100644
--- a/editor/editor_zoom_widget.cpp
+++ b/editor/editor_zoom_widget.cpp
@@ -167,7 +167,7 @@ EditorZoomWidget::EditorZoomWidget() {
zoom_minus->set_flat(true);
add_child(zoom_minus);
zoom_minus->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_minus));
- zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KeyModifierMask::CMD | Key::MINUS));
+ zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KeyModifierMask::CMD_OR_CTRL | Key::MINUS));
zoom_minus->set_shortcut_context(this);
zoom_minus->set_focus_mode(FOCUS_NONE);
@@ -189,7 +189,7 @@ EditorZoomWidget::EditorZoomWidget() {
zoom_plus->set_flat(true);
add_child(zoom_plus);
zoom_plus->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_plus));
- zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KeyModifierMask::CMD | Key::EQUAL)); // Usually direct access key for PLUS
+ zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KeyModifierMask::CMD_OR_CTRL | Key::EQUAL)); // Usually direct access key for PLUS
zoom_plus->set_shortcut_context(this);
zoom_plus->set_focus_mode(FOCUS_NONE);
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index 31f408eedb..29b6a5e546 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -312,12 +312,14 @@ void EditorExport::update_export_presets() {
// Clear the preset properties and values prior to reloading
preset->properties.clear();
preset->values.clear();
+ preset->update_visibility.clear();
for (const EditorExportPlatform::ExportOption &E : options) {
preset->properties.push_back(E.option);
StringName option_name = E.option.name;
preset->values[option_name] = previous_values.has(option_name) ? previous_values[option_name] : E.default_value;
+ preset->update_visibility[option_name] = E.update_visibility;
}
}
}
@@ -349,6 +351,8 @@ EditorExport::EditorExport() {
singleton = this;
set_process(true);
+
+ GLOBAL_DEF("editor/export/convert_text_resources_to_binary", true);
}
EditorExport::~EditorExport() {
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 34b407779e..2a444bb04f 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -44,6 +44,7 @@
#include "editor/editor_settings.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor_export_plugin.h"
+#include "scene/resources/packed_scene.h"
static int _get_pad(int p_alignment, int p_n) {
int rest = p_n % p_alignment;
@@ -286,7 +287,7 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat
Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
ERR_FAIL_COND_V(theme.is_null(), Ref<ImageTexture>());
- if (EditorNode::get_singleton()->get_main_control()->is_layout_rtl()) {
+ if (EditorNode::get_singleton()->get_main_screen_control()->is_layout_rtl()) {
return theme->get_icon(SNAME("PlayBackwards"), SNAME("EditorIcons"));
} else {
return theme->get_icon(SNAME("Play"), SNAME("EditorIcons"));
@@ -295,7 +296,7 @@ Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
String EditorExportPlatform::find_export_template(String template_file_name, String *err) const {
String current_version = VERSION_FULL_CONFIG;
- String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(current_version).plus_file(template_file_name);
+ String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(current_version).path_join(template_file_name);
if (FileAccess::exists(template_path)) {
return template_path;
@@ -323,6 +324,7 @@ Ref<EditorExportPreset> EditorExportPlatform::create_preset() {
for (const ExportOption &E : options) {
preset->properties.push_back(E.option);
preset->values[E.option.name] = E.default_value;
+ preset->update_visibility[E.option.name] = E.update_visibility;
}
return preset;
@@ -429,24 +431,21 @@ void EditorExportPlatform::_edit_filter_list(HashSet<String> &r_list, const Stri
_edit_files_with_filter(da, filters, r_list, exclude);
}
-EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_containers(const Ref<EditorExportPreset> &p_preset, bool p_debug) const {
+HashSet<String> EditorExportPlatform::get_features(const Ref<EditorExportPreset> &p_preset, bool p_debug) const {
Ref<EditorExportPlatform> platform = p_preset->get_platform();
List<String> feature_list;
platform->get_platform_features(&feature_list);
platform->get_preset_features(p_preset, &feature_list);
- FeatureContainers result;
+ HashSet<String> result;
for (const String &E : feature_list) {
- result.features.insert(E);
- result.features_pv.push_back(E);
+ result.insert(E);
}
if (p_debug) {
- result.features.insert("debug");
- result.features_pv.push_back("debug");
+ result.insert("debug");
} else {
- result.features.insert("release");
- result.features_pv.push_back("release");
+ result.insert("release");
}
if (!p_preset->get_custom_features().is_empty()) {
@@ -455,8 +454,7 @@ EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_contai
for (int i = 0; i < tmp_custom_list.size(); i++) {
String f = tmp_custom_list[i].strip_edges();
if (!f.is_empty()) {
- result.features.insert(f);
- result.features_pv.push_back(f);
+ result.insert(f);
}
}
}
@@ -465,14 +463,18 @@ EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_contai
}
EditorExportPlatform::ExportNotifier::ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- FeatureContainers features = p_platform.get_feature_containers(p_preset, p_debug);
+ HashSet<String> features = p_platform.get_features(p_preset, p_debug);
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
//initial export plugin callback
for (int i = 0; i < export_plugins.size(); i++) {
if (export_plugins[i]->get_script_instance()) { //script based
- export_plugins.write[i]->_export_begin_script(features.features_pv, p_debug, p_path, p_flags);
+ PackedStringArray features_psa;
+ for (const String &feature : features) {
+ features_psa.push_back(feature);
+ }
+ export_plugins.write[i]->_export_begin_script(features_psa, p_debug, p_path, p_flags);
} else {
- export_plugins.write[i]->_export_begin(features.features, p_debug, p_path, p_flags);
+ export_plugins.write[i]->_export_begin(features, p_debug, p_path, p_flags);
}
}
}
@@ -487,6 +489,295 @@ EditorExportPlatform::ExportNotifier::~ExportNotifier() {
}
}
+bool EditorExportPlatform::_export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ List<Variant> keys;
+ dict.get_key_list(&keys);
+ for (const Variant &K : keys) {
+ Variant v = dict[K];
+ switch (v.get_type()) {
+ case Variant::OBJECT: {
+ Ref<Resource> res = v;
+ if (res.is_valid()) {
+ for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
+ Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
+ if (new_res.is_valid()) {
+ changed = true;
+ if (new_res != res) {
+ dict[K] = new_res;
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ // If it was not replaced, go through and see if there is something to replace.
+ if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
+ changed = true;
+ }
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = v;
+ if (_export_customize_dictionary(d, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ case Variant::ARRAY: {
+ Array a = v;
+ if (_export_customize_array(a, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ default: {
+ }
+ }
+ }
+ return changed;
+}
+
+bool EditorExportPlatform::_export_customize_array(Array &arr, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ for (int i = 0; i < arr.size(); i++) {
+ Variant v = arr.get(i);
+ switch (v.get_type()) {
+ case Variant::OBJECT: {
+ Ref<Resource> res = v;
+ if (res.is_valid()) {
+ for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
+ Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
+ if (new_res.is_valid()) {
+ changed = true;
+ if (new_res != res) {
+ arr.set(i, new_res);
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ // If it was not replaced, go through and see if there is something to replace.
+ if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
+ changed = true;
+ }
+ }
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = v;
+ if (_export_customize_dictionary(d, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ case Variant::ARRAY: {
+ Array a = v;
+ if (_export_customize_array(a, customize_resources_plugins)) {
+ changed = true;
+ }
+ } break;
+ default: {
+ }
+ }
+ }
+ return changed;
+}
+
+bool EditorExportPlatform::_export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ List<PropertyInfo> props;
+ p_object->get_property_list(&props);
+ for (const PropertyInfo &E : props) {
+ switch (E.type) {
+ case Variant::OBJECT: {
+ Ref<Resource> res = p_object->get(E.name);
+ if (res.is_valid()) {
+ for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
+ Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
+ if (new_res.is_valid()) {
+ changed = true;
+ if (new_res != res) {
+ p_object->set(E.name, new_res);
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ // If it was not replaced, go through and see if there is something to replace.
+ if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
+ changed = true;
+ }
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = p_object->get(E.name);
+ if (_export_customize_dictionary(d, customize_resources_plugins)) {
+ // May have been generated, so set back just in case
+ p_object->set(E.name, d);
+ changed = true;
+ }
+ } break;
+ case Variant::ARRAY: {
+ Array a = p_object->get(E.name);
+ if (_export_customize_array(a, customize_resources_plugins)) {
+ // May have been generated, so set back just in case
+ p_object->set(E.name, a);
+ changed = true;
+ }
+ } break;
+ default: {
+ }
+ }
+ }
+ return changed;
+}
+
+bool EditorExportPlatform::_export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
+ bool changed = false;
+
+ if (p_node == p_root || p_node->get_owner() == p_root) {
+ if (_export_customize_object(p_node, customize_resources_plugins)) {
+ changed = true;
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ if (_export_customize_scene_resources(p_root, p_node->get_child(i), customize_resources_plugins)) {
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+String EditorExportPlatform::_export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save) {
+ if (!p_force_save && customize_resources_plugins.is_empty() && customize_scenes_plugins.is_empty()) {
+ return p_path; // do none
+ }
+
+ // Check if a cache exists
+ if (export_cache.has(p_path)) {
+ FileExportCache &fec = export_cache[p_path];
+
+ if (fec.saved_path.is_empty() || FileAccess::exists(fec.saved_path)) {
+ // Destination file exists (was not erased) or not needed
+
+ uint64_t mod_time = FileAccess::get_modified_time(p_path);
+ if (fec.source_modified_time == mod_time) {
+ // Cached (modified time matches).
+ fec.used = true;
+ return fec.saved_path.is_empty() ? p_path : fec.saved_path;
+ }
+
+ String md5 = FileAccess::get_md5(p_path);
+ if (FileAccess::exists(p_path + ".import")) {
+ // Also consider the import file in the string
+ md5 += FileAccess::get_md5(p_path + ".import");
+ }
+ if (fec.source_md5 == md5) {
+ // Cached (md5 matches).
+ fec.source_modified_time = mod_time;
+ fec.used = true;
+ return fec.saved_path.is_empty() ? p_path : fec.saved_path;
+ }
+ }
+ }
+
+ FileExportCache fec;
+ fec.used = true;
+ fec.source_modified_time = FileAccess::get_modified_time(p_path);
+
+ String md5 = FileAccess::get_md5(p_path);
+ if (FileAccess::exists(p_path + ".import")) {
+ // Also consider the import file in the string
+ md5 += FileAccess::get_md5(p_path + ".import");
+ }
+
+ fec.source_md5 = md5;
+
+ // Check if it should convert
+
+ String type = ResourceLoader::get_resource_type(p_path);
+
+ bool modified = false;
+
+ String save_path;
+
+ if (type == "PackedScene") { // Its a scene.
+ Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_FAIL_COND_V(ps.is_null(), p_path);
+ Node *node = ps->instantiate();
+ ERR_FAIL_COND_V(node == nullptr, p_path);
+ if (customize_scenes_plugins.size()) {
+ for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
+ Node *customized = customize_scenes_plugins[i]->_customize_scene(node, p_path);
+ if (customized != nullptr) {
+ node = customized;
+ modified = true;
+ }
+ }
+ }
+ if (customize_resources_plugins.size()) {
+ if (_export_customize_scene_resources(node, node, customize_resources_plugins)) {
+ modified = true;
+ }
+ }
+
+ if (modified || p_force_save) {
+ // If modified, save it again. This is also used for TSCN -> SCN conversion on export.
+
+ String base_file = p_path.get_file().get_basename() + ".scn"; // use SCN for saving (binary) and repack (If conversting, TSCN PackedScene representation is inefficient, so repacking is also desired).
+ save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file);
+
+ Ref<PackedScene> s;
+ s.instantiate();
+ s->pack(node);
+ Error err = ResourceSaver::save(s, save_path);
+ ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export scene file to: " + save_path);
+ }
+ } else {
+ Ref<Resource> res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_FAIL_COND_V(res.is_null(), p_path);
+
+ if (customize_resources_plugins.size()) {
+ for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) {
+ Ref<Resource> new_res = customize_resources_plugins[i]->_customize_resource(res, p_path);
+ if (new_res.is_valid()) {
+ modified = true;
+ if (new_res != res) {
+ res = new_res;
+ }
+ break;
+ }
+ }
+
+ if (_export_customize_object(res.ptr(), customize_resources_plugins)) {
+ modified = true;
+ }
+ }
+
+ if (modified || p_force_save) {
+ // If modified, save it again. This is also used for TRES -> RES conversion on export.
+
+ String base_file = p_path.get_file().get_basename() + ".res"; // use RES for saving (binary)
+ save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file);
+
+ Error err = ResourceSaver::save(res, save_path);
+ ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export resource file to: " + save_path);
+ }
+ }
+
+ fec.saved_path = save_path;
+
+ export_cache[p_path] = fec;
+
+ return save_path.is_empty() ? p_path : save_path;
+}
+
Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) {
//figure out paths of files that will be exported
HashSet<String> paths;
@@ -600,6 +891,15 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Error err = OK;
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ struct SortByName {
+ bool operator()(const Ref<EditorExportPlugin> &left, const Ref<EditorExportPlugin> &right) const {
+ return left->_get_name() < right->_get_name();
+ }
+ };
+
+ // Always sort by name, to so if for some reason theya are re-arranged, it still works.
+ export_plugins.sort_custom<SortByName>();
+
for (int i = 0; i < export_plugins.size(); i++) {
export_plugins.write[i]->set_export_preset(p_preset);
@@ -621,9 +921,66 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
export_plugins.write[i]->_clear();
}
- FeatureContainers feature_containers = get_feature_containers(p_preset, p_debug);
- HashSet<String> &features = feature_containers.features;
- Vector<String> &features_pv = feature_containers.features_pv;
+ HashSet<String> features = get_features(p_preset, p_debug);
+ PackedStringArray features_psa;
+ for (const String &feature : features) {
+ features_psa.push_back(feature);
+ }
+
+ // Check if custom processing is needed
+ uint32_t custom_resources_hash = HASH_MURMUR3_SEED;
+ uint32_t custom_scene_hash = HASH_MURMUR3_SEED;
+
+ LocalVector<Ref<EditorExportPlugin>> customize_resources_plugins;
+ LocalVector<Ref<EditorExportPlugin>> customize_scenes_plugins;
+
+ for (int i = 0; i < export_plugins.size(); i++) {
+ if (export_plugins[i]->_begin_customize_resources(Ref<EditorExportPlatform>(this), features_psa)) {
+ customize_resources_plugins.push_back(export_plugins[i]);
+
+ custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
+ uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
+ custom_resources_hash = hash_murmur3_one_64(hash, custom_resources_hash);
+ }
+ if (export_plugins[i]->_begin_customize_scenes(Ref<EditorExportPlatform>(this), features_psa)) {
+ customize_scenes_plugins.push_back(export_plugins[i]);
+
+ custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
+ uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
+ custom_scene_hash = hash_murmur3_one_64(hash, custom_scene_hash);
+ }
+ }
+
+ HashMap<String, FileExportCache> export_cache;
+ String export_base_path = ProjectSettings::get_singleton()->get_project_data_path().path_join("exported/") + itos(custom_resources_hash);
+
+ bool convert_text_to_binary = GLOBAL_GET("editor/export/convert_text_resources_to_binary");
+
+ if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) {
+ // See if we have something to open
+ Ref<FileAccess> f = FileAccess::open(export_base_path.path_join("file_cache"), FileAccess::READ);
+ if (f.is_valid()) {
+ String l = f->get_line();
+ while (l != String()) {
+ Vector<String> fields = l.split("::");
+ if (fields.size() == 4) {
+ FileExportCache fec;
+ String path = fields[0];
+ fec.source_md5 = fields[1].strip_edges();
+ fec.source_modified_time = fields[2].strip_edges().to_int();
+ fec.saved_path = fields[3];
+ fec.used = false; // Assume unused until used.
+ export_cache[path] = fec;
+ }
+ l = f->get_line();
+ }
+ } else {
+ // create the path
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ d->change_dir(ProjectSettings::get_singleton()->get_project_data_path());
+ d->make_dir_recursive("exported/" + itos(custom_resources_hash));
+ }
+ }
//store everything in the export medium
int idx = 0;
@@ -634,82 +991,134 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
String type = ResourceLoader::get_resource_type(path);
if (FileAccess::exists(path + ".import")) {
- //file is imported, replace by what it imports
- Ref<ConfigFile> config;
- config.instantiate();
- err = config->load(path + ".import");
- if (err != OK) {
- ERR_PRINT("Could not parse: '" + path + "', not exported.");
- continue;
- }
+ // Before doing this, try to see if it can be customized
+
+ String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, false);
+
+ if (export_path != path) {
+ // It was actually customized..
+ // Since the original file is likely not recognized, just use the import system
+
+ Ref<ConfigFile> config;
+ config.instantiate();
+ err = config->load(path + ".import");
+ if (err != OK) {
+ ERR_PRINT("Could not parse: '" + path + "', not exported.");
+ continue;
+ }
+ config->set_value("remap", "type", ResourceLoader::get_resource_type(export_path));
+
+ // Erase all PAths
+ List<String> keys;
+ config->get_section_keys("remap", &keys);
+ for (const String &K : keys) {
+ if (E.begins_with("path")) {
+ config->erase_section_key("remap", K);
+ }
+ }
+ // Set actual converted path.
+ config->set_value("remap", "path", export_path);
- String importer_type = config->get_value("remap", "importer");
+ // erase useless sections
+ config->erase_section("deps");
+ config->erase_section("params");
- if (importer_type == "keep") {
- //just keep file as-is
- Vector<uint8_t> array = FileAccess::get_file_as_array(path);
- err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ String import_text = config->encode_to_text();
+ CharString cs = import_text.utf8();
+ Vector<uint8_t> sarr;
+ sarr.resize(cs.size());
+ memcpy(sarr.ptrw(), cs.ptr(), sarr.size());
+ err = p_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
+ // Now actual remapped file:
+ sarr = FileAccess::get_file_as_array(export_path);
+ err = p_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
+ } else {
+ // file is imported and not customized, replace by what it imports
+ Ref<ConfigFile> config;
+ config.instantiate();
+ err = config->load(path + ".import");
+ if (err != OK) {
+ ERR_PRINT("Could not parse: '" + path + "', not exported.");
+ continue;
+ }
- continue;
- }
+ String importer_type = config->get_value("remap", "importer");
- List<String> remaps;
- config->get_section_keys("remap", &remaps);
+ if (importer_type == "keep") {
+ //just keep file as-is
+ Vector<uint8_t> array = FileAccess::get_file_as_array(path);
+ err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
- HashSet<String> remap_features;
+ if (err != OK) {
+ return err;
+ }
- for (const String &F : remaps) {
- String remap = F;
- String feature = remap.get_slice(".", 1);
- if (features.has(feature)) {
- remap_features.insert(feature);
+ continue;
}
- }
- if (remap_features.size() > 1) {
- this->resolve_platform_feature_priorities(p_preset, remap_features);
- }
+ List<String> remaps;
+ config->get_section_keys("remap", &remaps);
- err = OK;
+ HashSet<String> remap_features;
- for (const String &F : remaps) {
- String remap = F;
- if (remap == "path") {
- String remapped_path = config->get_value("remap", remap);
- Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path);
- err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
- } else if (remap.begins_with("path.")) {
+ for (const String &F : remaps) {
+ String remap = F;
String feature = remap.get_slice(".", 1);
+ if (features.has(feature)) {
+ remap_features.insert(feature);
+ }
+ }
- if (remap_features.has(feature)) {
+ if (remap_features.size() > 1) {
+ this->resolve_platform_feature_priorities(p_preset, remap_features);
+ }
+
+ err = OK;
+
+ for (const String &F : remaps) {
+ String remap = F;
+ if (remap == "path") {
String remapped_path = config->get_value("remap", remap);
Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path);
err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ } else if (remap.begins_with("path.")) {
+ String feature = remap.get_slice(".", 1);
+
+ if (remap_features.has(feature)) {
+ String remapped_path = config->get_value("remap", remap);
+ Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path);
+ err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ }
}
}
- }
- if (err != OK) {
- return err;
- }
+ if (err != OK) {
+ return err;
+ }
- //also save the .import file
- Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import");
- err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key);
+ //also save the .import file
+ Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import");
+ err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key);
- if (err != OK) {
- return err;
+ if (err != OK) {
+ return err;
+ }
}
} else {
+ // Customize
+
bool do_export = true;
for (int i = 0; i < export_plugins.size(); i++) {
if (export_plugins[i]->get_script_instance()) { //script based
- export_plugins.write[i]->_export_file_script(path, type, features_pv);
+ export_plugins.write[i]->_export_file_script(path, type, features_psa);
} else {
export_plugins.write[i]->_export_file(path, type, features);
}
@@ -745,8 +1154,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
//just store it as it comes
if (do_export) {
- Vector<uint8_t> array = FileAccess::get_file_as_array(path);
- err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ // Customization only happens if plugins did not take care of it before
+ bool force_binary = convert_text_to_binary && (path.get_extension().to_lower() == "tres" || path.get_extension().to_lower() == "tscn");
+ String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, force_binary);
+
+ if (export_path != path) {
+ // Add a remap entry
+ path_remaps.push_back(path);
+ path_remaps.push_back(export_path);
+ }
+
+ Vector<uint8_t> array = FileAccess::get_file_as_array(export_path);
+ err = p_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
@@ -756,6 +1175,31 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
idx++;
}
+ if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) {
+ // End scene customization
+
+ String fcache = export_base_path.path_join("file_cache");
+ Ref<FileAccess> f = FileAccess::open(fcache, FileAccess::WRITE);
+
+ if (f.is_valid()) {
+ for (const KeyValue<String, FileExportCache> &E : export_cache) {
+ if (E.value.used) { // May be old, unused
+ String l = E.key + "::" + E.value.source_md5 + "::" + itos(E.value.source_modified_time) + "::" + E.value.saved_path;
+ f->store_line(l);
+ }
+ }
+ } else {
+ ERR_PRINT("Error opening export file cache: " + fcache);
+ }
+
+ for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) {
+ customize_resources_plugins[i]->_end_customize_resources();
+ }
+
+ for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
+ customize_scenes_plugins[i]->_end_customize_scenes();
+ }
+ }
//save config!
Vector<String> custom_list;
@@ -845,7 +1289,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
} else {
// Use default text server data.
- String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
+ String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_icu_data");
TS->save_support_data(icu_data_file);
Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
@@ -858,7 +1302,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
String config_file = "project.binary";
- String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
+ String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp" + config_file);
ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list);
Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb);
DirAccess::remove_file_or_error(engine_cfb);
@@ -882,7 +1326,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir());
- String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp");
+ String tmppath = EditorPaths::get_singleton()->get_cache_dir().path_join("packtmp");
Ref<FileAccess> ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
if (ftmp.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Cannot create file \"%s\"."), tmppath));
@@ -1174,5 +1618,23 @@ void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags
}
}
+bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String templates_error;
+ bool valid_export_configuration = has_valid_export_configuration(p_preset, templates_error, r_missing_templates);
+
+ String project_configuration_error;
+ bool valid_project_configuration = has_valid_project_configuration(p_preset, project_configuration_error);
+
+ if (!templates_error.is_empty()) {
+ r_error += templates_error;
+ }
+
+ if (!project_configuration_error.is_empty()) {
+ r_error += project_configuration_error;
+ }
+
+ return valid_export_configuration && valid_project_configuration;
+}
+
EditorExportPlatform::EditorExportPlatform() {
}
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index 832a0cf846..93bc54284f 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -40,6 +40,8 @@ struct EditorProgress;
#include "scene/gui/rich_text_label.h"
#include "scene/main/node.h"
+class EditorExportPlugin;
+
class EditorExportPlatform : public RefCounted {
GDCLASS(EditorExportPlatform, RefCounted);
@@ -85,11 +87,6 @@ private:
EditorProgress *ep = nullptr;
};
- struct FeatureContainers {
- HashSet<String> features;
- Vector<String> features_pv;
- };
-
Vector<ExportMessage> messages;
void _export_find_resources(EditorFileSystemDirectory *p_dir, HashSet<String> &p_paths);
@@ -104,13 +101,27 @@ private:
static Error _add_shared_object(void *p_userdata, const SharedObject &p_so);
+ struct FileExportCache {
+ uint64_t source_modified_time = 0;
+ String source_md5;
+ String saved_path;
+ bool used = false;
+ };
+
+ bool _export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+ bool _export_customize_array(Array &array, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+ bool _export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+ bool _export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
+
+ String _export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save);
+
protected:
struct ExportNotifier {
ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
~ExportNotifier();
};
- FeatureContainers get_feature_containers(const Ref<EditorExportPreset> &p_preset, bool p_debug) const;
+ HashSet<String> get_features(const Ref<EditorExportPreset> &p_preset, bool p_debug) const;
bool exists_export_template(String template_file_name, String *err) const;
String find_export_template(String template_file_name, String *err = nullptr) const;
@@ -122,10 +133,12 @@ public:
struct ExportOption {
PropertyInfo option;
Variant default_value;
+ bool update_visibility = false;
- ExportOption(const PropertyInfo &p_info, const Variant &p_default) :
+ ExportOption(const PropertyInfo &p_info, const Variant &p_default, bool p_update_visibility = false) :
option(p_info),
- default_value(p_default) {
+ default_value(p_default),
+ update_visibility(p_update_visibility) {
}
ExportOption() {}
};
@@ -141,13 +154,13 @@ public:
messages.push_back(msg);
switch (p_type) {
case EXPORT_MESSAGE_INFO: {
- print_line(vformat("%s: %s\n", msg.category, msg.text));
+ print_line(vformat("%s: %s", msg.category, msg.text));
} break;
case EXPORT_MESSAGE_WARNING: {
- WARN_PRINT(vformat("%s: %s\n", msg.category, msg.text));
+ WARN_PRINT(vformat("%s: %s", msg.category, msg.text));
} break;
case EXPORT_MESSAGE_ERROR: {
- ERR_PRINT(vformat("%s: %s\n", msg.category, msg.text));
+ ERR_PRINT(vformat("%s: %s", msg.category, msg.text));
} break;
default:
break;
@@ -175,7 +188,7 @@ public:
virtual void get_export_options(List<ExportOption> *r_options) = 0;
virtual bool should_update_export_options() { return false; }
- virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; }
+ virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; }
virtual String get_os_name() const = 0;
virtual String get_name() const = 0;
@@ -205,7 +218,9 @@ public:
virtual Ref<Texture2D> get_run_icon() const { return get_logo(); }
String test_etc2() const;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0;
+ bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const = 0;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) = 0;
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index 5e0044f2ae..8538414523 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -75,7 +75,7 @@ Ref<Texture2D> EditorExportPlatformPC::get_logo() const {
return logo;
}
-bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformPC::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
bool valid = false;
@@ -106,6 +106,10 @@ bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset,
return valid;
}
+bool EditorExportPlatformPC::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+ return true;
+}
+
Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
@@ -181,9 +185,9 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
String src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path);
String target_path;
if (so_files[i].target.is_empty()) {
- target_path = p_path.get_base_dir().plus_file(src_path.get_file());
+ target_path = p_path.get_base_dir().path_join(src_path.get_file());
} else {
- target_path = p_path.get_base_dir().plus_file(so_files[i].target).plus_file(src_path.get_file());
+ target_path = p_path.get_base_dir().path_join(so_files[i].target).path_join(src_path.get_file());
}
if (da->dir_exists(src_path)) {
diff --git a/editor/export/editor_export_platform_pc.h b/editor/export/editor_export_platform_pc.h
index bdb86e924a..cf96db6c2d 100644
--- a/editor/export/editor_export_platform_pc.h
+++ b/editor/export/editor_export_platform_pc.h
@@ -52,7 +52,8 @@ public:
virtual String get_os_name() const override;
virtual Ref<Texture2D> get_logo() const override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
virtual String get_template_file_name(const String &p_target, const String &p_arch) const = 0;
diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp
index cf3a9b0810..971ea579cc 100644
--- a/editor/export/editor_export_plugin.cpp
+++ b/editor/export/editor_export_plugin.cpp
@@ -138,6 +138,64 @@ void EditorExportPlugin::_export_end_script() {
GDVIRTUAL_CALL(_export_end);
}
+// Customization
+
+bool EditorExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret)) {
+ return ret;
+ }
+ return false;
+}
+
+Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) {
+ Ref<Resource> ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_customize_resource, p_resource, p_path, ret)) {
+ return ret;
+ }
+ return Ref<Resource>();
+}
+
+bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret)) {
+ return ret;
+ }
+ return false;
+}
+
+Node *EditorExportPlugin::_customize_scene(Node *p_root, const String &p_path) {
+ Node *ret = nullptr;
+ if (GDVIRTUAL_REQUIRED_CALL(_customize_scene, p_root, p_path, ret)) {
+ return ret;
+ }
+ return nullptr;
+}
+
+uint64_t EditorExportPlugin::_get_customization_configuration_hash() const {
+ uint64_t ret = 0;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_customization_configuration_hash, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+void EditorExportPlugin::_end_customize_scenes() {
+ GDVIRTUAL_CALL(_end_customize_scenes);
+}
+
+void EditorExportPlugin::_end_customize_resources() {
+ GDVIRTUAL_CALL(_end_customize_resources);
+}
+
+String EditorExportPlugin::_get_name() const {
+ String ret;
+ if (GDVIRTUAL_REQUIRED_CALL(_get_name, ret)) {
+ return ret;
+ }
+ return "";
+}
+
void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
}
@@ -164,38 +222,20 @@ void EditorExportPlugin::_bind_methods() {
GDVIRTUAL_BIND(_export_file, "path", "type", "features");
GDVIRTUAL_BIND(_export_begin, "features", "is_debug", "path", "flags");
GDVIRTUAL_BIND(_export_end);
-}
-EditorExportPlugin::EditorExportPlugin() {
-}
+ GDVIRTUAL_BIND(_begin_customize_resources, "platform", "features");
+ GDVIRTUAL_BIND(_customize_resource, "resource", "path");
-///////////////////////
+ GDVIRTUAL_BIND(_begin_customize_scenes, "platform", "features");
+ GDVIRTUAL_BIND(_customize_scene, "scene", "path");
-void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
- String extension = p_path.get_extension().to_lower();
- if (extension != "tres" && extension != "tscn") {
- return;
- }
+ GDVIRTUAL_BIND(_get_customization_configuration_hash);
- bool convert = GLOBAL_GET("editor/export/convert_text_resources_to_binary");
- if (!convert) {
- return;
- }
- String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
- Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
- if (err != OK) {
- DirAccess::remove_file_or_error(tmp_path);
- ERR_FAIL();
- }
- Vector<uint8_t> data = FileAccess::get_file_as_array(tmp_path);
- if (data.size() == 0) {
- DirAccess::remove_file_or_error(tmp_path);
- ERR_FAIL();
- }
- DirAccess::remove_file_or_error(tmp_path);
- add_file(p_path + ".converted.res", data, true);
+ GDVIRTUAL_BIND(_end_customize_scenes);
+ GDVIRTUAL_BIND(_end_customize_resources);
+
+ GDVIRTUAL_BIND(_get_name);
}
-EditorExportTextSceneToBinaryPlugin::EditorExportTextSceneToBinaryPlugin() {
- GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false);
+EditorExportPlugin::EditorExportPlugin() {
}
diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h
index 04ebc1dfed..3f37ed40be 100644
--- a/editor/export/editor_export_plugin.h
+++ b/editor/export/editor_export_plugin.h
@@ -34,6 +34,7 @@
#include "core/extension/native_extension.h"
#include "editor_export_preset.h"
#include "editor_export_shared_object.h"
+#include "scene/main/node.h"
class EditorExportPlugin : public RefCounted {
GDCLASS(EditorExportPlugin, RefCounted);
@@ -77,6 +78,7 @@ class EditorExportPlugin : public RefCounted {
macos_plugin_files.clear();
}
+ // Export
void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features);
void _export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags);
void _export_end_script();
@@ -108,6 +110,31 @@ protected:
GDVIRTUAL4(_export_begin, Vector<String>, bool, String, uint32_t)
GDVIRTUAL0(_export_end)
+ GDVIRTUAL2RC(bool, _begin_customize_resources, const Ref<EditorExportPlatform> &, const Vector<String> &)
+ GDVIRTUAL2R(Ref<Resource>, _customize_resource, const Ref<Resource> &, String)
+
+ GDVIRTUAL2RC(bool, _begin_customize_scenes, const Ref<EditorExportPlatform> &, const Vector<String> &)
+ GDVIRTUAL2R(Node *, _customize_scene, Node *, String)
+ GDVIRTUAL0RC(uint64_t, _get_customization_configuration_hash)
+
+ GDVIRTUAL0(_end_customize_scenes)
+ GDVIRTUAL0(_end_customize_resources)
+
+ GDVIRTUAL0RC(String, _get_name)
+
+ bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization
+ Ref<Resource> _customize_resource(const Ref<Resource> &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made.
+
+ bool _begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization
+ Node *_customize_scene(Node *p_root, const String &p_path); // Return true if a change was made
+
+ uint64_t _get_customization_configuration_hash() const; // Hash used for caching customized resources and scenes.
+
+ void _end_customize_scenes();
+ void _end_customize_resources();
+
+ virtual String _get_name() const;
+
public:
Vector<String> get_ios_frameworks() const;
Vector<String> get_ios_embedded_frameworks() const;
@@ -121,12 +148,4 @@ public:
EditorExportPlugin();
};
-class EditorExportTextSceneToBinaryPlugin : public EditorExportPlugin {
- GDCLASS(EditorExportTextSceneToBinaryPlugin, EditorExportPlugin);
-
-public:
- virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override;
- EditorExportTextSceneToBinaryPlugin();
-};
-
#endif // EDITOR_EXPORT_PLUGIN_H
diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp
index cdf69e727d..4411ad11bc 100644
--- a/editor/export/editor_export_preset.cpp
+++ b/editor/export/editor_export_preset.cpp
@@ -34,6 +34,9 @@ bool EditorExportPreset::_set(const StringName &p_name, const Variant &p_value)
if (values.has(p_name)) {
values[p_name] = p_value;
EditorExport::singleton->save_presets();
+ if (update_visibility[p_name]) {
+ notify_property_list_changed();
+ }
return true;
}
@@ -51,7 +54,7 @@ bool EditorExportPreset::_get(const StringName &p_name, Variant &r_ret) const {
void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const {
for (const PropertyInfo &E : properties) {
- if (platform->get_export_option_visibility(E.name, values)) {
+ if (platform->get_export_option_visibility(this, E.name, values)) {
p_list->push_back(E);
}
}
diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h
index 00109396b0..0c780c45cd 100644
--- a/editor/export/editor_export_preset.h
+++ b/editor/export/editor_export_preset.h
@@ -67,6 +67,7 @@ private:
List<PropertyInfo> properties;
HashMap<StringName, Variant> values;
+ HashMap<StringName, bool> update_visibility;
String name;
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index a7d9d7f068..ceb5b63293 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -91,7 +91,7 @@ void ExportTemplateManager::_update_template_status() {
install_options_vb->show();
if (templates.has(current_version)) {
- current_installed_path->set_text(templates_dir.plus_file(current_version));
+ current_installed_path->set_text(templates_dir.path_join(current_version));
}
}
@@ -146,7 +146,7 @@ void ExportTemplateManager::_download_template(const String &p_url, bool p_skip_
download_progress_hb->show();
_set_current_progress_status(TTR("Starting the download..."));
- download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"));
+ download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_templates.tpz"));
download_templates->set_use_threads(true);
const String proxy_host = EDITOR_GET("network/http_proxy/host");
@@ -172,7 +172,7 @@ void ExportTemplateManager::_download_template_completed(int p_status, int p_cod
case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED:
case HTTPRequest::RESULT_CONNECTION_ERROR:
case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH:
- case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR:
+ case HTTPRequest::RESULT_TLS_HANDSHAKE_ERROR:
case HTTPRequest::RESULT_CANT_CONNECT: {
_set_current_progress_status(TTR("Can't connect to the mirror."), true);
} break;
@@ -345,8 +345,8 @@ bool ExportTemplateManager::_humanize_http_status(HTTPRequest *p_request, String
*r_status = TTR("Connection Error");
success = false;
break;
- case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR:
- *r_status = TTR("SSL Handshake Error");
+ case HTTPClient::STATUS_TLS_HANDSHAKE_ERROR:
+ *r_status = TTR("TLS Handshake Error");
success = false;
break;
}
@@ -440,7 +440,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
}
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(version);
+ String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(version);
Error err = d->make_dir_recursive(template_path);
if (err != OK) {
EditorNode::get_singleton()->show_warning(TTR("Error creating path for extracting templates:") + "\n" + template_path);
@@ -486,12 +486,12 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
if (base_dir != contents_dir && base_dir.begins_with(contents_dir)) {
base_dir = base_dir.substr(contents_dir.length(), file_path.length()).trim_prefix("/");
- file = base_dir.plus_file(file);
+ file = base_dir.path_join(file);
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_CONTINUE(da.is_null());
- String output_dir = template_path.plus_file(base_dir);
+ String output_dir = template_path.path_join(base_dir);
if (!DirAccess::exists(output_dir)) {
Error mkdir_err = da->make_dir_recursive(output_dir);
@@ -503,7 +503,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
p->step(TTR("Importing:") + " " + file, fc);
}
- String to_write = template_path.plus_file(file);
+ String to_write = template_path.path_join(file);
Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
if (f.is_null()) {
@@ -544,14 +544,14 @@ void ExportTemplateManager::_uninstall_template_confirmed() {
Error err = da->change_dir(templates_dir);
ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'.");
err = da->change_dir(uninstall_version);
- ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
+ ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.path_join(uninstall_version) + "'.");
err = da->erase_contents_recursive();
- ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(uninstall_version) + "'.");
+ ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.path_join(uninstall_version) + "'.");
da->change_dir("..");
err = da->remove(uninstall_version);
- ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
+ ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.path_join(uninstall_version) + "'.");
_update_template_status();
}
@@ -618,7 +618,7 @@ void ExportTemplateManager::_installed_table_button_cbk(Object *p_item, int p_co
void ExportTemplateManager::_open_template_folder(const String &p_version) {
const String &templates_dir = EditorPaths::get_singleton()->get_export_templates_dir();
- OS::get_singleton()->shell_open("file://" + templates_dir.plus_file(p_version));
+ OS::get_singleton()->shell_open("file://" + templates_dir.path_join(p_version));
}
void ExportTemplateManager::popup_manager() {
@@ -641,13 +641,13 @@ void ExportTemplateManager::_hide_dialog() {
}
bool ExportTemplateManager::can_install_android_template() {
- const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
- return FileAccess::exists(templates_dir.plus_file("android_source.zip"));
+ const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
+ return FileAccess::exists(templates_dir.path_join("android_source.zip"));
}
Error ExportTemplateManager::install_android_template() {
- const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
- const String &source_zip = templates_path.plus_file("android_source.zip");
+ const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
+ const String &source_zip = templates_path.path_join("android_source.zip");
ERR_FAIL_COND_V(!FileAccess::exists(source_zip), ERR_CANT_OPEN);
return install_android_template_from_file(source_zip);
}
@@ -723,11 +723,11 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
unzCloseCurrentFile(pkg);
if (!dirs_tested.has(base_dir)) {
- da->make_dir_recursive(String("android/build").plus_file(base_dir));
+ da->make_dir_recursive(String("android/build").path_join(base_dir));
dirs_tested.insert(base_dir);
}
- String to_write = String("res://android/build").plus_file(path);
+ String to_write = String("res://android/build").path_join(path);
Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
if (f.is_valid()) {
f->store_buffer(data.ptr(), data.size());
@@ -868,13 +868,13 @@ ExportTemplateManager::ExportTemplateManager() {
current_open_button = memnew(Button);
current_open_button->set_text(TTR("Open Folder"));
- current_open_button->set_tooltip(TTR("Open the folder containing installed templates for the current version."));
+ current_open_button->set_tooltip_text(TTR("Open the folder containing installed templates for the current version."));
current_installed_hb->add_child(current_open_button);
current_open_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_open_template_folder).bind(VERSION_FULL_CONFIG));
current_uninstall_button = memnew(Button);
current_uninstall_button->set_text(TTR("Uninstall"));
- current_uninstall_button->set_tooltip(TTR("Uninstall templates for the current version."));
+ current_uninstall_button->set_tooltip_text(TTR("Uninstall templates for the current version."));
current_installed_hb->add_child(current_uninstall_button);
current_uninstall_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template).bind(VERSION_FULL_CONFIG));
@@ -915,14 +915,14 @@ ExportTemplateManager::ExportTemplateManager() {
Button *download_current_button = memnew(Button);
download_current_button->set_text(TTR("Download and Install"));
- download_current_button->set_tooltip(TTR("Download and install templates for the current version from the best possible mirror."));
+ download_current_button->set_tooltip_text(TTR("Download and install templates for the current version from the best possible mirror."));
download_install_hb->add_child(download_current_button);
download_current_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_current));
// Update downloads buttons to prevent unsupported downloads.
if (!downloads_available) {
download_current_button->set_disabled(true);
- download_current_button->set_tooltip(TTR("Official export templates aren't available for development builds."));
+ download_current_button->set_tooltip_text(TTR("Official export templates aren't available for development builds."));
}
HBoxContainer *install_file_hb = memnew(HBoxContainer);
@@ -931,7 +931,7 @@ ExportTemplateManager::ExportTemplateManager() {
install_file_button = memnew(Button);
install_file_button->set_text(TTR("Install from File"));
- install_file_button->set_tooltip(TTR("Install templates from a local file."));
+ install_file_button->set_tooltip_text(TTR("Install templates from a local file."));
install_file_hb->add_child(install_file_button);
install_file_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_install_file));
@@ -956,7 +956,7 @@ ExportTemplateManager::ExportTemplateManager() {
Button *download_cancel_button = memnew(Button);
download_cancel_button->set_text(TTR("Cancel"));
- download_cancel_button->set_tooltip(TTR("Cancel the download of the templates."));
+ download_cancel_button->set_tooltip_text(TTR("Cancel the download of the templates."));
download_progress_hb->add_child(download_cancel_button);
download_cancel_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_cancel_template_download));
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index cb82cefbbb..00a0e08d3a 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -185,9 +185,9 @@ void ProjectExportDialog::_update_export_all() {
export_all_button->set_disabled(!can_export);
if (can_export) {
- export_all_button->set_tooltip(TTR("Export the project for all the presets defined."));
+ export_all_button->set_tooltip_text(TTR("Export the project for all the presets defined."));
} else {
- export_all_button->set_tooltip(TTR("All presets must have an export path defined for Export All to work."));
+ export_all_button->set_tooltip_text(TTR("All presets must have an export path defined for Export All to work."));
}
}
@@ -219,6 +219,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
export_path->show();
duplicate_preset->set_disabled(false);
delete_preset->set_disabled(false);
+ get_ok_button()->set_disabled(false);
name->set_text(current->get_name());
List<String> extension_list = current->get_platform()->get_binary_extensions(current);
@@ -265,7 +266,6 @@ void ProjectExportDialog::_edit_preset(int p_index) {
export_warning->hide();
export_button->set_disabled(true);
- get_ok_button()->set_disabled(true);
} else {
if (error != String()) {
Vector<String> items = error.split("\n", false);
@@ -285,7 +285,6 @@ void ProjectExportDialog::_edit_preset(int p_index) {
export_error->hide();
export_templates_error->hide();
export_button->set_disabled(false);
- get_ok_button()->set_disabled(false);
}
custom_features->set_text(current->get_custom_features());
@@ -1021,12 +1020,12 @@ ProjectExportDialog::ProjectExportDialog() {
mc->add_child(presets);
presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
duplicate_preset = memnew(Button);
- duplicate_preset->set_tooltip(TTR("Duplicate"));
+ duplicate_preset->set_tooltip_text(TTR("Duplicate"));
duplicate_preset->set_flat(true);
preset_hb->add_child(duplicate_preset);
duplicate_preset->connect("pressed", callable_mp(this, &ProjectExportDialog::_duplicate_preset));
delete_preset = memnew(Button);
- delete_preset->set_tooltip(TTR("Delete"));
+ delete_preset->set_tooltip_text(TTR("Delete"));
delete_preset->set_flat(true);
preset_hb->add_child(delete_preset);
delete_preset->connect("pressed", callable_mp(this, &ProjectExportDialog::_delete_preset));
@@ -1042,7 +1041,7 @@ ProjectExportDialog::ProjectExportDialog() {
name->connect("text_changed", callable_mp(this, &ProjectExportDialog::_name_changed));
runnable = memnew(CheckButton);
runnable->set_text(TTR("Runnable"));
- runnable->set_tooltip(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable."));
+ runnable->set_tooltip_text(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable."));
runnable->connect("pressed", callable_mp(this, &ProjectExportDialog::_runnable_pressed));
settings_vb->add_child(runnable);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index b823db68f0..19b4932d3d 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -76,7 +76,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_text(0, dname);
subdirectory_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE);
subdirectory_item->set_icon(0, get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
- subdirectory_item->set_icon_modulate(0, get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")));
+ subdirectory_item->set_icon_modulate(0, get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")));
subdirectory_item->set_selectable(0, true);
String lpath = p_dir->get_path();
subdirectory_item->set_metadata(0, lpath);
@@ -146,7 +146,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
file_item->set_text(0, fi.name);
file_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE);
file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type));
- String file_metadata = lpath.plus_file(fi.name);
+ String file_metadata = lpath.path_join(fi.name);
file_item->set_metadata(0, file_metadata);
if (!p_select_in_favorites && path == file_metadata) {
file_item->select(0);
@@ -246,7 +246,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
}
Ref<Texture2D> folder_icon = get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"));
- const Color folder_color = get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
+ const Color folder_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog"));
String text;
Ref<Texture2D> icon;
@@ -276,7 +276,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
ti->set_text(0, text);
ti->set_icon(0, icon);
ti->set_icon_modulate(0, color);
- ti->set_tooltip(0, fave);
+ ti->set_tooltip_text(0, fave);
ti->set_selectable(0, true);
ti->set_metadata(0, fave);
if (p_select_in_favorites && fave == path) {
@@ -614,11 +614,11 @@ void FileSystemDock::_set_file_display(bool p_active) {
if (p_active) {
file_list_display_mode = FILE_LIST_DISPLAY_LIST;
button_file_list_display_mode->set_icon(get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons")));
- button_file_list_display_mode->set_tooltip(TTR("View items as a grid of thumbnails."));
+ button_file_list_display_mode->set_tooltip_text(TTR("View items as a grid of thumbnails."));
} else {
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
button_file_list_display_mode->set_icon(get_theme_icon(SNAME("FileList"), SNAME("EditorIcons")));
- button_file_list_display_mode->set_tooltip(TTR("View items as a list."));
+ button_file_list_display_mode->set_tooltip_text(TTR("View items as a list."));
}
_update_file_list(true);
@@ -778,7 +778,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
}
Ref<Texture2D> folder_icon = (use_thumbnails) ? folder_thumbnail : get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
- const Color folder_color = get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
+ const Color folder_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog"));
// Build the FileInfo list.
List<FileInfo> file_list;
@@ -867,7 +867,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
String dname = efd->get_subdir(i)->get_name();
files->add_item(dname, folder_icon, true);
- files->set_item_metadata(-1, directory.plus_file(dname) + "/");
+ files->set_item_metadata(-1, directory.path_join(dname) + "/");
files->set_item_icon_modulate(-1, folder_color);
if (cselection.has(dname)) {
@@ -880,7 +880,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
for (int i = 0; i < efd->get_file_count(); i++) {
FileInfo fi;
fi.name = efd->get_file(i);
- fi.path = directory.plus_file(fi.name);
+ fi.path = directory.path_join(fi.name);
fi.type = efd->get_file_type(i);
fi.import_broken = !efd->get_file_import_is_valid(i);
fi.modified_time = efd->get_file_modified_time(i);
@@ -1545,7 +1545,7 @@ void FileSystemDock::_rename_operation_confirm() {
}
String old_path = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1) : to_rename.path;
- String new_path = old_path.get_base_dir().plus_file(new_name);
+ String new_path = old_path.get_base_dir().path_join(new_name);
if (old_path == new_path) {
return;
}
@@ -1605,7 +1605,7 @@ void FileSystemDock::_duplicate_operation_confirm() {
base_dir = base_dir.get_base_dir();
}
- String new_path = base_dir.plus_file(new_name);
+ String new_path = base_dir.path_join(new_name);
// Present a more user friendly warning for name conflict
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
@@ -1630,7 +1630,7 @@ Vector<String> FileSystemDock::_check_existing() {
String &p_to_path = to_move_path;
for (int i = 0; i < to_move.size(); i++) {
String ol_pth = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
- String p_new_path = p_to_path.plus_file(ol_pth.get_file());
+ String p_new_path = p_to_path.path_join(ol_pth.get_file());
FileOrFolder p_item = to_move[i];
String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/");
@@ -1662,7 +1662,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
// Check groups.
for (int i = 0; i < to_move.size(); i++) {
if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) {
- EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.plus_file(to_move[i].path.get_file()));
+ EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.path_join(to_move[i].path.get_file()));
}
}
@@ -1671,7 +1671,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
bool is_moved = false;
for (int i = 0; i < to_move.size(); i++) {
String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
- String new_path = p_to_path.plus_file(old_path.get_file());
+ String new_path = p_to_path.path_join(old_path.get_file());
if (old_path != new_path) {
_try_move_item(to_move[i], new_path, file_renames, folder_renames);
is_moved = true;
@@ -2005,7 +2005,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- make_script_dialog->config("Node", fpath.plus_file("new_script.gd"), false, false);
+ make_script_dialog->config("Node", fpath.path_join("new_script.gd"), false, false);
make_script_dialog->popup_centered();
} break;
@@ -2047,15 +2047,15 @@ void FileSystemDock::_resource_created() {
String type_name = new_resource_dialog->get_selected_type();
if (type_name == "Shader") {
- make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 0);
+ make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 0);
make_shader_dialog->popup_centered();
return;
} else if (type_name == "VisualShader") {
- make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 1);
+ make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 1);
make_shader_dialog->popup_centered();
return;
} else if (type_name == "ShaderInclude") {
- make_shader_dialog->config(fpath.plus_file("new_shader_include"), false, false, 2);
+ make_shader_dialog->config(fpath.path_join("new_shader_include"), false, false, 2);
make_shader_dialog->popup_centered();
return;
}
@@ -2370,11 +2370,11 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
String new_path_base;
if (to_move[i].is_file) {
- new_path = to_dir.plus_file(to_move[i].path.get_file());
+ new_path = to_dir.path_join(to_move[i].path.get_file());
new_path_base = new_path.get_basename() + " (%d)." + new_path.get_extension();
} else {
PackedStringArray path_split = to_move[i].path.split("/");
- new_path = to_dir.plus_file(path_split[path_split.size() - 2]);
+ new_path = to_dir.path_join(path_split[path_split.size() - 2]);
new_path_base = new_path + " (%d)";
}
@@ -2977,7 +2977,7 @@ void FileSystemDock::_file_sort_popup(int p_id) {
MenuButton *FileSystemDock::_create_file_menu_button() {
MenuButton *button = memnew(MenuButton);
button->set_flat(true);
- button->set_tooltip(TTR("Sort files"));
+ button->set_tooltip_text(TTR("Sort files"));
PopupMenu *p = button->get_popup();
p->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_sort_popup));
@@ -3021,10 +3021,10 @@ FileSystemDock::FileSystemDock() {
set_name("FileSystem");
path = "res://";
- // `KeyModifierMask::CMD | Key::C` conflicts with other editor shortcuts.
- ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::C);
+ // `KeyModifierMask::CMD_OR_CTRL | Key::C` conflicts with other editor shortcuts.
+ ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
ED_SHORTCUT("filesystem_dock/copy_uid", TTR("Copy UID"));
- ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KeyModifierMask::CMD | Key::D);
+ ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KeyModifierMask::CMD_OR_CTRL | Key::D);
ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), Key::KEY_DELETE);
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), Key::F2);
ED_SHORTCUT_OVERRIDE("filesystem_dock/rename", "macos", Key::ENTER);
@@ -3040,14 +3040,14 @@ FileSystemDock::FileSystemDock() {
button_hist_prev->set_flat(true);
button_hist_prev->set_disabled(true);
button_hist_prev->set_focus_mode(FOCUS_NONE);
- button_hist_prev->set_tooltip(TTR("Previous Folder/File"));
+ button_hist_prev->set_tooltip_text(TTR("Previous Folder/File"));
toolbar_hbc->add_child(button_hist_prev);
button_hist_next = memnew(Button);
button_hist_next->set_flat(true);
button_hist_next->set_disabled(true);
button_hist_next->set_focus_mode(FOCUS_NONE);
- button_hist_next->set_tooltip(TTR("Next Folder/File"));
+ button_hist_next->set_tooltip_text(TTR("Next Folder/File"));
toolbar_hbc->add_child(button_hist_next);
current_path = memnew(LineEdit);
@@ -3059,7 +3059,7 @@ FileSystemDock::FileSystemDock() {
button_reload = memnew(Button);
button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan));
button_reload->set_focus_mode(FOCUS_NONE);
- button_reload->set_tooltip(TTR("Re-Scan Filesystem"));
+ button_reload->set_tooltip_text(TTR("Re-Scan Filesystem"));
button_reload->hide();
toolbar_hbc->add_child(button_reload);
@@ -3067,7 +3067,7 @@ FileSystemDock::FileSystemDock() {
button_toggle_display_mode->set_toggle_mode(true);
button_toggle_display_mode->connect("toggled", callable_mp(this, &FileSystemDock::_toggle_split_mode));
button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
- button_toggle_display_mode->set_tooltip(TTR("Toggle Split Mode"));
+ button_toggle_display_mode->set_tooltip_text(TTR("Toggle Split Mode"));
button_toggle_display_mode->set_flat(true);
toolbar_hbc->add_child(button_toggle_display_mode);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 81b71b5609..16c5003fdc 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -168,7 +168,7 @@ void FindInFiles::_iterate() {
String folder_name = folders_to_scan[folders_to_scan.size() - 1];
pop_back(folders_to_scan);
- _current_dir = _current_dir.plus_file(folder_name);
+ _current_dir = _current_dir.path_join(folder_name);
PackedStringArray sub_dirs;
_scan_dir("res://" + _current_dir, sub_dirs);
@@ -246,7 +246,7 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) {
} else {
String file_ext = file.get_extension();
if (_extension_filter.has(file_ext)) {
- _files_to_scan.push_back(path.plus_file(file));
+ _files_to_scan.push_back(path.path_join(file));
}
}
}
@@ -373,7 +373,7 @@ FindInFilesDialog::FindInFilesDialog() {
Label *filter_label = memnew(Label);
filter_label->set_text(TTR("Filters:"));
- filter_label->set_tooltip(TTR("Include the files with the following extensions. Add or remove them in ProjectSettings."));
+ filter_label->set_tooltip_text(TTR("Include the files with the following extensions. Add or remove them in ProjectSettings."));
gc->add_child(filter_label);
_filters_container = memnew(HBoxContainer);
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index f16097f109..dac86acae4 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/box_container.h"
@@ -88,7 +89,7 @@ void GroupDialog::_load_nodes(Node *p_current) {
if (keep) {
node->set_text(0, item_name);
node->set_metadata(0, path);
- node->set_tooltip(0, path);
+ node->set_tooltip_text(0, path);
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(p_current, "Node");
node->set_icon(0, icon);
@@ -397,6 +398,10 @@ void GroupDialog::_notification(int p_what) {
}
}
+void GroupDialog::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void GroupDialog::edit() {
popup_centered();
@@ -696,6 +701,10 @@ void GroupsEditor::update_tree() {
}
}
+void GroupsEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void GroupsEditor::set_current(Node *p_node) {
node = p_node;
update_tree();
diff --git a/editor/groups_editor.h b/editor/groups_editor.h
index fec8913e31..8bbea4e652 100644
--- a/editor/groups_editor.h
+++ b/editor/groups_editor.h
@@ -31,7 +31,6 @@
#ifndef GROUPS_EDITOR_H
#define GROUPS_EDITOR_H
-#include "core/object/undo_redo.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
@@ -40,6 +39,8 @@
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class GroupDialog : public AcceptDialog {
GDCLASS(GroupDialog, AcceptDialog);
@@ -68,7 +69,7 @@ class GroupDialog : public AcceptDialog {
String selected_group;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _group_selected();
@@ -103,7 +104,7 @@ public:
};
void edit();
- void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
GroupDialog();
};
@@ -119,7 +120,7 @@ class GroupsEditor : public VBoxContainer {
Button *add = nullptr;
Tree *tree = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void update_tree();
void _add_group(const String &p_group = "");
@@ -137,7 +138,7 @@ public:
COPY_GROUP,
};
- void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_current(Node *p_node);
GroupsEditor();
diff --git a/editor/icons/BezierHandlesBalanced.svg b/editor/icons/BezierHandlesBalanced.svg
index 911029e431..b1778b1a5e 100644
--- a/editor/icons/BezierHandlesBalanced.svg
+++ b/editor/icons/BezierHandlesBalanced.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.4559186 5.1473018-4.7355323 1.5541798" fill="none" stroke="#5fb2ff" stroke-width=".618"/><path d="m10.790357 4.2063094-2.5009748.9433136" fill="none" stroke="#5fb2ff" stroke-width=".614897"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m1.7157324 5.8754878a1.2675855 1.1997888 0 0 0 -1.26757806 1.1992188 1.2675855 1.1997888 0 0 0 1.26757806 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765616-.8007812.84677333.80148375 0 0 1 .84765616-.8007812z"/><path d="m11.909414 2.4642073a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312527 1.2836218 1.231838 0 0 0 1.283614-1.2312527 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m2.4962504 7.6963851 10.1811806-3.7166314" fill="none" stroke="#61b2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="1.898304" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.338983" cy="5.491526" rx="1.267586" ry="1.199789"/><path d="m1.6910776 6.7273a1.2675855 1.1997888 0 0 0 -1.26757808 1.1992188 1.2675855 1.1997888 0 0 0 1.26757808 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765618-.8007812.84677333.80148375 0 0 1 .84765618-.8007812z"/><path d="m13.40948 2.2963899a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312526 1.2836218 1.231838 0 0 0 1.283614-1.2312526 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.8221719.85748593.82289328 0 0 1 -.858379-.8221719.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
diff --git a/editor/icons/BezierHandlesFree.svg b/editor/icons/BezierHandlesFree.svg
index 6e91288c79..c7bff530ae 100644
--- a/editor/icons/BezierHandlesFree.svg
+++ b/editor/icons/BezierHandlesFree.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.6850253 4.7560401-3.776127.6607599" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.695505 2.3941651-2.999121 2.2935078" fill="none" stroke="#5fb2ff" stroke-width=".730798"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m2.4961199 4.3976698a1.1997888 1.2675855 80.074672 0 0 -1.0419038 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.4553094.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.9729958-.6426902.80148375.84677333 80.074672 0 1 .6969432-.934902z"/><path d="m11.838896.64428913a1.231838 1.2836218 52.593897 0 0 -.271701 1.75779027 1.231838 1.2836218 52.593897 0 0 1.767576.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779027 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.3444462a.82289328.85748593 52.593897 0 1 1.181294.13165847.82289328.85748593 52.593897 0 1 -.182417 1.1745241.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.17452347z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.3064631-5.1979735 6.5945988-6.486109c5.0847463.9491522 5.9477733 6.486108 5.9477733 6.486108" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m2.3554991 8.5165019 6.0018116-1.3754919 2.0717113-4.6377276" fill="none" stroke="#61b3ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="1.898304" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.35731" cy="7.14101" rx="1.267586" ry="1.199789"/><path d="m1.3048251 7.4400522a1.1997888 1.2675855 80.074672 0 0 -1.04190379 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.45530939.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.97299579-.6426902.80148375.84677333 80.074672 0 1 .69694319-.934902z"/><path d="m10.024463.73592688a1.231838 1.2836218 52.593897 0 0 -.2717015 1.75779042 1.231838 1.2836218 52.593897 0 0 1.7675765.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779042 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.34444622a.82289328.85748593 52.593897 0 1 1.181294.1316585.82289328.85748593 52.593897 0 1 -.182417 1.1745242.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.1745236z"/></g></svg>
diff --git a/editor/icons/BezierHandlesLinear.svg b/editor/icons/BezierHandlesLinear.svg
new file mode 100644
index 0000000000..2667779dcb
--- /dev/null
+++ b/editor/icons/BezierHandlesLinear.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.2711868 4.7796612-6.3728828 8.7118648z" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m14.237288 13.491526-5.9661012-8.7118648" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m5.6316733 8.3879317 2.6395135-3.6082705 2.4416832 3.5654122" fill="none" stroke="#61b2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m5.0847454 7.9363749a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992183 1.2675855 1.1997888 0 0 0 1.2675781-1.1992183 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m11.254237 7.9043407a1.2836218 1.231838 0 0 0 -1.2836135 1.2312528 1.2836218 1.231838 0 0 0 1.2836135 1.2312525 1.2836218 1.231838 0 0 0 1.283614-1.2312525 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
diff --git a/editor/icons/BezierHandlesMirror.svg b/editor/icons/BezierHandlesMirror.svg
index 9180e31921..07817f7247 100644
--- a/editor/icons/BezierHandlesMirror.svg
+++ b/editor/icons/BezierHandlesMirror.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.2033896 4.6779662h-3.8335021" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.931789 4.6440679h-3.7283994" fill="none" stroke="#5fb2ff" stroke-width=".716709"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m3.1539157 3.4305762a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m13.093969 3.3750567a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.3389831 5.4915255-5.8519685.0395137" fill="none" stroke="#5fb2ff" stroke-width="1.5"/><path d="m13.814033 5.4419288-5.4750499.0156984" fill="none" stroke="#5fb2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="8.40678" cy="5.593221" rx="1.267586" ry="1.199789"/><path d="m1.6400247 4.2441355a1.2675855 1.1997888 0 0 0 -1.26757814 1.1992188 1.2675855 1.1997888 0 0 0 1.26757814 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765624-.8007812.84677333.80148375 0 0 1 .84765624-.8007812z"/><path d="m14.659116 4.188616a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg>
diff --git a/editor/icons/BoxContainer.svg b/editor/icons/BoxContainer.svg
new file mode 100644
index 0000000000..03b918d9cf
--- /dev/null
+++ b/editor/icons/BoxContainer.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.4520481 6.9086748c-.60273897.602739-.60272261 1.5799281 0 2.1826507l5.4566267 5.4566265c.602739.602739 1.5799281.602723 2.1826507 0l5.4566265-5.4566265c.602739-.602739.602723-1.5799281 0-2.1826507l-5.4566265-5.4566265c-.602739-.60273904-1.5799281-.60272304-2.1826507 0zm1.0913253 1.0913253 1.0913254-1.0913253 5.4566267 5.4566262-1.0913253 1.091326zm2.1826507-2.1826498 1.0913254-1.091326 5.4566265 5.4566267-1.091326 1.091325zm2.1826507-2.182651 1.0913254-1.091325 5.4566258 5.4566258-1.091325 1.0913254z" fill="#8eef97" stroke-width=".771684"/></svg>
diff --git a/editor/icons/CameraEffects.svg b/editor/icons/CameraAttributes.svg
index 1ee7e15c87..1ee7e15c87 100644
--- a/editor/icons/CameraEffects.svg
+++ b/editor/icons/CameraAttributes.svg
diff --git a/editor/icons/ContainerLayout.svg b/editor/icons/ContainerLayout.svg
new file mode 100644
index 0000000000..feabc2c350
--- /dev/null
+++ b/editor/icons/ContainerLayout.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m3 1c-1.105 0-2 .895-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.105-.895-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4c0 1.105.895 2 2 2v-2zm4 0v2h2v-2zm4 0v2h2v-2zm4 0v2c1.105 0 2-.895 2-2z" fill="#8eef97"/><path d="m7 7h4v4h-4z" fill="#d6d6d6"/></g></svg>
diff --git a/editor/icons/ControlLayout.svg b/editor/icons/ControlLayout.svg
index 11dd2554be..8503e3313c 100644
--- a/editor/icons/ControlLayout.svg
+++ b/editor/icons/ControlLayout.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h3v3h-3zm5 0h5v3h-5zm-5 5h3v5h-3zm5 0h5v5h-5z" fill="#8eef97"/></svg>
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m11.793 8v-2h-3.793v-2.113h-2v2.113h-2.142v2h2.142v3.967h2v-3.967z" fill="#d6d6d6"/><path d="m8 .345c-4.199 0-7.655 3.456-7.655 7.655s3.456 7.655 7.655 7.655 7.655-3.456 7.655-7.655-3.456-7.655-7.655-7.655zm0 1.999c3.103 0 5.656 2.553 5.656 5.656s-2.553 5.656-5.656 5.656-5.656-2.553-5.656-5.656 2.553-5.656 5.656-5.656z" fill="#8eef97"/></g></svg>
diff --git a/editor/icons/CurveIn.svg b/editor/icons/CurveIn.svg
index 2ad44dc654..fefad9ce6c 100644
--- a/editor/icons/CurveIn.svg
+++ b/editor/icons/CurveIn.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 8-3 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 8-3 8-8" fill="none" stroke="#80ff45" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveInOut.svg b/editor/icons/CurveInOut.svg
index 292dac4573..f099cb83f1 100644
--- a/editor/icons/CurveInOut.svg
+++ b/editor/icons/CurveInOut.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-8 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-8 8-8" fill="none" stroke="#45d7ff" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveLinear.svg b/editor/icons/CurveLinear.svg
index 3c1fb2a0e2..41d37c9329 100644
--- a/editor/icons/CurveLinear.svg
+++ b/editor/icons/CurveLinear.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 8-8" fill="none" stroke="#ffe345" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveOut.svg b/editor/icons/CurveOut.svg
index dfa9a26144..19710aa38d 100644
--- a/editor/icons/CurveOut.svg
+++ b/editor/icons/CurveOut.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 3-8 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 3-8 8-8" fill="none" stroke="#45ffa2" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveOutIn.svg b/editor/icons/CurveOutIn.svg
index 9a6463d0e9..7f200432bf 100644
--- a/editor/icons/CurveOutIn.svg
+++ b/editor/icons/CurveOutIn.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 8-3 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 8-3 8-8" fill="none" stroke="#ff4596" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/DefaultProjectIcon.svg b/editor/icons/DefaultProjectIcon.svg
index f81ba4d390..adc26df6c2 100644
--- a/editor/icons/DefaultProjectIcon.svg
+++ b/editor/icons/DefaultProjectIcon.svg
@@ -1 +1 @@
-<svg height="64" viewBox="0 0 64 64" width="64" xmlns="http://www.w3.org/2000/svg"><g stroke-linejoin="round"><path d="m8 0c-4.432 0-8 3.568-8 8v48c0 4.432 3.568 8 8 8h48c4.432 0 8-3.568 8-8v-48c0-4.432-3.568-8-8-8z" fill="#355570" stroke-linecap="round" stroke-width="2"/><path d="m8 0c-4.432 0-8 3.568-8 8v48c0 4.432 3.568 8 8 8h48c4.432 0 8-3.568 8-8v-48c0-4.432-3.568-8-8-8zm0 2h48c3.324 0 6 2.676 6 6v48c0 3.324-2.676 6-6 6h-48c-3.324 0-6-2.676-6-6v-48c0-3.324 2.676-6 6-6z" fill-opacity=".19608" stroke-linecap="round" stroke-width="2"/><path d="m27.254 10c-2.1314.47383-4.2401 1.134-6.2168 2.1289.04521 1.7455.15796 3.4164.38672 5.1152-.76768.4919-1.574.91443-2.291 1.4902-.72854.5604-1.4731 1.0965-2.1328 1.752-1.3179-.8716-2.7115-1.691-4.1484-2.4141-1.549 1.667-2.9985 3.4672-4.1816 5.4805.89011 1.4399 1.8209 2.7894 2.8242 4.0703h.027343v9.9453 1.2617 1.1504l-.009765 1.6309h-.001953c.0031.7321.011718 1.5356.011718 1.6953 0 7.1942 9.1264 10.652 20.465 10.691h.013672.013672c11.338-.04 20.461-3.4972 20.461-10.691 0-.1626.010282-.96271.013672-1.6953h-.001953l-.011719-1.6309v-.98633l.003907-.001953v-11.369h.027343c1.0035-1.2809 1.9337-2.6304 2.8242-4.0703-1.1827-2.0133-2.6327-3.8135-4.1816-5.4805-1.4366.7231-2.8325 1.5425-4.1504 2.4141-.65947-.6555-1.4013-1.1916-2.1309-1.752-.71682-.5758-1.5248-.99833-2.291-1.4902.22813-1.6988.3413-3.3697.38672-5.1152-1.977-.99494-4.0863-1.6551-6.2188-2.1289-.85139 1.4309-1.6285 2.9812-2.3066 4.4961-.80409-.1344-1.613-.18571-2.4219-.19531h-.015625-.015625c-.81037.01-1.6176.060513-2.4219.19531-.67768-1.5149-1.4559-3.0652-2.3086-4.4961z" fill="#fff" stroke="#fff" stroke-width="3"/></g><g stroke-width=".32031" transform="matrix(.050279 0 0 .050279 6.2574 1.18)"><path d="m0 0s-.325 1.994-.515 1.976l-36.182-3.491c-2.879-.278-5.115-2.574-5.317-5.459l-.994-14.247-27.992-1.997-1.904 12.912c-.424 2.872-2.932 5.037-5.835 5.037h-38.188c-2.902 0-5.41-2.165-5.834-5.037l-1.905-12.912-27.992 1.997-.994 14.247c-.202 2.886-2.438 5.182-5.317 5.46l-36.2 3.49c-.187.018-.324-1.978-.511-1.978l-.049-7.83 30.658-4.944 1.004-14.374c.203-2.91 2.551-5.263 5.463-5.472l38.551-2.75c.146-.01.29-.016.434-.016 2.897 0 5.401 2.166 5.825 5.038l1.959 13.286h28.005l1.959-13.286c.423-2.871 2.93-5.037 5.831-5.037.142 0 .284.005.423.015l38.556 2.75c2.911.209 5.26 2.562 5.463 5.472l1.003 14.374 30.645 4.966z" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 919.24 771.67)"/><path d="m0 0v-59.041c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325h.134c4.795 6.12 9.232 12.569 13.487 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.253-6.88 8.693-13.329 13.487-19.449z" fill="#478cbf" transform="matrix(4.1626 0 0 -4.1626 104.7 525.91)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.133c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.1626 0 0 -4.1626 784.07 817.24)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 389.21 625.67)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.1626 0 0 -4.1626 367.37 631.06)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 511.99 724.74)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 634.79 625.67)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.1626 0 0 -4.1626 656.64 631.06)"/></g></svg>
+<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><g transform="translate(32 32)"><path d="m-16-32c-8.86 0-16 7.13-16 15.99v95.98c0 8.86 7.13 15.99 16 15.99h96c8.86 0 16-7.13 16-15.99v-95.98c0-8.85-7.14-15.99-16-15.99z" fill="#363d52"/><path d="m-16-32c-8.86 0-16 7.13-16 15.99v95.98c0 8.86 7.13 15.99 16 15.99h96c8.86 0 16-7.13 16-15.99v-95.98c0-8.85-7.14-15.99-16-15.99zm0 4h96c6.64 0 12 5.35 12 11.99v95.98c0 6.64-5.35 11.99-12 11.99h-96c-6.64 0-12-5.35-12-11.99v-95.98c0-6.64 5.36-11.99 12-11.99z" fill-opacity=".4"/></g><g stroke-width="9.92746" transform="matrix(.10073078 0 0 .10073078 12.425923 2.256365)"><path d="m0 0s-.325 1.994-.515 1.976l-36.182-3.491c-2.879-.278-5.115-2.574-5.317-5.459l-.994-14.247-27.992-1.997-1.904 12.912c-.424 2.872-2.932 5.037-5.835 5.037h-38.188c-2.902 0-5.41-2.165-5.834-5.037l-1.905-12.912-27.992 1.997-.994 14.247c-.202 2.886-2.438 5.182-5.317 5.46l-36.2 3.49c-.187.018-.324-1.978-.511-1.978l-.049-7.83 30.658-4.944 1.004-14.374c.203-2.91 2.551-5.263 5.463-5.472l38.551-2.75c.146-.01.29-.016.434-.016 2.897 0 5.401 2.166 5.825 5.038l1.959 13.286h28.005l1.959-13.286c.423-2.871 2.93-5.037 5.831-5.037.142 0 .284.005.423.015l38.556 2.75c2.911.209 5.26 2.562 5.463 5.472l1.003 14.374 30.645 4.966z" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 919.24059 771.67186)"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164715 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426579-6.973692 9.2079702-13.9828876 13.621-19.449z" fill="#478cbf" transform="matrix(4.162611 0 0 -4.162611 104.69892 525.90697)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.162611 0 0 -4.162611 784.07144 817.24284)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 389.21484 625.67104)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.162611 0 0 -4.162611 367.36686 631.05679)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 511.99336 724.73954)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 634.78706 625.67104)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.162611 0 0 -4.162611 656.64056 631.05679)"/></g></svg>
diff --git a/editor/icons/FlowContainer.svg b/editor/icons/FlowContainer.svg
new file mode 100644
index 0000000000..57699ce874
--- /dev/null
+++ b/editor/icons/FlowContainer.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m1.4491431 6.9081906c-.59885747.5988575-.59885747 1.5847615 0 2.1836189l5.4590474 5.4590465c.5988576.598858 1.5847616.598858 2.183619.000001l5.4590465-5.4590475c.598858-.5988574.598858-1.5847614.000001-2.183619l-5.4590475-5.4590474c-.5988574-.59885747-1.5847614-.59885747-2.183619 0zm1.0918095 1.0918091 5.4590471-5.4590471 5.4590473 5.4590471-5.4590473 5.4590473zm1.6377142-.5459043c-.3024312.3024312-.3024312.7893781 0 1.0918092.3024313.3024311.7893783.3024311 1.0918095 0l1.0918095-1.0918093c.3024312-.3024312.3024312-.7893782 0-1.0918094-.3024312-.3024313-.7893782-.3024313-1.0918095 0zm2.7273401-2.7273401c-.3024312.3024311-.3024312.7893782 0 1.0918094.3024313.3024313.7893783.3024313 1.0918095 0l.5480882-.5480884c.3024311-.3024311.3024319-.7893783 0-1.0918094-.3024311-.3024313-.789378-.3024313-1.0918093 0zm-1.0896258 4.3650542c-.3024313.3024311-.3024313.7893779 0 1.0918095.3024312.302431.7893781.302431 1.0918094 0 .3024312-.3024316.3024313-.7893784 0-1.0918095-.3024311-.3024311-.7893781-.3024311-1.0918094 0zm1.6377142-1.6377142c-.3024313.3024313-.3024313.7893782 0 1.0918093s.7893782.3024311 1.0918093 0l1.6377144-1.637714c.302431-.3024312.302431-.7893783 0-1.0918096-.3024316-.3024312-.7893784-.3024311-1.0918095.0000002zm-.00218 3.2776127c-.3024312.302431-.3024313.789377-.0000001 1.091809.3024312.302431.7893782.302431 1.0918093 0l2.1858035-2.1858026c.302431-.3024311.302431-.7893787 0-1.0918098s-.7893792-.3024311-1.0918103 0z" fill="#8eef97" fill-rule="nonzero" stroke-width=".772026"/></svg>
diff --git a/editor/icons/InterpCubicAngle.svg b/editor/icons/InterpCubicAngle.svg
new file mode 100644
index 0000000000..e302d556dc
--- /dev/null
+++ b/editor/icons/InterpCubicAngle.svg
@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#5fff95" stroke-linecap="round"><path d="m2 6c5 0 3-4 6-4s1 4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5" stroke-linejoin="round"/></g></svg>
diff --git a/editor/icons/InterpLinearAngle.svg b/editor/icons/InterpLinearAngle.svg
new file mode 100644
index 0000000000..af4e87a6cb
--- /dev/null
+++ b/editor/icons/InterpLinearAngle.svg
@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fd995f" stroke-linecap="round" stroke-linejoin="round"><path d="m2 6 6-4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5"/></g></svg>
diff --git a/editor/icons/Position2D.svg b/editor/icons/Marker2D.svg
index 191f0b2a03..191f0b2a03 100644
--- a/editor/icons/Position2D.svg
+++ b/editor/icons/Marker2D.svg
diff --git a/editor/icons/Position3D.svg b/editor/icons/Marker3D.svg
index 894b195589..894b195589 100644
--- a/editor/icons/Position3D.svg
+++ b/editor/icons/Marker3D.svg
diff --git a/editor/icons/MemberAnnotation.svg b/editor/icons/MemberAnnotation.svg
new file mode 100644
index 0000000000..c73ebf7b9b
--- /dev/null
+++ b/editor/icons/MemberAnnotation.svg
@@ -0,0 +1 @@
+<svg width="16" height="16" version="1.0" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><script id="custom-useragent-string-page-script"/><path d="m13.821 12.756c-5.0033 3.9148-12.551 2.248-12.49-4.538 0.67424-11.471 17.312-7.4502 12.446 2.1173-1.0549 1.1955-2.0737 1.4617-3.1983 0.4329-0.21023-0.19282-0.44783-1.1594-0.3819-1.5089 0.35827-1.8946 1.0885-4.0778-0.72151-4.7234-2.4171-0.86457-4.5592 1.6495-4.9697 4.0193-0.47396 2.7343 2.284 3.3749 4.1487 1.9879 0.4553-0.36324 1.6433-1.3796 1.6806-1.9742" fill="none" stroke="#e0e0e0" stroke-linejoin="round" stroke-width="1.4928"/></svg>
diff --git a/editor/icons/MenuBar.svg b/editor/icons/MenuBar.svg
new file mode 100644
index 0000000000..0a53f07f85
--- /dev/null
+++ b/editor/icons/MenuBar.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 6a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V7a1 1 0 0 0-1-1Zm1 2h10v2H3Zm0 3h10v2H3ZM1 1v4h6V1Zm1 1h4L4 4Z" fill="#8eef97"/></svg>
diff --git a/editor/icons/NavigationLink2D.svg b/editor/icons/NavigationLink2D.svg
new file mode 100644
index 0000000000..6c5f17e256
--- /dev/null
+++ b/editor/icons/NavigationLink2D.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#8ea6f4" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/>
+<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#8ea6f4" fill-opacity=".99608"/>
+</svg>
diff --git a/editor/icons/NavigationLink3D.svg b/editor/icons/NavigationLink3D.svg
new file mode 100644
index 0000000000..ea4092c2c7
--- /dev/null
+++ b/editor/icons/NavigationLink3D.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#fc7e7e" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/>
+<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#fc7d7d" fill-opacity=".99608"/>
+</svg>
diff --git a/editor/icons/NodeInfo.svg b/editor/icons/NodeInfo.svg
new file mode 100644
index 0000000000..4e3f0c42d0
--- /dev/null
+++ b/editor/icons/NodeInfo.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1 3h2v2h-2zm0 3h2v5h-2z" fill="#fff"/></svg>
diff --git a/editor/icons/ParticlesMaterial.svg b/editor/icons/ParticleProcessMaterial.svg
index 33598980a5..33598980a5 100644
--- a/editor/icons/ParticlesMaterial.svg
+++ b/editor/icons/ParticleProcessMaterial.svg
diff --git a/editor/icons/RigidDynamicBody2D.svg b/editor/icons/RigidBody2D.svg
index 5d08e991ae..5d08e991ae 100644
--- a/editor/icons/RigidDynamicBody2D.svg
+++ b/editor/icons/RigidBody2D.svg
diff --git a/editor/icons/RigidDynamicBody3D.svg b/editor/icons/RigidBody3D.svg
index 7f5db4ce88..7f5db4ce88 100644
--- a/editor/icons/RigidDynamicBody3D.svg
+++ b/editor/icons/RigidBody3D.svg
diff --git a/editor/icons/SceneUniqueName.svg b/editor/icons/SceneUniqueName.svg
index 34279a14a6..c8aca7b3e6 100644
--- a/editor/icons/SceneUniqueName.svg
+++ b/editor/icons/SceneUniqueName.svg
@@ -1 +1,2 @@
-<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.378 2.224q1.235 0 2.084.866.865.85.865 2.083 0 1.17-.881 2.036-.866.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.068t.866-2.051q.865-.866 2.083-.866zm.962 1.988q-.4-.4-.962-.4-.56 0-.961.4-.401.384-.401.93 0 .56.4.961.401.385.962.385.561 0 .962-.385.4-.4.4-.946 0-.56-.4-.945zm5.45-2.116h1.218L5.677 13.78H4.442Zm1.17 5.722q1.234 0 2.083.866.866.849.866 2.1 0 1.17-.882 2.035-.865.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.084 0-1.202.866-2.051.865-.866 2.083-.866zm.961 1.987q-.4-.4-.962-.4-.56 0-.961.4-.4.385-.4.946 0 .561.4.962.4.384.961.384.561 0 .962-.384.4-.4.4-.946 0-.56-.4-.962z" aria-label="%" style="font-weight:600;font-size:16.0277px;font-family:FreeSans;-inkscape-font-specification:'FreeSans Semi-Bold';letter-spacing:0;word-spacing:0;fill:#e0e0e0;fill-opacity:.996078;stroke-width:.400692"/></svg>
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.378 2.224q1.235 0 2.084.866.865.85.865 2.083 0 1.17-.881 2.036-.866.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.068t.866-2.051q.865-.866 2.083-.866zm.962 1.988q-.4-.4-.962-.4-.56 0-.961.4-.401.384-.401.93 0 .56.4.961.401.385.962.385.561 0 .962-.385.4-.4.4-.946 0-.56-.4-.945zm5.45-2.116h1.218l-6.331 11.684h-1.235zm1.17 5.722q1.234 0 2.083.866.866.849.866 2.1 0 1.17-.882 2.035-.865.85-2.068.85-1.218 0-2.083-.85-.866-.866-.866-2.084 0-1.202.866-2.051.865-.866 2.083-.866zm.961 1.987q-.4-.4-.962-.4-.56 0-.961.4-.4.385-.4.946 0 .561.4.962.4.384.961.384.561 0 .962-.384.4-.4.4-.946 0-.56-.4-.962z" fill="#e0e0e0" stroke-width=".400692"/></svg>
+
diff --git a/editor/icons/SoftDynamicBody3D.svg b/editor/icons/SoftBody3D.svg
index 7bc9a22c22..7bc9a22c22 100644
--- a/editor/icons/SoftDynamicBody3D.svg
+++ b/editor/icons/SoftBody3D.svg
diff --git a/editor/icons/SplitContainer.svg b/editor/icons/SplitContainer.svg
new file mode 100644
index 0000000000..bb03350166
--- /dev/null
+++ b/editor/icons/SplitContainer.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.452048 6.9086746c-.60273888.6027391-.60272252 1.5799284 0 2.1826511l5.4566266 5.4566263c.6027391.602739 1.5799284.602722 2.1826511 0l5.4566263-5.4566263c.602739-.6027397.602722-1.5799284 0-2.1826511l-5.4566263-5.4566266c-.6027397-.60273888-1.5799284-.60272252-2.1826511 0zm1.0913254 1.0913254 2.1826506-2.1826506 1.636988 1.6369879v2.1826504h2.1826508l1.6369882 1.6369883-2.182651 2.182651zm3.273976-3.273976 2.1826506-2.1826506 5.456627 5.4566266-2.182651 2.182651-1.6369883-1.6369882v-2.1826508h-2.1826504z" fill="#8eef97" stroke-width=".771683"/></svg>
diff --git a/editor/icons/VcsBranches.svg b/editor/icons/VcsBranches.svg
new file mode 100644
index 0000000000..e79019590f
--- /dev/null
+++ b/editor/icons/VcsBranches.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="nonzero"><path d="m3.755 1.396c-1.599 0-2.914 1.315-2.914 2.913 0 1.599 1.315 2.914 2.914 2.914 1.598 0 2.913-1.315 2.913-2.914 0-1.598-1.315-2.913-2.913-2.913zm0 1.462c.796 0 1.451.655 1.451 1.451 0 .797-.655 1.452-1.451 1.452-.797 0-1.452-.655-1.452-1.452 0-.796.655-1.451 1.452-1.451z"/><path d="m12.073 8.956c-1.599 0-2.914 1.316-2.914 2.914s1.315 2.914 2.914 2.914c1.598 0 2.914-1.316 2.914-2.914s-1.316-2.914-2.914-2.914zm0 1.463c.796 0 1.451.655 1.451 1.451s-.655 1.451-1.451 1.451-1.451-.655-1.451-1.451.655-1.451 1.451-1.451z"/><path d="m12.073 1.396c-1.599 0-2.914 1.315-2.914 2.913 0 1.599 1.315 2.914 2.914 2.914 1.598 0 2.914-1.315 2.914-2.914 0-1.598-1.316-2.913-2.914-2.913zm0 1.462c.796 0 1.451.655 1.451 1.451 0 .797-.655 1.452-1.451 1.452s-1.451-.655-1.451-1.452c0-.796.655-1.451 1.451-1.451z"/></g><path d="m9.159 11.87h-2.491l-2.913-2.914v-1.733" fill="none" stroke="#e0e0e0" stroke-width="1.5"/><path d="m9.159 4.309h-2.491" fill="none" stroke="#e0e0e0" stroke-width="1.5"/></svg>
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index f3709efab6..e3da82a5cb 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -57,13 +57,13 @@ void AudioStreamImportSettings::_notification(int p_what) {
zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
- _indicator->update();
- _preview->update();
+ _indicator->queue_redraw();
+ _preview->queue_redraw();
} break;
case NOTIFICATION_PROCESS: {
_current = _player->get_playback_position();
- _indicator->update();
+ _indicator->queue_redraw();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -167,7 +167,7 @@ void AudioStreamImportSettings::_draw_preview() {
void AudioStreamImportSettings::_preview_changed(ObjectID p_which) {
if (stream.is_valid() && stream->get_instance_id() == p_which) {
- _preview->update();
+ _preview->queue_redraw();
}
}
@@ -179,8 +179,8 @@ void AudioStreamImportSettings::_preview_zoom_in() {
zoom_bar->set_page(page_size * 0.5);
zoom_bar->set_value(zoom_bar->get_value() + page_size * 0.25);
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_preview_zoom_out() {
@@ -191,8 +191,8 @@ void AudioStreamImportSettings::_preview_zoom_out() {
zoom_bar->set_page(MIN(zoom_bar->get_max(), page_size * 2.0));
zoom_bar->set_value(zoom_bar->get_value() - page_size * 0.5);
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_preview_zoom_reset() {
@@ -202,22 +202,22 @@ void AudioStreamImportSettings::_preview_zoom_reset() {
zoom_bar->set_max(stream->get_length());
zoom_bar->set_page(zoom_bar->get_max());
zoom_bar->set_value(0);
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_preview_zoom_offset_changed(double) {
- _preview->update();
- _indicator->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_audio_changed() {
if (!is_visible()) {
return;
}
- _preview->update();
- _indicator->update();
- color_rect->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
+ color_rect->queue_redraw();
}
void AudioStreamImportSettings::_play() {
@@ -238,7 +238,7 @@ void AudioStreamImportSettings::_stop() {
_player->stop();
_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
_current = 0;
- _indicator->update();
+ _indicator->queue_redraw();
set_process(false);
}
@@ -246,7 +246,7 @@ void AudioStreamImportSettings::_on_finished() {
_play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
if (!_pausing) {
_current = 0;
- _indicator->update();
+ _indicator->queue_redraw();
} else {
_pausing = false;
}
@@ -310,7 +310,7 @@ void AudioStreamImportSettings::_draw_indicator() {
void AudioStreamImportSettings::_on_indicator_mouse_exited() {
_hovering_beat = -1;
- _indicator->update();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::_on_input_indicator(Ref<InputEvent> p_event) {
@@ -353,11 +353,11 @@ void AudioStreamImportSettings::_on_input_indicator(Ref<InputEvent> p_event) {
int new_hovering_beat = _get_beat_at_pos(mm->get_position().x);
if (new_hovering_beat != _hovering_beat) {
_hovering_beat = new_hovering_beat;
- _indicator->update();
+ _indicator->queue_redraw();
}
} else if (_hovering_beat != -1) {
_hovering_beat = -1;
- _indicator->update();
+ _indicator->queue_redraw();
}
}
}
@@ -391,7 +391,7 @@ void AudioStreamImportSettings::_seek_to(real_t p_x) {
_current = zoom_bar->get_value() + p_x / _preview->get_rect().size.x * zoom_bar->get_page();
_current = CLAMP(_current, 0, stream->get_length());
_player->seek(_current);
- _indicator->update();
+ _indicator->queue_redraw();
}
void AudioStreamImportSettings::edit(const String &p_path, const String &p_importer, const Ref<AudioStream> &p_stream) {
@@ -410,9 +410,9 @@ void AudioStreamImportSettings::edit(const String &p_path, const String &p_impor
if (!stream.is_null()) {
stream->connect("changed", callable_mp(this, &AudioStreamImportSettings::_audio_changed));
- _preview->update();
- _indicator->update();
- color_rect->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
+ color_rect->queue_redraw();
} else {
hide();
}
@@ -500,9 +500,9 @@ void AudioStreamImportSettings::_settings_changed() {
updating_settings = false;
- _preview->update();
- _indicator->update();
- color_rect->update();
+ _preview->queue_redraw();
+ _indicator->queue_redraw();
+ color_rect->queue_redraw();
}
void AudioStreamImportSettings::_reimport() {
@@ -526,7 +526,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
loop_hb->add_theme_constant_override("separation", 4 * EDSCALE);
loop = memnew(CheckBox);
loop->set_text(TTR("Enable"));
- loop->set_tooltip(TTR("Enable looping."));
+ loop->set_tooltip_text(TTR("Enable looping."));
loop->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
loop_hb->add_child(loop);
loop_hb->add_spacer();
@@ -535,7 +535,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
loop_offset->set_max(10000);
loop_offset->set_step(0.001);
loop_offset->set_suffix("sec");
- loop_offset->set_tooltip(TTR("Loop offset (from beginning). Note that if BPM is set, this setting will be ignored."));
+ loop_offset->set_tooltip_text(TTR("Loop offset (from beginning). Note that if BPM is set, this setting will be ignored."));
loop_offset->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
loop_hb->add_child(loop_offset);
main_vbox->add_margin_child(TTR("Loop:"), loop_hb);
@@ -549,14 +549,14 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
bpm_edit = memnew(SpinBox);
bpm_edit->set_max(400);
bpm_edit->set_step(0.01);
- bpm_edit->set_tooltip(TTR("Configure the Beats Per Measure (tempo) used for the interactive streams.\nThis is required in order to configure beat information."));
+ bpm_edit->set_tooltip_text(TTR("Configure the Beats Per Measure (tempo) used for the interactive streams.\nThis is required in order to configure beat information."));
bpm_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(bpm_edit);
interactive_hb->add_spacer();
bar_beats_label = memnew(Label(TTR("Beats/Bar:")));
interactive_hb->add_child(bar_beats_label);
bar_beats_edit = memnew(SpinBox);
- bar_beats_edit->set_tooltip(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams."));
+ bar_beats_edit->set_tooltip_text(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams."));
bar_beats_edit->set_min(2);
bar_beats_edit->set_max(32);
bar_beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
@@ -567,7 +567,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
beats_enabled->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(beats_enabled);
beats_edit = memnew(SpinBox);
- beats_edit->set_tooltip(TTR("Configure the amount of Beats used for music-aware looping. If zero, it will be autodetected from the length.\nIt is recommended to set this value (either manually or by clicking on a beat number in the preview) to ensure looping works properly."));
+ beats_edit->set_tooltip_text(TTR("Configure the amount of Beats used for music-aware looping. If zero, it will be autodetected from the length.\nIt is recommended to set this value (either manually or by clicking on a beat number in the preview) to ensure looping works properly."));
beats_edit->set_max(99999);
beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(beats_edit);
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index f4d19fe8b6..5d8e453395 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -131,7 +131,7 @@ Transform3D Collada::Node::compute_transform(const Collada &state) const {
switch (xf.op) {
case XForm::OP_ROTATE: {
if (xf.data.size() >= 4) {
- xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg2rad(xf.data[3]));
+ xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg_to_rad(xf.data[3]));
}
} break;
case XForm::OP_SCALE: {
@@ -289,7 +289,7 @@ void Collada::_parse_image(XMLParser &parser) {
String path = parser.get_attribute_value("source").strip_edges();
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.uri_decode()));
+ image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode()));
}
} else {
while (parser.read() == OK) {
@@ -302,7 +302,7 @@ void Collada::_parse_image(XMLParser &parser) {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path));
} else if (path.find("file:///") == 0) {
path = path.replace_first("file:///", "");
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index 043681aa87..d1f37179f3 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -449,8 +449,8 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper
// Update font preview.
if (font_preview.is_valid()) {
- if (p_edited_property == "antialiased") {
- font_preview->set_antialiased(import_settings_data->get("antialiased"));
+ if (p_edited_property == "antialiasing") {
+ font_preview->set_antialiasing((TextServer::FontAntialiasing)import_settings_data->get("antialiasing").operator int());
} else if (p_edited_property == "generate_mipmaps") {
font_preview->set_generate_mipmaps(import_settings_data->get("generate_mipmaps"));
} else if (p_edited_property == "multichannel_signed_distance_field") {
@@ -474,7 +474,7 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper
font_preview_label->add_theme_font_override("font", font_preview);
font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE);
- font_preview_label->update();
+ font_preview_label->queue_redraw();
}
/*************************************************************************/
@@ -574,6 +574,12 @@ void DynamicFontImportSettings::_variations_validate() {
}
}
}
+ if ((TextServer::FontAntialiasing)(int)import_settings_data->get("antialiasing") == TextServer::FONT_ANTIALIASING_LCD) {
+ warn += "\n" + TTR("Note: LCD sub-pixel anti-aliasing is selected, each of the glyphs will be pre-rendered for all supported sub-pixel layouts (5x).");
+ }
+ if ((TextServer::SubpixelPositioning)(int)import_settings_data->get("subpixel_positioning") != TextServer::SUBPIXEL_POSITIONING_DISABLED) {
+ warn += "\n" + TTR("Note: Sub-pixel positioning is selected, each of the glyphs might be pre-rendered for multiple sub-pixel offsets (up to 4x).");
+ }
if (warn.is_empty()) {
label_warn->set_text("");
label_warn->hide();
@@ -881,7 +887,7 @@ void DynamicFontImportSettings::_re_import() {
HashMap<StringName, Variant> main_settings;
main_settings["face_index"] = import_settings_data->get("face_index");
- main_settings["antialiased"] = import_settings_data->get("antialiased");
+ main_settings["antialiasing"] = import_settings_data->get("antialiasing");
main_settings["generate_mipmaps"] = import_settings_data->get("generate_mipmaps");
main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field");
main_settings["msdf_pixel_range"] = import_settings_data->get("msdf_pixel_range");
@@ -1079,7 +1085,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
import_settings_data->notify_property_list_changed();
if (font_preview.is_valid()) {
- font_preview->set_antialiased(import_settings_data->get("antialiased"));
+ font_preview->set_antialiasing((TextServer::FontAntialiasing)import_settings_data->get("antialiasing").operator int());
font_preview->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field"));
font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range"));
font_preview->set_msdf_size(import_settings_data->get("msdf_size"));
@@ -1090,7 +1096,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
}
font_preview_label->add_theme_font_override("font", font_preview);
font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE);
- font_preview_label->update();
+ font_preview_label->queue_redraw();
_variations_validate();
@@ -1108,7 +1114,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));
- options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
+ options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel"), 1));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8));
@@ -1233,7 +1239,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
add_var = memnew(Button);
page2_hb_vars->add_child(add_var);
- add_var->set_tooltip(TTR("Add configuration"));
+ add_var->set_tooltip_text(TTR("Add configuration"));
add_var->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
add_var->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_variation_add));
@@ -1337,8 +1343,8 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
for (int i = 0; i < 16; i++) {
glyph_table->set_column_title(i + 1, String::num_int64(i, 16));
}
- glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox(SNAME("bg")));
- glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox(SNAME("bg")));
+ glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox(SNAME("panel")));
+ glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox(SNAME("panel")));
glyph_table->add_theme_constant_override("h_separation", 0);
glyph_table->set_h_size_flags(Control::SIZE_EXPAND_FILL);
glyph_table->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index e822b4963a..5211f003c1 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -115,7 +115,7 @@ void EditorImportPlugin::get_import_options(const String &p_path, List<ResourceI
Array needed;
needed.push_back("name");
needed.push_back("default_value");
- Array options;
+ TypedArray<Dictionary> options;
if (GDVIRTUAL_CALL(_get_import_options, p_path, p_preset, options)) {
for (int i = 0; i < options.size(); i++) {
Dictionary d = options[i];
@@ -164,7 +164,7 @@ bool EditorImportPlugin::get_option_visibility(const String &p_path, const Strin
Error EditorImportPlugin::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
Dictionary options;
- Array platform_variants, gen_files;
+ TypedArray<String> platform_variants, gen_files;
HashMap<StringName, Variant>::ConstIterator E = p_options.begin();
while (E) {
diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h
index 4548513b6f..1468ed082b 100644
--- a/editor/import/editor_import_plugin.h
+++ b/editor/import/editor_import_plugin.h
@@ -32,6 +32,7 @@
#define EDITOR_IMPORT_PLUGIN_H
#include "core/io/resource_importer.h"
+#include "core/variant/typed_array.h"
class EditorImportPlugin : public ResourceImporter {
GDCLASS(EditorImportPlugin, ResourceImporter);
@@ -44,13 +45,13 @@ protected:
GDVIRTUAL0RC(int, _get_preset_count)
GDVIRTUAL1RC(String, _get_preset_name, int)
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
- GDVIRTUAL2RC(Array, _get_import_options, String, int)
+ GDVIRTUAL2RC(TypedArray<Dictionary>, _get_import_options, String, int)
GDVIRTUAL0RC(String, _get_save_extension)
GDVIRTUAL0RC(String, _get_resource_type)
GDVIRTUAL0RC(float, _get_priority)
GDVIRTUAL0RC(int, _get_import_order)
GDVIRTUAL3RC(bool, _get_option_visibility, String, StringName, Dictionary)
- GDVIRTUAL5RC(int, _import, String, String, Dictionary, Array, Array)
+ GDVIRTUAL5RC(int, _import, String, String, Dictionary, TypedArray<String>, TypedArray<String>)
public:
EditorImportPlugin();
diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp
index 69c0a047e4..72ccb832c7 100644
--- a/editor/import/post_import_plugin_skeleton_renamer.cpp
+++ b/editor/import/post_import_plugin_skeleton_renamer.cpp
@@ -143,7 +143,7 @@ void PostImportPluginSkeletonRenamer::internal_process(InternalImportCategory p_
// Make unique skeleton.
if (bool(p_options["retarget/bone_renamer/unique_node/make_unique"])) {
String unique_name = String(p_options["retarget/bone_renamer/unique_node/skeleton_name"]);
- ERR_FAIL_COND_MSG(unique_name == String(), "Skeleton unique name cannot be empty.");
+ ERR_FAIL_COND_MSG(unique_name.is_empty(), "Skeleton unique name cannot be empty.");
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
index 4f00bd120a..a5ef2e7f97 100644
--- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
+++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
@@ -38,16 +38,16 @@
void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) {
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true));
-
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable"), false));
- r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15));
-
// TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options).
// get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values.
// r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/filter", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::STRING_NAME, PROPERTY_HINT_ENUM, "Hips,Spine,Chest")), Array()));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/fix_silhouette/filter", PROPERTY_HINT_ARRAY_TYPE, "StringName"), Array()));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/base_height_adjustment", PROPERTY_HINT_RANGE, "-1,1,0.01"), 0.0));
}
}
@@ -67,6 +67,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
if (!src_skeleton) {
return;
}
+
bool is_renamed = bool(p_options["retarget/bone_renamer/rename_bones"]);
Array filter = p_options["retarget/rest_fixer/fix_silhouette/filter"];
bool is_rest_changed = false;
@@ -89,44 +90,134 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- // Set motion scale to Skeleton if normalize position tracks.
- if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) {
- int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone());
- if (src_bone_idx >= 0) {
- real_t motion_scale = abs(src_skeleton->get_bone_global_rest(src_bone_idx).origin.y);
- if (motion_scale > 0) {
- src_skeleton->set_motion_scale(motion_scale);
+ // Get global transform.
+ Transform3D global_transform;
+ if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
+ Node *pr = src_skeleton;
+ while (pr) {
+ Node3D *pr3d = Object::cast_to<Node3D>(pr);
+ if (pr3d) {
+ global_transform = pr3d->get_transform() * global_transform;
+ pr3d->set_transform(Transform3D());
}
+ pr = pr->get_parent();
}
+ global_transform.origin = Vector3(); // Translation by a Node is not a bone animation, so the retargeted model should be at the origin.
+ }
- TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ // Calc IBM difference.
+ LocalVector<Vector<Transform3D>> ibm_diffs;
+ {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
while (nodes.size()) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
- List<StringName> anims;
- ap->get_animation_list(&anims);
- for (const StringName &name : anims) {
- Ref<Animation> anim = ap->get_animation(name);
- int track_len = anim->get_track_count();
- for (int i = 0; i < track_len; i++) {
- if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
- continue;
- }
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
+ ERR_CONTINUE(!mi);
- if (anim->track_is_compressed(i)) {
- continue; // Shouldn't occur in internal_process().
- }
+ Ref<Skin> skin = mi->get_skin();
+ ERR_CONTINUE(!skin.is_valid());
+
+ Node *node = mi->get_node(mi->get_skeleton_path());
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!mesh_skeleton || mesh_skeleton != src_skeleton) {
+ continue;
+ }
+
+ Vector<Transform3D> ibm_diff;
+ ibm_diff.resize(src_skeleton->get_bone_count());
+ Transform3D *ibm_diff_w = ibm_diff.ptrw();
+
+ int skin_len = skin->get_bind_count();
+ for (int i = 0; i < skin_len; i++) {
+ StringName bn = skin->get_bind_name(i);
+ int bone_idx = src_skeleton->find_bone(bn);
+ if (bone_idx >= 0) {
+ ibm_diff_w[bone_idx] = global_transform * src_skeleton->get_bone_global_rest(bone_idx) * skin->get_bind_pose(i);
+ }
+ }
+
+ ibm_diffs.push_back(ibm_diff);
+ }
+ }
+
+ // Apply node transforms.
+ if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
+ Vector3 scl = global_transform.basis.get_scale_local();
+
+ Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
+ for (int i = 0; i < bones_to_process.size(); i++) {
+ src_skeleton->set_bone_rest(bones_to_process[i], global_transform.orthonormalized() * src_skeleton->get_bone_rest(bones_to_process[i]));
+ }
+
+ while (bones_to_process.size() > 0) {
+ int src_idx = bones_to_process[0];
+ bones_to_process.erase(src_idx);
+ Vector<int> src_children = src_skeleton->get_bone_children(src_idx);
+ for (int i = 0; i < src_children.size(); i++) {
+ bones_to_process.push_back(src_children[i]);
+ }
+ src_skeleton->set_bone_rest(src_idx, Transform3D(src_skeleton->get_bone_rest(src_idx).basis, src_skeleton->get_bone_rest(src_idx).origin * scl));
+ }
+
+ // Fix animation.
+ bones_to_process = src_skeleton->get_parentless_bones();
+ {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ while (nodes.size()) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ int track_len = anim->get_track_count();
+ for (int i = 0; i < track_len; i++) {
+ if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) {
+ continue;
+ }
+
+ if (anim->track_is_compressed(i)) {
+ continue; // Shouldn't occur in internal_process().
+ }
+
+ String track_path = String(anim->track_get_path(i).get_concatenated_names());
+ Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
+ ERR_CONTINUE(!node);
- String track_path = String(anim->track_get_path(i).get_concatenated_names());
- Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
- if (node) {
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (track_skeleton) {
- if (track_skeleton && track_skeleton == src_skeleton) {
- real_t mlt = 1 / src_skeleton->get_motion_scale();
- int key_len = anim->track_get_key_count(i);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_subname(0);
+ if (!bn) {
+ continue;
+ }
+
+ int bone_idx = src_skeleton->find_bone(bn);
+ int key_len = anim->track_get_key_count(i);
+ if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) {
+ if (bones_to_process.has(bone_idx)) {
+ for (int j = 0; j < key_len; j++) {
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin);
+ }
+ } else {
for (int j = 0; j < key_len; j++) {
- Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, pos * mlt);
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, ps * scl);
+ }
+ }
+ } else if (bones_to_process.has(bone_idx)) {
+ if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
+ for (int j = 0; j < key_len; j++) {
+ Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt);
+ }
+ } else {
+ for (int j = 0; j < key_len; j++) {
+ Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
+ anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale());
}
}
}
@@ -134,6 +225,8 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
}
+
+ is_rest_changed = true;
}
// Complement Rotation track for compatibility between different rests.
@@ -165,24 +258,26 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- if (found_skeleton) {
- // Search and insert rot track if it doesn't exist.
- for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) {
- String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx)));
- if (bone_name == String()) {
- continue;
- }
- int src_idx = src_skeleton->find_bone(bone_name);
- if (src_idx == -1) {
- continue;
- }
- String insert_path = track_path + ":" + bone_name;
- int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D);
- if (rot_track == -1) {
- int track = anim->add_track(Animation::TYPE_ROTATION_3D);
- anim->track_set_path(track, insert_path);
- anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
- }
+ if (!found_skeleton) {
+ continue;
+ }
+
+ // Search and insert rot track if it doesn't exist.
+ for (int prof_idx = 0; prof_idx < prof_skeleton->get_bone_count(); prof_idx++) {
+ String bone_name = is_renamed ? prof_skeleton->get_bone_name(prof_idx) : String(bone_map->get_skeleton_bone_name(prof_skeleton->get_bone_name(prof_idx)));
+ if (bone_name.is_empty()) {
+ continue;
+ }
+ int src_idx = src_skeleton->find_bone(bone_name);
+ if (src_idx == -1) {
+ continue;
+ }
+ String insert_path = track_path + ":" + bone_name;
+ int rot_track = anim->find_track(insert_path, Animation::TYPE_ROTATION_3D);
+ if (rot_track == -1) {
+ int track = anim->add_track(Animation::TYPE_ROTATION_3D);
+ anim->track_set_path(track, insert_path);
+ anim->rotation_track_insert_key(track, 0, src_skeleton->get_bone_rest(src_idx).basis.get_rotation_quaternion());
}
}
}
@@ -269,7 +364,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
Vector3 src_dir = src_tail - src_head;
// Rotate rest.
- if (Math::abs(Math::rad2deg(src_dir.angle_to(prof_dir))) > float(p_options["retarget/rest_fixer/fix_silhouette/threshold"])) {
+ if (Math::abs(Math::rad_to_deg(src_dir.angle_to(prof_dir))) > float(p_options["retarget/rest_fixer/fix_silhouette/threshold"])) {
// Get rotation difference.
Vector3 up_vec; // Need to rotate other than roll axis.
switch (Vector3(abs(src_dir.x), abs(src_dir.y), abs(src_dir.z)).min_axis_index()) {
@@ -303,6 +398,56 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
+ // Adjust scale base bone height.
+ float base_adjustment = float(p_options["retarget/rest_fixer/fix_silhouette/base_height_adjustment"]);
+ if (!Math::is_zero_approx(base_adjustment)) {
+ StringName scale_base_bone_name = profile->get_scale_base_bone();
+ int src_bone_idx = src_skeleton->find_bone(scale_base_bone_name);
+ Transform3D src_rest = src_skeleton->get_bone_rest(src_bone_idx);
+ src_skeleton->set_bone_rest(src_bone_idx, Transform3D(src_rest.basis, Vector3(src_rest.origin.x, src_rest.origin.y + base_adjustment, src_rest.origin.z)));
+
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ while (nodes.size()) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ int track_len = anim->get_track_count();
+ for (int i = 0; i < track_len; i++) {
+ if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
+ continue;
+ }
+
+ if (anim->track_is_compressed(i)) {
+ continue; // Shouldn't occur in internal_process().
+ }
+
+ String track_path = String(anim->track_get_path(i).get_concatenated_names());
+ Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_concatenated_subnames();
+ if (bn != scale_base_bone_name) {
+ continue;
+ }
+
+ int key_len = anim->track_get_key_count(i);
+ for (int j = 0; j < key_len; j++) {
+ Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ pos.y += base_adjustment;
+ anim->track_set_key_value(i, j, pos);
+ }
+ }
+ }
+ }
+ }
+
// For skin modification in overwrite rest.
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
silhouette_diff_w[i] = old_skeleton_global_rest[i] * src_skeleton->get_bone_global_rest(i).inverse();
@@ -311,6 +456,53 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
is_rest_changed = true;
}
+ // Set motion scale to Skeleton if normalize position tracks.
+ if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) {
+ int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone());
+ if (src_bone_idx >= 0) {
+ real_t motion_scale = abs(src_skeleton->get_bone_global_rest(src_bone_idx).origin.y);
+ if (motion_scale > 0) {
+ src_skeleton->set_motion_scale(motion_scale);
+ }
+ }
+
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ while (nodes.size()) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ int track_len = anim->get_track_count();
+ for (int i = 0; i < track_len; i++) {
+ if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
+ continue;
+ }
+
+ if (anim->track_is_compressed(i)) {
+ continue; // Shouldn't occur in internal_process().
+ }
+
+ String track_path = String(anim->track_get_path(i).get_concatenated_names());
+ Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ real_t mlt = 1 / src_skeleton->get_motion_scale();
+ int key_len = anim->track_get_key_count(i);
+ for (int j = 0; j < key_len; j++) {
+ Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, pos * mlt);
+ }
+ }
+ }
+ }
+ }
+
// Overwrite axis.
if (bool(p_options["retarget/rest_fixer/overwrite_axis"])) {
LocalVector<Transform3D> old_skeleton_rest;
@@ -367,37 +559,12 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
src_skeleton->set_bone_rest(src_idx, Transform3D(tgt_rot, diff.xform(src_skeleton->get_bone_rest(src_idx).origin)));
}
- // Fix skin.
- {
- TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
- while (nodes.size()) {
- ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
- Ref<Skin> skin = mi->get_skin();
- if (skin.is_valid()) {
- Node *node = mi->get_node(mi->get_skeleton_path());
- if (node) {
- Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
- if (mesh_skeleton && node == src_skeleton) {
- int skin_len = skin->get_bind_count();
- for (int i = 0; i < skin_len; i++) {
- StringName bn = skin->get_bind_name(i);
- int bone_idx = src_skeleton->find_bone(bn);
- if (bone_idx >= 0) {
- Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx);
- skin->set_bind_pose(i, new_rest.inverse());
- }
- }
- }
- }
- }
- }
- }
-
// Fix animation.
{
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ ERR_CONTINUE(!ap);
List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
@@ -414,53 +581,57 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
- if (node) {
- Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (track_skeleton && track_skeleton == src_skeleton) {
- StringName bn = anim->track_get_path(i).get_subname(0);
- if (bn) {
- int bone_idx = src_skeleton->find_bone(bn);
-
- Transform3D old_rest = old_skeleton_rest[bone_idx];
- Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
- Transform3D old_pg;
- Transform3D new_pg;
- int parent_idx = src_skeleton->get_bone_parent(bone_idx);
- if (parent_idx >= 0) {
- old_pg = old_skeleton_global_rest[parent_idx];
- new_pg = src_skeleton->get_bone_global_rest(parent_idx);
- }
-
- int key_len = anim->track_get_key_count(i);
- if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
- Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion();
- Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion();
- Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
- Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
- for (int j = 0; j < key_len; j++) {
- Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
- }
- } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
- Basis old_rest_b = old_rest.basis;
- Basis new_rest_b = new_rest.basis;
- Basis old_pg_b = old_pg.basis;
- Basis new_pg_b = new_pg.basis;
- for (int j = 0; j < key_len; j++) {
- Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
- anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
- }
- } else {
- Vector3 old_rest_o = old_rest.origin;
- Vector3 new_rest_o = new_rest.origin;
- Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
- Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
- for (int j = 0; j < key_len; j++) {
- Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
- }
- }
- }
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!track_skeleton || track_skeleton != src_skeleton) {
+ continue;
+ }
+
+ StringName bn = anim->track_get_path(i).get_subname(0);
+ if (!bn) {
+ continue;
+ }
+
+ int bone_idx = src_skeleton->find_bone(bn);
+
+ Transform3D old_rest = old_skeleton_rest[bone_idx];
+ Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
+ Transform3D old_pg;
+ Transform3D new_pg;
+ int parent_idx = src_skeleton->get_bone_parent(bone_idx);
+ if (parent_idx >= 0) {
+ old_pg = old_skeleton_global_rest[parent_idx];
+ new_pg = src_skeleton->get_bone_global_rest(parent_idx);
+ }
+
+ int key_len = anim->track_get_key_count(i);
+ if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
+ Quaternion old_rest_q = old_rest.basis.get_rotation_quaternion();
+ Quaternion new_rest_q = new_rest.basis.get_rotation_quaternion();
+ Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
+ Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
+ for (int j = 0; j < key_len; j++) {
+ Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, new_pg_q.inverse() * old_pg_q * qt * old_rest_q.inverse() * old_pg_q.inverse() * new_pg_q * new_rest_q);
+ }
+ } else if (anim->track_get_type(i) == Animation::TYPE_SCALE_3D) {
+ Basis old_rest_b = old_rest.basis;
+ Basis new_rest_b = new_rest.basis;
+ Basis old_pg_b = old_pg.basis;
+ Basis new_pg_b = new_pg.basis;
+ for (int j = 0; j < key_len; j++) {
+ Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
+ anim->track_set_key_value(i, j, (new_pg_b.inverse() * old_pg_b * sc * old_rest_b.inverse() * old_pg_b.inverse() * new_pg_b * new_rest_b).get_scale());
+ }
+ } else {
+ Vector3 old_rest_o = old_rest.origin;
+ Vector3 new_rest_o = new_rest.origin;
+ Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion();
+ Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion();
+ for (int j = 0; j < key_len; j++) {
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest_o)) + new_rest_o);
}
}
}
@@ -471,8 +642,43 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
is_rest_changed = true;
}
- // Init skeleton pose to new rest.
if (is_rest_changed) {
+ // Fix skin.
+ {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
+ int skin_idx = 0;
+ while (nodes.size()) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
+ ERR_CONTINUE(!mi);
+
+ Ref<Skin> skin = mi->get_skin();
+ ERR_CONTINUE(!skin.is_valid());
+
+ Node *node = mi->get_node(mi->get_skeleton_path());
+ ERR_CONTINUE(!node);
+
+ Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (!mesh_skeleton || mesh_skeleton != src_skeleton) {
+ continue;
+ }
+
+ Vector<Transform3D> ibm_diff = ibm_diffs[skin_idx];
+
+ int skin_len = skin->get_bind_count();
+ for (int i = 0; i < skin_len; i++) {
+ StringName bn = skin->get_bind_name(i);
+ int bone_idx = src_skeleton->find_bone(bn);
+ if (bone_idx >= 0) {
+ Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx);
+ skin->set_bind_pose(i, new_rest.inverse() * ibm_diff[bone_idx]);
+ }
+ }
+
+ skin_idx++;
+ }
+ }
+
+ // Init skeleton pose to new rest.
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
Transform3D fixed_rest = src_skeleton->get_bone_rest(i);
src_skeleton->set_bone_pose_position(i, fixed_rest.origin);
diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp
index c03962b8a4..577a4c32b3 100644
--- a/editor/import/resource_importer_bitmask.cpp
+++ b/editor/import/resource_importer_bitmask.cpp
@@ -99,7 +99,7 @@ Error ResourceImporterBitMap::import(const String &p_source_file, const String &
bit = c.a > threshold;
}
- bitmap->set_bit(Vector2(j, i), bit);
+ bitmap->set_bit(j, i, bit);
}
}
diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp
index 32fd94b093..c822cd0fec 100644
--- a/editor/import/resource_importer_dynamic_font.cpp
+++ b/editor/import/resource_importer_dynamic_font.cpp
@@ -105,7 +105,7 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<
r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8));
@@ -139,7 +139,7 @@ void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) {
Error ResourceImporterDynamicFont::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
print_verbose("Importing dynamic font from: " + p_source_file);
- bool antialiased = p_options["antialiased"];
+ int antialiasing = p_options["antialiasing"];
bool generate_mipmaps = p_options["generate_mipmaps"];
bool msdf = p_options["multichannel_signed_distance_field"];
int px_range = p_options["msdf_pixel_range"];
@@ -159,7 +159,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str
Ref<FontFile> font;
font.instantiate();
font->set_data(data);
- font->set_antialiased(antialiased);
+ font->set_antialiasing((TextServer::FontAntialiasing)antialiasing);
font->set_generate_mipmaps(generate_mipmaps);
font->set_multichannel_signed_distance_field(msdf);
font->set_msdf_pixel_range(px_range);
diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp
index 374cbe7ce2..58c2061051 100644
--- a/editor/import/resource_importer_imagefont.cpp
+++ b/editor/import/resource_importer_imagefont.cpp
@@ -99,7 +99,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin
Ref<FontFile> font;
font.instantiate();
- font->set_antialiased(false);
+ font->set_antialiasing(TextServer::FONT_ANTIALIASING_NONE);
font->set_generate_mipmaps(false);
font->set_multichannel_signed_distance_field(false);
font->set_fixed_size(base_size);
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index 2e6de95a46..ed83535421 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -139,7 +139,7 @@ void ResourceImporterLayeredTexture::get_import_options(const String &p_path, Li
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized,Normal Map (RG Channels)"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit", PROPERTY_HINT_RANGE, "-1,256"), -1));
@@ -250,7 +250,7 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons
}
if (p_mipmaps) {
- p_images.write[i]->generate_mipmaps();
+ p_images.write[i]->generate_mipmaps(p_csource == Image::COMPRESS_SOURCE_NORMAL);
} else {
p_images.write[i]->clear_mipmaps();
}
@@ -327,7 +327,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::load_image(p_source_file, image, nullptr, false, 1.0);
+ Error err = ImageLoader::load_image(p_source_file, image);
if (err != OK) {
return err;
}
@@ -354,6 +354,9 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
Image::CompressSource csource = Image::COMPRESS_SOURCE_GENERIC;
if (channel_pack == 0) {
csource = Image::COMPRESS_SOURCE_SRGB;
+ } else if (channel_pack == 2) {
+ // force normal
+ csource = Image::COMPRESS_SOURCE_NORMAL;
}
Image::UsedChannels used_channels = image->detect_used_channels(csource);
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index d1c4e1f8dd..fe70fd58b5 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -129,7 +129,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
if (p.is_absolute_path()) {
path = p;
} else {
- path = base_path.plus_file(p);
+ path = base_path.path_join(p);
}
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -149,7 +149,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
if (p.is_absolute_path()) {
path = p;
} else {
- path = base_path.plus_file(p);
+ path = base_path.path_join(p);
}
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -169,7 +169,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
if (p.is_absolute_path()) {
path = p;
} else {
- path = base_path.plus_file(p);
+ path = base_path.path_join(p);
}
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -184,7 +184,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_bump", "").replace("\\", "/").strip_edges();
- String path = base_path.plus_file(p);
+ String path = base_path.path_join(p);
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -405,7 +405,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
HashMap<String, Ref<StandardMaterial3D>> lib;
String lib_path = current_material_library;
if (lib_path.is_relative_path()) {
- lib_path = p_path.get_base_dir().plus_file(current_material_library);
+ lib_path = p_path.get_base_dir().path_join(current_material_library);
}
Error err = _parse_material_library(lib_path, lib, r_missing_deps);
if (err == OK) {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 3c0de61d24..41061c3fc3 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -368,6 +368,185 @@ static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r
}
}
+struct ScalableNodeCollection {
+ HashSet<Node3D *> node_3ds;
+ HashSet<Ref<ImporterMesh>> importer_meshes;
+ HashSet<Ref<Skin>> skins;
+ HashSet<Ref<Animation>> animations;
+};
+
+void _rescale_importer_mesh(Vector3 p_scale, Ref<ImporterMesh> p_mesh, bool is_shadow = false) {
+ // MESH and SKIN data divide, to compensate for object position multiplying.
+
+ const int surf_count = p_mesh->get_surface_count();
+ const int blendshape_count = p_mesh->get_blend_shape_count();
+ struct LocalSurfData {
+ Mesh::PrimitiveType prim = {};
+ Array arr;
+ Array bsarr;
+ Dictionary lods;
+ String name;
+ Ref<Material> mat;
+ int fmt_compress_flags = 0;
+ };
+
+ Vector<LocalSurfData> surf_data_by_mesh;
+
+ Vector<String> blendshape_names;
+ for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
+ blendshape_names.append(p_mesh->get_blend_shape_name(bsidx));
+ }
+
+ for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) {
+ Mesh::PrimitiveType prim = p_mesh->get_surface_primitive_type(surf_idx);
+ const int fmt_compress_flags = p_mesh->get_surface_format(surf_idx);
+ Array arr = p_mesh->get_surface_arrays(surf_idx);
+ String name = p_mesh->get_surface_name(surf_idx);
+ Dictionary lods = Dictionary();
+ Ref<Material> mat = p_mesh->get_surface_material(surf_idx);
+ {
+ Vector<Vector3> vertex_array = arr[ArrayMesh::ARRAY_VERTEX];
+ for (int vert_arr_i = 0; vert_arr_i < vertex_array.size(); vert_arr_i++) {
+ vertex_array.write[vert_arr_i] = vertex_array[vert_arr_i] * p_scale;
+ }
+ arr[ArrayMesh::ARRAY_VERTEX] = vertex_array;
+ }
+ Array blendshapes;
+ for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
+ Array current_bsarr = p_mesh->get_surface_blend_shape_arrays(surf_idx, bsidx);
+ Vector<Vector3> current_bs_vertex_array = current_bsarr[ArrayMesh::ARRAY_VERTEX];
+ int current_bs_vert_arr_len = current_bs_vertex_array.size();
+ for (int32_t bs_vert_arr_i = 0; bs_vert_arr_i < current_bs_vert_arr_len; bs_vert_arr_i++) {
+ current_bs_vertex_array.write[bs_vert_arr_i] = current_bs_vertex_array[bs_vert_arr_i] * p_scale;
+ }
+ current_bsarr[ArrayMesh::ARRAY_VERTEX] = current_bs_vertex_array;
+ blendshapes.push_back(current_bsarr);
+ }
+
+ LocalSurfData surf_data_dictionary = LocalSurfData();
+ surf_data_dictionary.prim = prim;
+ surf_data_dictionary.arr = arr;
+ surf_data_dictionary.bsarr = blendshapes;
+ surf_data_dictionary.lods = lods;
+ surf_data_dictionary.fmt_compress_flags = fmt_compress_flags;
+ surf_data_dictionary.name = name;
+ surf_data_dictionary.mat = mat;
+
+ surf_data_by_mesh.push_back(surf_data_dictionary);
+ }
+
+ p_mesh->clear();
+
+ for (int bsidx = 0; bsidx < blendshape_count; bsidx++) {
+ p_mesh->add_blend_shape(blendshape_names[bsidx]);
+ }
+
+ for (int surf_idx = 0; surf_idx < surf_count; surf_idx++) {
+ const Mesh::PrimitiveType prim = surf_data_by_mesh[surf_idx].prim;
+ const Array arr = surf_data_by_mesh[surf_idx].arr;
+ const Array bsarr = surf_data_by_mesh[surf_idx].bsarr;
+ const Dictionary lods = surf_data_by_mesh[surf_idx].lods;
+ const int fmt_compress_flags = surf_data_by_mesh[surf_idx].fmt_compress_flags;
+ const String name = surf_data_by_mesh[surf_idx].name;
+ const Ref<Material> mat = surf_data_by_mesh[surf_idx].mat;
+
+ p_mesh->add_surface(prim, arr, bsarr, lods, mat, name, fmt_compress_flags);
+ }
+
+ if (!is_shadow && p_mesh->get_shadow_mesh() != p_mesh && p_mesh->get_shadow_mesh().is_valid()) {
+ _rescale_importer_mesh(p_scale, p_mesh->get_shadow_mesh(), true);
+ }
+}
+
+void _rescale_skin(Vector3 p_scale, Ref<Skin> p_skin) {
+ // MESH and SKIN data divide, to compensate for object position multiplying.
+ for (int i = 0; i < p_skin->get_bind_count(); i++) {
+ Transform3D transform = p_skin->get_bind_pose(i);
+ p_skin->set_bind_pose(i, Transform3D(transform.basis, p_scale * transform.origin));
+ }
+}
+
+void _rescale_animation(Vector3 p_scale, Ref<Animation> p_animation) {
+ for (int track_idx = 0; track_idx < p_animation->get_track_count(); track_idx++) {
+ if (p_animation->track_get_type(track_idx) == Animation::TYPE_POSITION_3D) {
+ for (int key_idx = 0; key_idx < p_animation->track_get_key_count(track_idx); key_idx++) {
+ Vector3 value = p_animation->track_get_key_value(track_idx, key_idx);
+ value = p_scale * value;
+ p_animation->track_set_key_value(track_idx, key_idx, value);
+ }
+ }
+ }
+}
+
+void _apply_basis_to_scalable_node_collection(ScalableNodeCollection &p_dictionary, Vector3 p_scale) {
+ for (Node3D *node_3d : p_dictionary.node_3ds) {
+ if (node_3d) {
+ node_3d->set_position(p_scale * node_3d->get_position());
+
+ Skeleton3D *skeleton_3d = Object::cast_to<Skeleton3D>(node_3d);
+ if (skeleton_3d) {
+ for (int i = 0; i < skeleton_3d->get_bone_count(); i++) {
+ Transform3D rest = skeleton_3d->get_bone_rest(i);
+ skeleton_3d->set_bone_rest(i, Transform3D(rest.basis, p_scale * rest.origin));
+ skeleton_3d->set_bone_pose_position(i, p_scale * rest.origin);
+ }
+ }
+ }
+ }
+ for (Ref<ImporterMesh> mesh : p_dictionary.importer_meshes) {
+ _rescale_importer_mesh(p_scale, mesh, false);
+ }
+ for (Ref<Skin> skin : p_dictionary.skins) {
+ _rescale_skin(p_scale, skin);
+ }
+ for (Ref<Animation> animation : p_dictionary.animations) {
+ _rescale_animation(p_scale, animation);
+ }
+}
+
+void _populate_scalable_nodes_collection(Node *p_node, ScalableNodeCollection &p_dictionary) {
+ if (!p_node) {
+ return;
+ }
+ Node3D *node_3d = Object::cast_to<Node3D>(p_node);
+ if (node_3d) {
+ p_dictionary.node_3ds.insert(node_3d);
+ ImporterMeshInstance3D *mesh_instance_3d = Object::cast_to<ImporterMeshInstance3D>(p_node);
+ if (mesh_instance_3d) {
+ Ref<ImporterMesh> mesh = mesh_instance_3d->get_mesh();
+ if (mesh.is_valid()) {
+ p_dictionary.importer_meshes.insert(mesh);
+ }
+ Ref<Skin> skin = mesh_instance_3d->get_skin();
+ if (skin.is_valid()) {
+ p_dictionary.skins.insert(skin);
+ }
+ }
+ }
+ AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_node);
+ if (animation_player) {
+ List<StringName> animation_list;
+ animation_player->get_animation_list(&animation_list);
+
+ for (const StringName &E : animation_list) {
+ Ref<Animation> animation = animation_player->get_animation(E);
+ p_dictionary.animations.insert(animation);
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ _populate_scalable_nodes_collection(child, p_dictionary);
+ }
+}
+
+void _apply_permanent_rotation_scale_to_node(Node *p_node) {
+ Transform3D transform = Object::cast_to<Node3D>(p_node)->get_transform();
+ ScalableNodeCollection scalable_node_collection;
+ _populate_scalable_nodes_collection(p_node, scalable_node_collection);
+ _apply_basis_to_scalable_node_collection(scalable_node_collection, transform.basis.get_scale());
+}
+
Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames) {
// Children first.
for (int i = 0; i < p_node->get_child_count(); i++) {
@@ -565,7 +744,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
_pre_gen_shape_list(mesh, shapes, true);
}
- RigidDynamicBody3D *rigid_body = memnew(RigidDynamicBody3D);
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
rigid_body->set_name(_fixstr(name, "rigid_body"));
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
@@ -850,12 +1029,12 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
bool use_optimizer = node_settings["optimizer/enabled"];
- float anim_optimizer_linerr = node_settings["optimizer/max_linear_error"];
+ float anim_optimizer_linerr = node_settings["optimizer/max_velocity_error"];
float anim_optimizer_angerr = node_settings["optimizer/max_angular_error"];
- float anim_optimizer_maxang = node_settings["optimizer/max_angle"];
+ int anim_optimizer_preerr = node_settings["optimizer/max_precision_error"];
if (use_optimizer) {
- _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang);
+ _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_preerr);
}
bool use_compression = node_settings["compression/enabled"];
@@ -1060,7 +1239,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
base = col;
} break;
case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
- RigidDynamicBody3D *rigid_body = memnew(RigidDynamicBody3D);
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
rigid_body->set_name(p_node->get_name());
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings));
@@ -1386,12 +1565,12 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
al->remove_animation("default"); // Remove default (no longer needed).
}
-void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
+void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error) {
List<StringName> anim_names;
anim->get_animation_list(&anim_names);
for (const StringName &E : anim_names) {
Ref<Animation> a = anim->get_animation(E);
- a->optimize(p_max_lin_error, p_max_ang_error, Math::deg2rad(p_max_angle));
+ a->optimize(p_max_vel_error, p_max_ang_error, p_prc_error);
}
}
@@ -1467,9 +1646,9 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_linear_error"), 0.05));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error"), 0.01));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angle"), 22));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_velocity_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "optimizer/max_precision_error", PROPERTY_HINT_NONE, "1,6,1"), 3));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compression/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compression/page_size", PROPERTY_HINT_RANGE, "4,512,1,suffix:kb"), 8));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
@@ -1678,6 +1857,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
script_ext_hint += "*." + E;
}
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/apply_root_scale"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true));
@@ -2144,6 +2324,21 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
return err;
}
+ bool apply_root = true;
+ if (p_options.has("nodes/apply_root_scale")) {
+ apply_root = p_options["nodes/apply_root_scale"];
+ }
+ real_t root_scale = 1;
+ if (p_options.has("nodes/root_scale")) {
+ root_scale = p_options["nodes/root_scale"];
+ }
+ if (Object::cast_to<Node3D>(scene)) {
+ Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
+ }
+ if (apply_root) {
+ _apply_permanent_rotation_scale_to_node(scene);
+ Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale).inverse());
+ }
Dictionary subresources = p_options["_subresources"];
Dictionary node_data;
@@ -2199,12 +2394,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
scene->set_script(Variant(root_script));
}
- float root_scale = 1.0;
- if (Object::cast_to<Node3D>(scene)) {
- root_scale = p_options["nodes/root_scale"];
- Object::cast_to<Node3D>(scene)->scale(Vector3(root_scale, root_scale, root_scale));
- }
-
if (p_options["nodes/root_name"] != "Scene Root") {
scene->set_name(p_options["nodes/root_name"]);
} else {
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index b336931476..da37893cc5 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -280,7 +280,7 @@ public:
Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
- void _optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
+ void _optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error);
void _compress_animations(AnimationPlayer *anim, int p_page_size_kb);
Node *pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options);
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index d3079141e0..55afd71c76 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -79,7 +79,7 @@ static String _include_function(const String &p_path, void *userpointer) {
String include = p_path;
if (include.is_relative_path()) {
- include = base_path->plus_file(include);
+ include = base_path->path_join(include);
}
Ref<FileAccess> file_inc = FileAccess::open(include, FileAccess::READ, &err);
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 0eed6184c0..17b94ec706 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -409,11 +409,26 @@ void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String
}
Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+ // Parse import options.
+ int32_t loader_flags = ImageFormatLoader::FLAG_NONE;
+
+ // Compression.
CompressMode compress_mode = CompressMode(int(p_options["compress/mode"]));
const float lossy = p_options["compress/lossy_quality"];
const int pack_channels = p_options["compress/channel_pack"];
+ const int normal = p_options["compress/normal_map"];
+ const int hdr_compression = p_options["compress/hdr_compression"];
+ const int bptc_ldr = p_options["compress/bptc_ldr"];
+
+ // Mipmaps.
const bool mipmaps = p_options["mipmaps/generate"];
const uint32_t mipmap_limit = mipmaps ? uint32_t(p_options["mipmaps/limit"]) : uint32_t(-1);
+
+ // Roughness.
+ const int roughness = p_options["roughness/mode"];
+ const String normal_map = p_options["roughness/src_normal"];
+
+ // Processing.
const bool fix_alpha_border = p_options["process/fix_alpha_border"];
const bool premult_alpha = p_options["process/premult_alpha"];
const bool normal_map_invert_y = p_options["process/normal_map_invert_y"];
@@ -421,29 +436,29 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
const bool stream = false;
const int size_limit = p_options["process/size_limit"];
const bool hdr_as_srgb = p_options["process/hdr_as_srgb"];
+ if (hdr_as_srgb) {
+ loader_flags |= ImageFormatLoader::FLAG_FORCE_LINEAR;
+ }
const bool hdr_clamp_exposure = p_options["process/hdr_clamp_exposure"];
- const int normal = p_options["compress/normal_map"];
- const int hdr_compression = p_options["compress/hdr_compression"];
- const int bptc_ldr = p_options["compress/bptc_ldr"];
- const int roughness = p_options["roughness/mode"];
- const String normal_map = p_options["roughness/src_normal"];
+
float scale = 1.0;
+ // SVG-specific options.
if (p_options.has("svg/scale")) {
scale = p_options["svg/scale"];
}
Ref<Image> normal_image;
Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R;
-
if (mipmaps && roughness > 1 && FileAccess::exists(normal_map)) {
normal_image.instantiate();
if (ImageLoader::load_image(normal_map, normal_image) == OK) {
roughness_channel = Image::RoughnessChannel(roughness - 2);
}
}
+
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::load_image(p_source_file, image, nullptr, hdr_as_srgb, scale);
+ Error err = ImageLoader::load_image(p_source_file, image, nullptr, loader_flags, scale);
if (err != OK) {
return err;
}
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index bae1b903c6..9171f04f42 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -382,7 +382,6 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
mesh_texture->set_mesh(mesh);
texture = mesh_texture;
- //mesh
}
String save_path = p_base_paths[E.key] + ".res";
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index a1e00f7d30..1dcae2841b 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -390,7 +390,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
int first = 0;
int last = (frames / format_channels) - 1;
bool found = false;
- float limit = Math::db2linear(TRIM_DB_LIMIT);
+ float limit = Math::db_to_linear(TRIM_DB_LIMIT);
for (int i = 0; i < data.size() / format_channels; i++) {
float ampChannelSum = 0;
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index 6c12464b5a..730aa3bd61 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -30,6 +30,7 @@
#include "scene_import_settings.h"
+#include "core/config/project_settings.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_file_system.h"
#include "editor/editor_inspector.h"
@@ -176,7 +177,7 @@ void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_ma
item->set_meta("type", "Material");
item->set_meta("import_id", import_id);
- item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+ item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
item->set_selectable(0, true);
if (p_tree == scene_tree) {
@@ -232,7 +233,7 @@ void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, Tree
item->set_meta("type", "Mesh");
item->set_meta("import_id", import_id);
- item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id));
+ item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id));
item->set_selectable(0, true);
@@ -331,7 +332,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
item->set_meta("type", "Node");
item->set_meta("class", type);
item->set_meta("import_id", import_id);
- item->set_tooltip(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
+ item->set_tooltip_text(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id));
item->set_selectable(0, true);
@@ -979,7 +980,7 @@ void SceneImportSettings::_save_path_changed(const String &p_path) {
if (FileAccess::exists(p_path)) {
save_path_item->set_text(2, "Warning: File exists");
- save_path_item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ save_path_item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
save_path_item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1024,12 +1025,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
if (md.has_import_id) {
if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) {
item->set_text(2, "Already External");
- item->set_tooltip(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again."));
+ item->set_tooltip_text(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again."));
} else {
item->set_metadata(0, E.key);
item->set_editable(0, true);
item->set_checked(0, true);
- String path = p_path.plus_file(name);
+ String path = p_path.path_join(name);
if (external_extension_type->get_selected() == 0) {
path += ".tres";
} else {
@@ -1039,7 +1040,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_text(1, path);
if (FileAccess::exists(path)) {
item->set_text(2, "Warning: File exists");
- item->set_tooltip(2, TTR("Existing file with the same name will be replaced."));
+ item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced."));
item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1052,7 +1053,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
} else {
item->set_text(2, "No import ID");
- item->set_tooltip(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_tooltip_text(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
}
@@ -1077,12 +1078,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
if (md.has_import_id) {
if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) {
item->set_text(2, "Already Saving");
- item->set_tooltip(2, TTR("This mesh already saves to an external resource, no action will be taken."));
+ item->set_tooltip_text(2, TTR("This mesh already saves to an external resource, no action will be taken."));
} else {
item->set_metadata(0, E.key);
item->set_editable(0, true);
item->set_checked(0, true);
- String path = p_path.plus_file(name);
+ String path = p_path.path_join(name);
if (external_extension_type->get_selected() == 0) {
path += ".tres";
} else {
@@ -1092,7 +1093,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_text(1, path);
if (FileAccess::exists(path)) {
item->set_text(2, "Warning: File exists");
- item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1105,7 +1106,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
} else {
item->set_text(2, "No import ID");
- item->set_tooltip(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
+ item->set_tooltip_text(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID."));
item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
}
@@ -1129,12 +1130,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) {
item->set_text(2, "Already Saving");
- item->set_tooltip(2, TTR("This animation already saves to an external resource, no action will be taken."));
+ item->set_tooltip_text(2, TTR("This animation already saves to an external resource, no action will be taken."));
} else {
item->set_metadata(0, E.key);
item->set_editable(0, true);
item->set_checked(0, true);
- String path = p_path.plus_file(name);
+ String path = p_path.path_join(name);
if (external_extension_type->get_selected() == 0) {
path += ".tres";
} else {
@@ -1144,7 +1145,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_text(1, path);
if (FileAccess::exists(path)) {
item->set_text(2, "Warning: File exists");
- item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import."));
+ item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import."));
item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
} else {
@@ -1288,6 +1289,11 @@ SceneImportSettings::SceneImportSettings() {
base_viewport->add_child(camera);
camera->make_current();
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ camera->set_attributes(camera_attributes);
+ }
+
light = memnew(DirectionalLight3D);
light->set_transform(Transform3D().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0)));
base_viewport->add_child(light);
diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h
index b5cf82f64b..0e12a83116 100644
--- a/editor/import/scene_import_settings.h
+++ b/editor/import/scene_import_settings.h
@@ -74,6 +74,7 @@ class SceneImportSettings : public ConfirmationDialog {
SubViewport *base_viewport = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
bool first_aabb = false;
AABB contents_aabb;
@@ -191,7 +192,7 @@ class SceneImportSettings : public ConfirmationDialog {
bool editing_animation = false;
- Timer *update_view_timer;
+ Timer *update_view_timer = nullptr;
protected:
void _notification(int p_what);
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 087ef48b56..4732268256 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -584,12 +584,12 @@ void ImportDock::_set_dirty(bool p_dirty) {
// Add a dirty marker to notify the user that they should reimport the selected resource to see changes.
import->set_text(TTR("Reimport") + " (*)");
import->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- import->set_tooltip(TTR("You have pending changes that haven't been applied yet. Click Reimport to apply changes made to the import options.\nSelecting another resource in the FileSystem dock without clicking Reimport first will discard changes made in the Import dock."));
+ import->set_tooltip_text(TTR("You have pending changes that haven't been applied yet. Click Reimport to apply changes made to the import options.\nSelecting another resource in the FileSystem dock without clicking Reimport first will discard changes made in the Import dock."));
} else {
// Remove the dirty marker on the Reimport button.
import->set_text(TTR("Reimport"));
import->remove_theme_color_override("font_color");
- import->set_tooltip("");
+ import->set_tooltip_text("");
}
}
@@ -628,6 +628,9 @@ ImportDock::ImportDock() {
content->add_margin_child(TTR("Import As:"), hb);
import_as = memnew(OptionButton);
import_as->set_disabled(true);
+ import_as->set_fit_to_longest_item(false);
+ import_as->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
+ import_as->set_h_size_flags(SIZE_EXPAND_FILL);
import_as->connect("item_selected", callable_mp(this, &ImportDock::_importer_selected));
hb->add_child(import_as);
import_as->set_h_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 79d94246ad..74fdbdebd7 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -178,7 +178,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
- editor_data->get_undo_redo().clear_history();
+ int history_id = editor_data->get_undo_redo()->get_history_for_object(current).id;
+ editor_data->get_undo_redo()->clear_history(true, history_id);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(current);
@@ -246,7 +247,7 @@ void InspectorDock::_resource_file_selected(String p_file) {
}
if (res.is_null()) {
- warning_dialog->set_text(TTR("Failed to load resource."));
+ info_dialog->set_text(TTR("Failed to load resource."));
return;
};
@@ -310,7 +311,6 @@ void InspectorDock::_prepare_history() {
history_menu->get_popup()->clear();
- Ref<Texture2D> base_icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
HashSet<ObjectID> already;
for (int i = editor_history->get_history_len() - 1; i >= history_to; i--) {
ObjectID id = editor_history->get_history_obj(i);
@@ -324,13 +324,12 @@ void InspectorDock::_prepare_history() {
already.insert(id);
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj, "");
- if (icon.is_null()) {
- icon = base_icon;
- }
+ Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj, "Object");
String text;
- if (Object::cast_to<Resource>(obj)) {
+ if (obj->has_method("_get_editor_name")) {
+ text = obj->call("_get_editor_name");
+ } else if (Object::cast_to<Resource>(obj)) {
Resource *r = Object::cast_to<Resource>(obj);
if (r->get_path().is_resource_file()) {
text = r->get_path().get_file();
@@ -348,14 +347,14 @@ void InspectorDock::_prepare_history() {
}
if (i == editor_history->get_history_pos() && current) {
- text = "[" + text + "]";
+ text += " " + TTR("(Current)");
}
history_menu->get_popup()->add_icon_item(icon, text, i);
}
}
void InspectorDock::_select_history(int p_idx) {
- //push it to the top, it is not correct, but it's more useful
+ // Push it to the top, it is not correct, but it's more useful.
ObjectID id = EditorNode::get_singleton()->get_editor_selection_history()->get_history_obj(p_idx);
Object *obj = ObjectDB::get_instance(id);
if (!obj) {
@@ -408,8 +407,8 @@ void InspectorDock::_menu_expand_revertable() {
inspector->expand_revertable();
}
-void InspectorDock::_warning_pressed() {
- warning_dialog->popup_centered();
+void InspectorDock::_info_pressed() {
+ info_dialog->popup_centered();
}
Container *InspectorDock::get_addon_area() {
@@ -445,8 +444,13 @@ void InspectorDock::_notification(int p_what) {
history_menu->set_icon(get_theme_icon(SNAME("History"), SNAME("EditorIcons")));
object_menu->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
- warning->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ if (info_is_warning) {
+ info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ } else {
+ info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor")));
+ }
} break;
}
}
@@ -475,11 +479,22 @@ void InspectorDock::open_resource(const String &p_type) {
_load_resource(p_type);
}
-void InspectorDock::set_warning(const String &p_message) {
- warning->hide();
- if (!p_message.is_empty()) {
- warning->show();
- warning_dialog->set_text(p_message);
+void InspectorDock::set_info(const String &p_button_text, const String &p_message, bool p_is_warning) {
+ info->hide();
+ info_is_warning = p_is_warning;
+
+ if (info_is_warning) {
+ info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ } else {
+ info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor")));
+ }
+
+ if (!p_button_text.is_empty() && !p_message.is_empty()) {
+ info->show();
+ info->set_text(p_button_text);
+ info_dialog->set_text(p_message);
}
}
@@ -514,7 +529,7 @@ void InspectorDock::update(Object *p_object) {
resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_MAKE_BUILT_IN), !is_resource || is_text_file);
if (!is_object || is_text_file) {
- warning->hide();
+ info->hide();
editor_path->clear_path();
return;
}
@@ -616,20 +631,20 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
resource_new_button = memnew(Button);
resource_new_button->set_flat(true);
- resource_new_button->set_tooltip(TTR("Create a new resource in memory and edit it."));
+ resource_new_button->set_tooltip_text(TTR("Create a new resource in memory and edit it."));
general_options_hb->add_child(resource_new_button);
resource_new_button->connect("pressed", callable_mp(this, &InspectorDock::_new_resource));
resource_new_button->set_focus_mode(Control::FOCUS_NONE);
resource_load_button = memnew(Button);
resource_load_button->set_flat(true);
- resource_load_button->set_tooltip(TTR("Load an existing resource from disk and edit it."));
+ resource_load_button->set_tooltip_text(TTR("Load an existing resource from disk and edit it."));
general_options_hb->add_child(resource_load_button);
resource_load_button->connect("pressed", callable_mp(this, &InspectorDock::_open_resource_selector));
resource_load_button->set_focus_mode(Control::FOCUS_NONE);
resource_save_button = memnew(MenuButton);
- resource_save_button->set_tooltip(TTR("Save the currently edited resource."));
+ resource_save_button->set_tooltip_text(TTR("Save the currently edited resource."));
general_options_hb->add_child(resource_save_button);
resource_save_button->get_popup()->add_item(TTR("Save"), RESOURCE_SAVE);
resource_save_button->get_popup()->add_item(TTR("Save As..."), RESOURCE_SAVE_AS);
@@ -638,7 +653,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
resource_save_button->set_disabled(true);
resource_extra_button = memnew(MenuButton);
- resource_extra_button->set_tooltip(TTR("Extra resource options."));
+ resource_extra_button->set_tooltip_text(TTR("Extra resource options."));
general_options_hb->add_child(resource_extra_button);
resource_extra_button->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_resource_extra_popup));
resource_extra_button->get_popup()->add_icon_shortcut(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")), ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource from Clipboard")), RESOURCE_EDIT_CLIPBOARD);
@@ -654,19 +669,19 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
backward_button = memnew(Button);
backward_button->set_flat(true);
general_options_hb->add_child(backward_button);
- backward_button->set_tooltip(TTR("Go to the previous edited object in history."));
+ backward_button->set_tooltip_text(TTR("Go to the previous edited object in history."));
backward_button->set_disabled(true);
backward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_back));
forward_button = memnew(Button);
forward_button->set_flat(true);
general_options_hb->add_child(forward_button);
- forward_button->set_tooltip(TTR("Go to the next edited object in history."));
+ forward_button->set_tooltip_text(TTR("Go to the next edited object in history."));
forward_button->set_disabled(true);
forward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_forward));
history_menu = memnew(MenuButton);
- history_menu->set_tooltip(TTR("History of recently edited objects."));
+ history_menu->set_tooltip_text(TTR("History of recently edited objects."));
general_options_hb->add_child(history_menu);
history_menu->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_history));
history_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_select_history));
@@ -680,7 +695,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
open_docs_button = memnew(Button);
open_docs_button->set_flat(true);
open_docs_button->set_disabled(true);
- open_docs_button->set_tooltip(TTR("Open documentation for this object."));
+ open_docs_button->set_tooltip_text(TTR("Open documentation for this object."));
open_docs_button->set_shortcut(ED_SHORTCUT("property_editor/open_help", TTR("Open Documentation")));
subresource_hb->add_child(open_docs_button);
open_docs_button->connect("pressed", callable_mp(this, &InspectorDock::_menu_option).bind(OBJECT_REQUEST_HELP));
@@ -702,16 +717,15 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
object_menu = memnew(MenuButton);
object_menu->set_shortcut_context(this);
property_tools_hb->add_child(object_menu);
- object_menu->set_tooltip(TTR("Manage object properties."));
+ object_menu->set_tooltip_text(TTR("Manage object properties."));
object_menu->get_popup()->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_menu));
object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option));
- warning = memnew(Button);
- add_child(warning);
- warning->set_text(TTR("Changes may be lost!"));
- warning->set_clip_text(true);
- warning->hide();
- warning->connect("pressed", callable_mp(this, &InspectorDock::_warning_pressed));
+ info = memnew(Button);
+ add_child(info);
+ info->set_clip_text(true);
+ info->hide();
+ info->connect("pressed", callable_mp(this, &InspectorDock::_info_pressed));
unique_resources_confirmation = memnew(ConfirmationDialog);
add_child(unique_resources_confirmation);
@@ -736,8 +750,8 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
unique_resources_confirmation->connect("confirmed", callable_mp(this, &InspectorDock::_menu_confirm_current));
- warning_dialog = memnew(AcceptDialog);
- EditorNode::get_singleton()->get_gui_base()->add_child(warning_dialog);
+ info_dialog = memnew(AcceptDialog);
+ EditorNode::get_singleton()->get_gui_base()->add_child(info_dialog);
load_resource_dialog = memnew(EditorFileDialog);
add_child(load_resource_dialog);
@@ -755,7 +769,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
inspector->set_property_name_style(EditorPropertyNameProcessor::get_default_inspector_style());
inspector->set_use_folding(!bool(EDITOR_GET("interface/inspector/disable_folding")));
inspector->register_text_enter(search);
- inspector->set_undo_redo(&editor_data->get_undo_redo());
+ inspector->set_undo_redo(editor_data->get_undo_redo());
inspector->set_use_filter(true); // TODO: check me
diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h
index e32410151f..5ebcbf70c7 100644
--- a/editor/inspector_dock.h
+++ b/editor/inspector_dock.h
@@ -93,8 +93,9 @@ class InspectorDock : public VBoxContainer {
MenuButton *object_menu = nullptr;
EditorPath *editor_path = nullptr;
- Button *warning = nullptr;
- AcceptDialog *warning_dialog = nullptr;
+ bool info_is_warning = false; // Display in yellow and use warning icon if true.
+ Button *info = nullptr;
+ AcceptDialog *info_dialog = nullptr;
int current_option = -1;
ConfirmationDialog *unique_resources_confirmation = nullptr;
@@ -118,7 +119,7 @@ class InspectorDock : public VBoxContainer {
void _paste_resource();
void _prepare_resource_extra_popup();
- void _warning_pressed();
+ void _info_pressed();
void _resource_created();
void _resource_selected(const Ref<Resource> &p_res, const String &p_property);
void _edit_forward();
@@ -145,7 +146,7 @@ public:
void edit_resource(const Ref<Resource> &p_resource);
void open_resource(const String &p_type);
void clear();
- void set_warning(const String &p_message);
+ void set_info(const String &p_button_text, const String &p_message, bool p_is_warning);
void update(Object *p_object);
Container *get_addon_area();
EditorInspector *get_inspector() { return inspector; }
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index e8fb80eb57..683481ecc1 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_translation_parser.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/filesystem_dock.h"
#include "editor/pot_generator.h"
#include "scene/gui/control.h"
@@ -192,7 +193,7 @@ void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) {
TreeItem *ed = translation_remap_options->get_edited();
ERR_FAIL_COND(!ed);
- locale_select->set_locale(ed->get_tooltip(1));
+ locale_select->set_locale(ed->get_tooltip_text(1));
locale_select->popup_locale_dialog();
}
@@ -201,7 +202,7 @@ void LocalizationEditor::_translation_res_option_selected(const String &p_locale
ERR_FAIL_COND(!ed);
ed->set_text(1, TranslationServer::get_singleton()->get_locale_name(p_locale));
- ed->set_tooltip(1, p_locale);
+ ed->set_tooltip_text(1, p_locale);
LocalizationEditor::_translation_res_option_changed();
}
@@ -225,7 +226,7 @@ void LocalizationEditor::_translation_res_option_changed() {
String key = k->get_metadata(0);
int idx = ed->get_metadata(0);
String path = ed->get_metadata(1);
- String locale = ed->get_tooltip(1);
+ String locale = ed->get_tooltip_text(1);
ERR_FAIL_COND(!remaps.has(key));
PackedStringArray r = remaps[key];
@@ -485,7 +486,7 @@ void LocalizationEditor::update_translations() {
TreeItem *t = translation_list->create_item(root);
t->set_editable(0, false);
t->set_text(0, translations[i].replace_first("res://", ""));
- t->set_tooltip(0, translations[i]);
+ t->set_tooltip_text(0, translations[i]);
t->set_metadata(0, i);
t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
}
@@ -519,14 +520,14 @@ void LocalizationEditor::update_translations() {
TreeItem *t = translation_remap->create_item(root);
t->set_editable(0, false);
t->set_text(0, keys[i].replace_first("res://", ""));
- t->set_tooltip(0, keys[i]);
+ t->set_tooltip_text(0, keys[i]);
t->set_metadata(0, keys[i]);
t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
// Display that it has been removed if this is the case.
if (!FileAccess::exists(keys[i])) {
t->set_text(0, t->get_text(0) + vformat(" (%s)", TTR("Removed")));
- t->set_tooltip(0, vformat(TTR("%s cannot be found."), t->get_tooltip(0)));
+ t->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t->get_tooltip_text(0)));
}
if (keys[i] == remap_selected) {
@@ -543,19 +544,19 @@ void LocalizationEditor::update_translations() {
TreeItem *t2 = translation_remap_options->create_item(root2);
t2->set_editable(0, false);
t2->set_text(0, path.replace_first("res://", ""));
- t2->set_tooltip(0, path);
+ t2->set_tooltip_text(0, path);
t2->set_metadata(0, j);
t2->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
t2->set_cell_mode(1, TreeItem::CELL_MODE_CUSTOM);
t2->set_text(1, TranslationServer::get_singleton()->get_locale_name(locale));
t2->set_editable(1, true);
t2->set_metadata(1, path);
- t2->set_tooltip(1, locale);
+ t2->set_tooltip_text(1, locale);
// Display that it has been removed if this is the case.
if (!FileAccess::exists(path)) {
t2->set_text(0, t2->get_text(0) + vformat(" (%s)", TTR("Removed")));
- t2->set_tooltip(0, vformat(TTR("%s cannot be found."), t2->get_tooltip(0)));
+ t2->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t2->get_tooltip_text(0)));
}
}
}
@@ -572,7 +573,7 @@ void LocalizationEditor::update_translations() {
TreeItem *t = translation_pot_list->create_item(root);
t->set_editable(0, false);
t->set_text(0, pot_translations[i].replace_first("res://", ""));
- t->set_tooltip(0, pot_translations[i]);
+ t->set_tooltip_text(0, pot_translations[i]);
t->set_metadata(0, i);
t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
}
diff --git a/editor/localization_editor.h b/editor/localization_editor.h
index 10ccdfdc13..ecac171fe3 100644
--- a/editor/localization_editor.h
+++ b/editor/localization_editor.h
@@ -56,7 +56,7 @@ class LocalizationEditor : public VBoxContainer {
EditorFileDialog *pot_file_open_dialog = nullptr;
EditorFileDialog *pot_generate_dialog = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool updating_translations = false;
String localization_changed;
diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp
index a694b8d754..a386fba84d 100644
--- a/editor/multi_node_edit.cpp
+++ b/editor/multi_node_edit.cpp
@@ -32,6 +32,7 @@
#include "core/math/math_fieldwise.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
bool MultiNodeEdit::_set(const StringName &p_name, const Variant &p_value) {
return _set_impl(p_name, p_value, "");
@@ -45,7 +46,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
String name = p_name;
- if (name == "scripts") { // script set is intercepted at object level (check Variant Object::get() ) ,so use a different name
+ if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name.
name = "script";
}
@@ -54,15 +55,11 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
node_path_target = es->get_node(p_value);
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
- ur->create_action(TTR("MultiNode Set") + " " + String(name), UndoRedo::MERGE_ENDS);
+ ur->create_action(vformat(TTR("Set %s on %d nodes"), name, get_node_count()), UndoRedo::MERGE_ENDS);
for (const NodePath &E : nodes) {
- if (!es->has_node(E)) {
- continue;
- }
-
- Node *n = es->get_node(E);
+ Node *n = es->get_node_or_null(E);
if (!n) {
continue;
}
@@ -99,16 +96,12 @@ bool MultiNodeEdit::_get(const StringName &p_name, Variant &r_ret) const {
}
String name = p_name;
- if (name == "scripts") { // script set is intercepted at object level (check Variant Object::get() ) ,so use a different name
+ if (name == "scripts") { // Script set is intercepted at object level (check Variant Object::get()), so use a different name.
name = "script";
}
for (const NodePath &E : nodes) {
- if (!es->has_node(E)) {
- continue;
- }
-
- const Node *n = es->get_node(E);
+ const Node *n = es->get_node_or_null(E);
if (!n) {
continue;
}
@@ -136,11 +129,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
List<PLData *> data_list;
for (const NodePath &E : nodes) {
- if (!es->has_node(E)) {
- continue;
- }
-
- Node *n = es->get_node(E);
+ Node *n = es->get_node_or_null(E);
if (!n) {
continue;
}
@@ -150,7 +139,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
for (const PropertyInfo &F : plist) {
if (F.name == "script") {
- continue; //added later manually, since this is intercepted before being set (check Variant Object::get() )
+ continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()).
}
if (!usage.has(F.name)) {
PLData pld;
@@ -160,7 +149,7 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
data_list.push_back(usage.getptr(F.name));
}
- // Make sure only properties with the same exact PropertyInfo data will appear
+ // Make sure only properties with the same exact PropertyInfo data will appear.
if (usage[F.name].info == F) {
usage[F.name].uses++;
}
@@ -178,6 +167,66 @@ void MultiNodeEdit::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, "scripts", PROPERTY_HINT_RESOURCE_TYPE, "Script"));
}
+String MultiNodeEdit::_get_editor_name() const {
+ return vformat(TTR("%s (%d Selected)"), get_edited_class_name(), get_node_count());
+}
+
+bool MultiNodeEdit::_property_can_revert(const StringName &p_name) const {
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es) {
+ return false;
+ }
+
+ if (ClassDB::has_property(get_edited_class_name(), p_name)) {
+ StringName class_name;
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ class_name = node->get_class_name();
+ }
+
+ Variant default_value = ClassDB::class_get_default_property_value(class_name, p_name);
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ if (node->get(p_name) != default_value) {
+ // A node that doesn't have the default value has been found, so show the revert button.
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Don't show the revert button if the edited class doesn't have the property.
+ return false;
+}
+
+bool MultiNodeEdit::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es) {
+ return false;
+ }
+
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ r_property = ClassDB::class_get_default_property_value(node->get_class_name(), p_name);
+ return true;
+ }
+
+ return false;
+}
+
void MultiNodeEdit::add_node(const NodePath &p_node) {
nodes.push_back(p_node);
}
@@ -191,9 +240,69 @@ NodePath MultiNodeEdit::get_node(int p_index) const {
return nodes[p_index];
}
+StringName MultiNodeEdit::get_edited_class_name() const {
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es) {
+ return SNAME("Node");
+ }
+
+ // Get the class name of the first node.
+ StringName class_name;
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ class_name = node->get_class_name();
+ break;
+ }
+
+ if (class_name == StringName()) {
+ return SNAME("Node");
+ }
+
+ bool check_again = true;
+ while (check_again) {
+ check_again = false;
+
+ if (class_name == SNAME("Node") || class_name == StringName()) {
+ // All nodes inherit from Node, so no need to continue checking.
+ return SNAME("Node");
+ }
+
+ // Check that all nodes inherit from class_name.
+ for (const NodePath &E : nodes) {
+ Node *node = es->get_node_or_null(E);
+ if (!node) {
+ continue;
+ }
+
+ const StringName node_class_name = node->get_class_name();
+ if (class_name == node_class_name || ClassDB::is_parent_class(node_class_name, class_name)) {
+ // class_name is the same or a parent of the node's class.
+ continue;
+ }
+
+ // class_name is not a parent of the node's class, so check again with the parent class.
+ class_name = ClassDB::get_parent_class(class_name);
+ check_again = true;
+ break;
+ }
+ }
+
+ return class_name;
+}
+
void MultiNodeEdit::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) {
_set_impl(p_property, p_value, p_field);
}
+void MultiNodeEdit::_bind_methods() {
+ ClassDB::bind_method("_hide_script_from_inspector", &MultiNodeEdit::_hide_script_from_inspector);
+ ClassDB::bind_method("_hide_metadata_from_inspector", &MultiNodeEdit::_hide_metadata_from_inspector);
+ ClassDB::bind_method("_get_editor_name", &MultiNodeEdit::_get_editor_name);
+}
+
MultiNodeEdit::MultiNodeEdit() {
}
diff --git a/editor/multi_node_edit.h b/editor/multi_node_edit.h
index 31678d7b01..9c0ec85e20 100644
--- a/editor/multi_node_edit.h
+++ b/editor/multi_node_edit.h
@@ -45,15 +45,25 @@ class MultiNodeEdit : public RefCounted {
bool _set_impl(const StringName &p_name, const Variant &p_value, const String &p_field);
protected:
+ static void _bind_methods();
+
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
+ bool _hide_script_from_inspector() { return true; }
+ bool _hide_metadata_from_inspector() { return true; }
+
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
+ String _get_editor_name() const;
+
void add_node(const NodePath &p_node);
int get_node_count() const;
NodePath get_node(int p_index) const;
+ StringName get_edited_class_name() const;
void set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field);
diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp
index 986370f537..55fa2f22dd 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -117,7 +117,7 @@ NodeDock::NodeDock() {
groups_button->connect("pressed", callable_mp(this, &NodeDock::show_groups));
connections = memnew(ConnectionsDock);
- connections->set_undoredo(EditorNode::get_undo_redo());
+ connections->set_undo_redo(EditorNode::get_undo_redo());
add_child(connections);
connections->set_v_size_flags(SIZE_EXPAND_FILL);
connections->hide();
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 6d323572e6..71ff77e9bc 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -62,7 +62,7 @@ void PluginConfigDialog::_on_confirmed() {
if (script_name.get_extension().is_empty()) {
script_name += "." + ext;
}
- String script_path = path.plus_file(script_name);
+ String script_path = path.path_join(script_name);
Ref<ConfigFile> cf = memnew(ConfigFile);
cf->set_value("plugin", "name", name_edit->get_text());
@@ -71,7 +71,7 @@ void PluginConfigDialog::_on_confirmed() {
cf->set_value("plugin", "version", version_edit->get_text());
cf->set_value("plugin", "script", script_name);
- cf->save(path.plus_file("plugin.cfg"));
+ cf->save(path.path_join("plugin.cfg"));
if (!_edit_mode) {
String class_name = script_name.get_basename();
@@ -111,32 +111,32 @@ void PluginConfigDialog::_on_required_text_changed(const String &) {
name_validation->set_texture(valid_icon);
subfolder_validation->set_texture(valid_icon);
script_validation->set_texture(valid_icon);
- name_validation->set_tooltip("");
- subfolder_validation->set_tooltip("");
- script_validation->set_tooltip("");
+ name_validation->set_tooltip_text("");
+ subfolder_validation->set_tooltip_text("");
+ script_validation->set_tooltip_text("");
// Change valid status to invalid depending on conditions.
Vector<String> errors;
if (name_edit->get_text().is_empty()) {
is_valid = false;
name_validation->set_texture(invalid_icon);
- name_validation->set_tooltip(TTR("Plugin name cannot be blank."));
+ name_validation->set_tooltip_text(TTR("Plugin name cannot be blank."));
}
if ((!script_edit->get_text().get_extension().is_empty() && script_edit->get_text().get_extension() != ext) || script_edit->get_text().ends_with(".")) {
is_valid = false;
script_validation->set_texture(invalid_icon);
- script_validation->set_tooltip(vformat(TTR("Script extension must match chosen language extension (.%s)."), ext));
+ script_validation->set_tooltip_text(vformat(TTR("Script extension must match chosen language extension (.%s)."), ext));
}
if (!subfolder_edit->get_text().is_empty() && !subfolder_edit->get_text().is_valid_filename()) {
is_valid = false;
subfolder_validation->set_texture(invalid_icon);
- subfolder_validation->set_tooltip(TTR("Subfolder name is not a valid folder name."));
+ subfolder_validation->set_tooltip_text(TTR("Subfolder name is not a valid folder name."));
} else {
String path = "res://addons/" + _get_subfolder();
if (!_edit_mode && DirAccess::exists(path)) { // Only show this error if in "create" mode.
is_valid = false;
subfolder_validation->set_texture(invalid_icon);
- subfolder_validation->set_tooltip(TTR("Subfolder cannot be one which already exists."));
+ subfolder_validation->set_tooltip_text(TTR("Subfolder cannot be one which already exists."));
}
}
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index a7d7c0145a..c928b95642 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/separator.h"
bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const {
@@ -234,13 +235,13 @@ void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_r
button_delete->set_disabled(p_disable);
if (p_disable) {
- button_create->set_tooltip(p_reason);
- button_edit->set_tooltip(p_reason);
- button_delete->set_tooltip(p_reason);
+ button_create->set_tooltip_text(p_reason);
+ button_edit->set_tooltip_text(p_reason);
+ button_delete->set_tooltip_text(p_reason);
} else {
- button_create->set_tooltip(TTR("Create points."));
- button_edit->set_tooltip(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point"));
- button_delete->set_tooltip(TTR("Erase points."));
+ button_create->set_tooltip_text(TTR("Create points."));
+ button_edit->set_tooltip_text(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point"));
+ button_delete->set_tooltip_text(TTR("Erase points."));
}
}
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index 696fd7b637..1fbbe67c8d 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -36,6 +36,7 @@
#include "scene/gui/box_container.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class AbstractPolygon2DEditor : public HBoxContainer {
GDCLASS(AbstractPolygon2DEditor, HBoxContainer);
@@ -99,7 +100,7 @@ protected:
int mode = MODE_EDIT;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void _menu_option(int p_option);
void _wip_changed();
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 32d97c65a9..0e941ad433 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
@@ -47,7 +48,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
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();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -55,67 +58,69 @@ 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() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
+ if (!read_only) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
- List<StringName> classes;
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- classes.sort_custom<StringName::AlphCompare>();
+ List<StringName> classes;
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ classes.sort_custom<StringName::AlphCompare>();
- menu->add_submenu_item(TTR("Add Animation"), "animations");
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
- if (gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (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);
+ 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);
+ for (const StringName &E : names) {
+ animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
+ animations_to_add.push_back(E);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue;
- }
+ for (const StringName &E : classes) {
+ String name = String(E).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue;
+ }
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E);
+ }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ 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("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
- menu->reset_size();
- menu->popup();
+ 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;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
+ add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
- if (snap->is_pressed()) {
- add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ if (snap->is_pressed()) {
+ add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ }
}
}
if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- blend_space_draw->update(); // why not
+ blend_space_draw->queue_redraw(); // why not
// try to see if a point can be selected
selected_point = -1;
@@ -137,31 +142,33 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
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);
- point += drag_ofs.x;
+ if (!read_only) {
+ if (dragging_selected) {
+ // move
+ float point = blend_space->get_blend_point_position(selected_point);
+ point += drag_ofs.x;
+
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ dragging_selected_attempt = false;
+ dragging_selected = false;
+ blend_space_draw->queue_redraw();
}
-
- dragging_selected_attempt = false;
- dragging_selected = false;
- blend_space_draw->update();
}
// *set* the blend
@@ -171,20 +178,20 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos += blend_space->get_min_space();
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && !blend_space_draw->has_focus()) {
blend_space_draw->grab_focus();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mm.is_valid() && dragging_selected_attempt) {
dragging_selected = true;
drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0));
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
_update_edited_point_pos();
}
@@ -195,7 +202,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -254,10 +261,12 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
float point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs.x;
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs.x;
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
}
}
@@ -321,7 +330,7 @@ void AnimationNodeBlendSpace1DEditor::_update_space() {
snap_value->set_value(blend_space->get_snap());
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
updating = false;
}
@@ -346,7 +355,7 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
@@ -365,7 +374,7 @@ void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
}
void AnimationNodeBlendSpace1DEditor::_snap_toggled() {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
@@ -416,7 +425,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
@@ -434,7 +443,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) {
@@ -447,7 +456,7 @@ void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) {
}
_update_tool_erase();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
@@ -474,7 +483,7 @@ void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();
- tool_erase->set_disabled(!point_valid);
+ tool_erase->set_disabled(!point_valid || read_only);
if (point_valid) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
@@ -485,7 +494,11 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -504,7 +517,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() {
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -524,7 +537,7 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_open_editor() {
@@ -539,9 +552,9 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
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_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), 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")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), 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")));
@@ -589,10 +602,20 @@ bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ edit_value->set_editable(!read_only);
+ label_value->set_editable(!read_only);
+ min_value->set_editable(!read_only);
+ max_value->set_editable(!read_only);
+ sync->set_disabled(read_only);
}
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
@@ -612,7 +635,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_blend->set_button_group(bg);
top_hb->add_child(tool_blend);
tool_blend->set_pressed(true);
- tool_blend->set_tooltip(TTR("Set the blending position within the space"));
+ tool_blend->set_tooltip_text(TTR("Set the blending position within the space"));
tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(3));
tool_select = memnew(Button);
@@ -620,7 +643,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
top_hb->add_child(tool_select);
- tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
+ tool_select->set_tooltip_text(TTR("Select and move points, create points with RMB."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(0));
tool_create = memnew(Button);
@@ -628,7 +651,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
top_hb->add_child(tool_create);
- tool_create->set_tooltip(TTR("Create points."));
+ tool_create->set_tooltip_text(TTR("Create points."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(1));
tool_erase_sep = memnew(VSeparator);
@@ -636,7 +659,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_erase = memnew(Button);
tool_erase->set_flat(true);
top_hb->add_child(tool_erase);
- tool_erase->set_tooltip(TTR("Erase points."));
+ tool_erase->set_tooltip_text(TTR("Erase points."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected));
top_hb->add_child(memnew(VSeparator));
@@ -646,7 +669,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
snap->set_toggle_mode(true);
top_hb->add_child(snap);
snap->set_pressed(true);
- snap->set_tooltip(TTR("Enable snap and show grid."));
+ snap->set_tooltip_text(TTR("Enable snap and show grid."));
snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_snap_toggled));
snap_value = memnew(SpinBox);
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index 9b06f3248f..c8b01cb54b 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -40,10 +40,13 @@
#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace1D> blend_space;
+ bool read_only = false;
HBoxContainer *goto_parent_hb = nullptr;
Button *goto_parent = nullptr;
@@ -76,7 +79,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
bool updating = false;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
static AnimationNodeBlendSpace1DEditor *singleton;
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index dc764725dd..f75dcdf2d6 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
@@ -51,7 +52,7 @@ bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node)
}
void AnimationNodeBlendSpace2DEditor::_blend_space_changed() {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
@@ -59,11 +60,29 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space->disconnect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
}
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
blend_space->connect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
+ max_x_value->set_editable(!read_only);
+ min_x_value->set_editable(!read_only);
+ max_y_value->set_editable(!read_only);
+ min_y_value->set_editable(!read_only);
+ label_x->set_editable(!read_only);
+ label_y->set_editable(!read_only);
+ edit_x->set_editable(!read_only);
+ edit_y->set_editable(!read_only);
+ tool_triangle->set_disabled(read_only);
+ auto_triangles->set_disabled(read_only);
+ sync->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
}
StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
@@ -75,7 +94,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventKey> k = p_event;
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();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -83,62 +104,64 @@ 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() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- 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);
+ if (!read_only) {
+ 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);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue; // nope
+ for (const StringName &E : classes) {
+ String name = String(E).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);
}
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ 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("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
-
- 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;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
-
- if (snap->is_pressed()) {
- add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+
+ 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;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
+
+ if (snap->is_pressed()) {
+ add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ }
}
}
if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- blend_space_draw->update(); //update anyway
+ blend_space_draw->queue_redraw(); //update anyway
//try to see if a point can be selected
selected_point = -1;
selected_triangle = -1;
@@ -178,7 +201,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- blend_space_draw->update(); //update anyway
+ blend_space_draw->queue_redraw(); //update anyway
//try to see if a point can be selected
selected_point = -1;
@@ -221,21 +244,23 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
point = point.snapped(blend_space->get_snap());
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ if (!read_only) {
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
+ }
}
dragging_selected_attempt = false;
dragging_selected = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
@@ -246,30 +271,32 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && !blend_space_draw->has_focus()) {
blend_space_draw->grab_focus();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mm.is_valid() && dragging_selected_attempt) {
dragging_selected = true;
- drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
- blend_space_draw->update();
+ if (!read_only) {
+ drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
+ }
+ blend_space_draw->queue_redraw();
_update_edited_point_pos();
}
if (mm.is_valid() && tool_triangle->is_pressed() && making_triangle.size()) {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mm.is_valid() && !tool_triangle->is_pressed() && making_triangle.size()) {
making_triangle.clear();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
if (mm.is_valid() && tool_blend->is_pressed() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
@@ -280,7 +307,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -332,7 +359,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
@@ -350,11 +377,14 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
- tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count()));
+ tool_erase->set_disabled(
+ (!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())) ||
+ read_only);
+
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
@@ -362,7 +392,11 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
} else {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -390,7 +424,7 @@ void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) {
tool_erase_sep->hide();
}
_update_tool_erase();
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
@@ -502,10 +536,12 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
points.clear();
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
Vector2 point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs;
- if (snap->is_pressed()) {
- point = point.snapped(blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs;
+ if (snap->is_pressed()) {
+ point = point.snapped(blend_space->get_snap());
+ }
}
}
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
@@ -578,7 +614,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
}
void AnimationNodeBlendSpace2DEditor::_snap_toggled() {
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_update_space() {
@@ -611,7 +647,7 @@ void AnimationNodeBlendSpace2DEditor::_update_space() {
snap_x->set_value(blend_space->get_snap().x);
snap_y->set_value(blend_space->get_snap().y);
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
updating = false;
}
@@ -638,7 +674,7 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_labels_changed(String) {
@@ -680,7 +716,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
} else if (selected_triangle != -1) {
updating = true;
undo_redo->create_action(TTR("Remove BlendSpace2D Triangle"));
@@ -692,7 +728,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
}
@@ -731,16 +767,16 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
undo_redo->commit_action();
updating = false;
- blend_space_draw->update();
+ blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
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_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), 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")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), 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")));
@@ -832,7 +868,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_blend->set_button_group(bg);
top_hb->add_child(tool_blend);
tool_blend->set_pressed(true);
- tool_blend->set_tooltip(TTR("Set the blending position within the space"));
+ tool_blend->set_tooltip_text(TTR("Set the blending position within the space"));
tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(3));
tool_select = memnew(Button);
@@ -840,7 +876,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
top_hb->add_child(tool_select);
- tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
+ tool_select->set_tooltip_text(TTR("Select and move points, create points with RMB."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(0));
tool_create = memnew(Button);
@@ -848,7 +884,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
top_hb->add_child(tool_create);
- tool_create->set_tooltip(TTR("Create points."));
+ tool_create->set_tooltip_text(TTR("Create points."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(1));
tool_triangle = memnew(Button);
@@ -856,7 +892,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_triangle->set_toggle_mode(true);
tool_triangle->set_button_group(bg);
top_hb->add_child(tool_triangle);
- tool_triangle->set_tooltip(TTR("Create triangles by connecting points."));
+ tool_triangle->set_tooltip_text(TTR("Create triangles by connecting points."));
tool_triangle->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(2));
tool_erase_sep = memnew(VSeparator);
@@ -864,7 +900,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_erase = memnew(Button);
tool_erase->set_flat(true);
top_hb->add_child(tool_erase);
- tool_erase->set_tooltip(TTR("Erase points and triangles."));
+ tool_erase->set_tooltip_text(TTR("Erase points and triangles."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_erase_selected));
tool_erase->set_disabled(true);
@@ -875,7 +911,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
top_hb->add_child(auto_triangles);
auto_triangles->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled));
auto_triangles->set_toggle_mode(true);
- auto_triangles->set_tooltip(TTR("Generate blend triangles automatically (instead of manually)"));
+ auto_triangles->set_tooltip_text(TTR("Generate blend triangles automatically (instead of manually)"));
top_hb->add_child(memnew(VSeparator));
@@ -884,7 +920,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
snap->set_toggle_mode(true);
top_hb->add_child(snap);
snap->set_pressed(true);
- snap->set_tooltip(TTR("Enable snap and show grid."));
+ snap->set_tooltip_text(TTR("Enable snap and show grid."));
snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_snap_toggled));
snap_x = memnew(SpinBox);
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index 26471df051..1f015a1804 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -40,10 +40,13 @@
#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
+ bool read_only = false;
PanelContainer *panel = nullptr;
Button *tool_blend = nullptr;
@@ -82,7 +85,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
bool updating;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
static AnimationNodeBlendSpace2DEditor *singleton;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 79be2d04b3..f1e6c70549 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
@@ -133,6 +134,8 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
GraphNode *node = memnew(GraphNode);
graph->add_child(node);
+ node->set_draggable(!read_only);
+
Ref<AnimationNode> agnode = blend_tree->get_node(E);
ERR_CONTINUE(!agnode.is_valid());
@@ -145,9 +148,10 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (String(E) != "output") {
LineEdit *name = memnew(LineEdit);
name->set_text(E);
+ name->set_editable(!read_only);
name->set_expand_to_text_length_enabled(true);
node->add_child(name);
- node->set_slot(0, false, 0, Color(), true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
+ node->set_slot(0, false, 0, Color(), true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed).bind(agnode), CONNECT_DEFERRED);
name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(name, agnode), CONNECT_DEFERRED);
base = 1;
@@ -159,7 +163,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
Label *in_name = memnew(Label);
node->add_child(in_name);
in_name->set_text(agnode->get_input_name(i));
- node->set_slot(base + i, true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
+ node->set_slot(base + i, true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
}
List<PropertyInfo> pinfo;
@@ -171,6 +175,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F.type, base_path, F.hint, F.hint_string, F.usage);
if (prop) {
+ prop->set_read_only(read_only);
prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path);
prop->update_property();
prop->set_name_split_ratio(0);
@@ -194,12 +199,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (agnode->has_filter()) {
node->add_child(memnew(HSeparator));
- Button *edit_filters = memnew(Button);
- edit_filters->set_text(TTR("Edit Filters"));
- edit_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
- node->add_child(edit_filters);
- edit_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_edit_filters).bind(E), CONNECT_DEFERRED);
- edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
+ Button *inspect_filters = memnew(Button);
+ if (read_only) {
+ inspect_filters->set_text(TTR("Inspect Filters"));
+ } else {
+ inspect_filters->set_text(TTR("Edit Filters"));
+ }
+ inspect_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
+ node->add_child(inspect_filters);
+ inspect_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_inspect_filters).bind(E), CONNECT_DEFERRED);
+ inspect_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
}
Ref<AnimationNodeAnimation> anim = agnode;
@@ -207,6 +216,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
MenuButton *mb = memnew(MenuButton);
mb->set_text(anim->get_animation());
mb->set_icon(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")));
+ mb->set_disabled(read_only);
Array options;
node->add_child(memnew(HSeparator));
@@ -232,7 +242,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
}
}
- pb->set_percent_visible(false);
+ pb->set_show_percentage(false);
pb->set_custom_minimum_size(Vector2(0, 14) * EDSCALE);
animations[E] = pb;
node->add_child(pb);
@@ -369,10 +379,18 @@ void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2
}
void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+ if (read_only) {
+ return;
+ }
+
_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) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_from);
if (node.is_valid()) {
from_node = p_from;
@@ -381,6 +399,10 @@ void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, in
}
void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_to);
if (node.is_valid()) {
to_node = p_to;
@@ -401,6 +423,10 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve
}
void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
AnimationNodeBlendTree::ConnectionError err = blend_tree->can_connect_node(p_to, p_to_index, p_from);
if (err != AnimationNodeBlendTree::CONNECTION_OK) {
@@ -417,6 +443,10 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
}
void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);
updating = true;
@@ -444,6 +474,10 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
}
void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
+ if (read_only) {
+ return;
+ }
+
undo_redo->create_action(TTR("Delete Node"));
undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which);
undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which));
@@ -463,6 +497,10 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
}
void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<StringName> &p_nodes) {
+ if (read_only) {
+ return;
+ }
+
List<StringName> to_erase;
if (p_nodes.is_empty()) {
@@ -494,6 +532,10 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String
}
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
+ if (read_only) {
+ return;
+ }
+
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
ERR_FAIL_COND(!gn);
@@ -678,7 +720,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
}
}
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
@@ -691,7 +733,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -713,7 +755,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, types_text);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -726,7 +768,15 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
return true;
}
-void AnimationNodeBlendTreeEditor::_edit_filters(const String &p_which) {
+void AnimationNodeBlendTreeEditor::_inspect_filters(const String &p_which) {
+ if (read_only) {
+ filter_dialog->set_title(TTR("Inspect Filtered Tracks:"));
+ } else {
+ filter_dialog->set_title(TTR("Edit Filtered Tracks:"));
+ }
+
+ filter_enabled->set_disabled(read_only);
+
Ref<AnimationNode> anode = blend_tree->get_node(p_which);
ERR_FAIL_COND(!anode.is_valid());
@@ -750,7 +800,7 @@ void AnimationNodeBlendTreeEditor::_update_editor_settings() {
}
void AnimationNodeBlendTreeEditor::_update_theme() {
- error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
}
@@ -837,6 +887,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
+ if (read_only) {
+ return;
+ }
+
if (updating) {
return;
}
@@ -943,13 +997,20 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
blend_tree = p_node;
+ read_only = false;
+
if (blend_tree.is_null()) {
hide();
} else {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree);
+
blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
_update_graph();
}
+
+ add_node->set_disabled(read_only);
+ graph->set_arrange_nodes_button_hidden(read_only);
}
AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
@@ -985,6 +1046,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
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).bind(false));
+ add_node->set_disabled(read_only);
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 18199676b8..30a54930a2 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -41,11 +41,15 @@
class ProgressBar;
class EditorFileDialog;
+class EditorUndoRedoManager;
class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
+
+ bool read_only = false;
+
GraphEdit *graph = nullptr;
MenuButton *add_node = nullptr;
Vector2 position_from_popup_menu;
@@ -54,7 +58,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
AcceptDialog *filter_dialog = nullptr;
Tree *filters = nullptr;
@@ -105,7 +109,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _delete_nodes_request(const TypedArray<StringName> &p_nodes);
bool _update_filters(const Ref<AnimationNode> &anode);
- void _edit_filters(const String &p_which);
+ void _inspect_filters(const String &p_which);
void _filter_edited();
void _filter_toggled();
Ref<AnimationNode> _filter_edit;
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index cae33edecb..2d20c0cca7 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
void AnimationLibraryEditor::set_animation_player(Object *p_player) {
player = p_player;
@@ -92,7 +93,7 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) {
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<EditorUndoRedoManager> 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());
@@ -109,7 +110,7 @@ void AnimationLibraryEditor::_add_library_confirm() {
} else {
String lib_name = add_library_name->get_text();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
Ref<AnimationLibrary> al;
al.instantiate();
@@ -149,13 +150,35 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
}
switch (p_id) {
case FILE_MENU_SAVE_LIBRARY: {
- if (al->get_path().is_resource_file()) {
+ if (al->get_path().is_resource_file() && !FileAccess::exists(al->get_path() + ".import")) {
EditorNode::get_singleton()->save_resource(al);
break;
}
[[fallthrough]];
}
case FILE_MENU_SAVE_AS_LIBRARY: {
+ // Check if we're allowed to save this
+ {
+ String al_path = al->get_path();
+ if (!al_path.is_resource_file()) {
+ int srpos = al_path.find("::");
+ if (srpos != -1) {
+ String base = al_path.substr(0, srpos);
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ error_dialog->set_text(TTR("This animation library can't be saved because it does not belong to the edited scene. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ } else {
+ if (FileAccess::exists(al_path + ".import")) {
+ error_dialog->set_text(TTR("This animation library can't be saved because it was imported from another file. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ }
+
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Save Library"));
if (al->get_path().is_resource_file()) {
@@ -175,10 +198,19 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
} break;
case FILE_MENU_MAKE_LIBRARY_UNIQUE: {
StringName lib_name = file_dialog_library;
+ List<StringName> animation_list;
+
+ Ref<AnimationLibrary> ald = memnew(AnimationLibrary);
+ al->get_animation_list(&animation_list);
+ for (const StringName &animation_name : animation_list) {
+ Ref<Animation> animation = al->get_animation(animation_name);
+ if (EditorNode::get_singleton()->is_resource_read_only(animation)) {
+ animation = animation->duplicate();
+ }
+ ald->add_animation(animation_name, animation);
+ }
- Ref<AnimationLibrary> ald = al->duplicate();
-
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> 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);
@@ -188,19 +220,43 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
undo_redo->add_undo_method(this, "_update_editor", player);
undo_redo->commit_action();
+ update_tree();
+
} 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()) {
+ if (anim->get_path().is_resource_file() && !FileAccess::exists(anim->get_path() + ".import")) {
EditorNode::get_singleton()->save_resource(anim);
break;
}
[[fallthrough]];
}
case FILE_MENU_SAVE_AS_ANIMATION: {
+ // Check if we're allowed to save this
+ {
+ String anim_path = al->get_path();
+ if (!anim_path.is_resource_file()) {
+ int srpos = anim_path.find("::");
+ if (srpos != -1) {
+ String base = anim_path.substr(0, srpos);
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ error_dialog->set_text(TTR("This animation can't be saved because it does not belong to the edited scene. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ } else {
+ if (FileAccess::exists(anim_path + ".import")) {
+ error_dialog->set_text(TTR("This animation can't be saved because it was imported from another file. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ }
+
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Save Animation"));
if (anim->get_path().is_resource_file()) {
@@ -223,7 +279,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
Ref<Animation> animd = anim->duplicate();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> 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);
@@ -232,6 +288,8 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
undo_redo->add_do_method(this, "_update_editor", player);
undo_redo->add_undo_method(this, "_update_editor", player);
undo_redo->commit_action();
+
+ update_tree();
} break;
case FILE_MENU_EDIT_ANIMATION: {
EditorNode::get_singleton()->push_item(anim.ptr());
@@ -269,7 +327,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> 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);
@@ -307,7 +365,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> 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);
@@ -323,7 +381,7 @@ void AnimationLibraryEditor::_load_file(String p_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();
+ Ref<EditorUndoRedoManager> 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());
@@ -344,7 +402,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
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();
+ Ref<EditorUndoRedoManager> 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());
@@ -362,7 +420,7 @@ void AnimationLibraryEditor::_item_renamed() {
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();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) {
restore_text = true;
@@ -476,7 +534,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
name = base_name + " (" + itos(attempt) + ")";
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> 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);
@@ -502,7 +560,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
file_dialog_library = lib_name;
} break;
case LIB_BUTTON_DELETE: {
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> 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);
@@ -543,7 +601,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
} break;
case ANIM_BUTTON_DELETE: {
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> 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);
@@ -577,19 +635,45 @@ void AnimationLibraryEditor::update_tree() {
} 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 {
+ bool animation_library_is_foreign = false;
+ String al_path = al->get_path();
+ if (!al_path.is_resource_file()) {
libitem->set_text(1, TTR("[built-in]"));
+ libitem->set_tooltip_text(1, al_path);
+ int srpos = al_path.find("::");
+ if (srpos != -1) {
+ String base = al_path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ animation_library_is_foreign = true;
+ libitem->set_text(1, TTR("[foreign]"));
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ animation_library_is_foreign = true;
+ libitem->set_text(1, TTR("[imported]"));
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(al_path + ".import")) {
+ animation_library_is_foreign = true;
+ libitem->set_text(1, TTR("[imported]"));
+ } else {
+ libitem->set_text(1, al_path.get_file());
+ }
}
+
+ libitem->set_editable(0, !animation_library_is_foreign);
+ 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, animation_library_is_foreign, TTR("Add Animation to Library"));
+ libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, animation_library_is_foreign, TTR("Load animation from file and add to library"));
+ libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, animation_library_is_foreign, TTR("Paste Animation to Library from clipboard"));
+
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"));
@@ -600,20 +684,38 @@ void AnimationLibraryEditor::update_tree() {
for (const StringName &L : animations) {
TreeItem *anitem = tree->create_item(libitem);
anitem->set_text(0, L);
- anitem->set_editable(0, true);
+ anitem->set_editable(0, !animation_library_is_foreign);
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);
+ anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, animation_library_is_foreign, TTR("Copy animation to clipboard"));
- if (anim->get_path().is_resource_file()) {
- anitem->set_text(1, anim->get_path().get_file());
- anitem->set_tooltip(1, anim->get_path());
- } else {
+ Ref<Animation> anim = al->get_animation(L);
+ String anim_path = anim->get_path();
+ if (!anim_path.is_resource_file()) {
anitem->set_text(1, TTR("[built-in]"));
+ anitem->set_tooltip_text(1, anim_path);
+ int srpos = anim_path.find("::");
+ if (srpos != -1) {
+ String base = anim_path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ anitem->set_text(1, TTR("[foreign]"));
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ anitem->set_text(1, TTR("[imported]"));
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(anim_path + ".import")) {
+ anitem->set_text(1, TTR("[imported]"));
+ } else {
+ anitem->set_text(1, anim_path.get_file());
+ }
}
- 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"));
+ anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk"));
+ anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library"));
}
}
}
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index ebd7525bb8..5406aada09 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -55,7 +55,7 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) {
set_process(false);
- track_editor->set_animation(Ref<Animation>());
+ track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr);
track_editor->show_select_node_warning(true);
_update_player();
@@ -283,7 +283,9 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
Ref<Animation> anim = player->get_animation(current);
{
- track_editor->set_animation(anim);
+ bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim);
+
+ track_editor->set_animation(anim, animation_library_is_foreign);
Node *root = player->get_node(player->get_root());
if (root) {
track_editor->set_root(root);
@@ -292,7 +294,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
frame->set_max((double)anim->get_length());
} else {
- track_editor->set_animation(Ref<Animation>());
+ track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr);
}
@@ -751,14 +753,17 @@ void AnimationPlayerEditor::_animation_edit() {
String current = _get_current();
if (current != String()) {
Ref<Animation> anim = player->get_animation(current);
- track_editor->set_animation(anim);
+
+ bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim);
+
+ track_editor->set_animation(anim, animation_library_is_foreign);
Node *root = player->get_node(player->get_root());
if (root) {
track_editor->set_root(root);
}
} else {
- track_editor->set_animation(Ref<Animation>());
+ track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr);
}
}
@@ -800,25 +805,32 @@ void AnimationPlayerEditor::_update_player() {
animation->clear();
+ tool_anim->set_disabled(player == nullptr);
+ pin->set_disabled(player == nullptr);
+
if (!player) {
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
return;
}
List<StringName> libraries;
- if (player) {
- player->get_animation_library_list(&libraries);
- }
+ player->get_animation_library_list(&libraries);
int active_idx = -1;
bool no_anims_found = true;
+ bool foreign_global_anim_lib = false;
for (const StringName &K : libraries) {
if (K != StringName()) {
animation->add_separator(K);
}
+ // Check if the global library is foreign since we want to disable options for adding/remove/renaming animations if it is.
Ref<AnimationLibrary> library = player->get_animation_library(K);
+ if (K == "") {
+ foreign_global_anim_lib = EditorNode::get_singleton()->is_resource_read_only(library);
+ }
+
List<StringName> animlist;
library->get_animation_list(&animlist);
@@ -835,7 +847,13 @@ void AnimationPlayerEditor::_update_player() {
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)
+#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), foreign_global_anim_lib)
+
+ ITEM_CHECK_DISABLED(TOOL_NEW_ANIM);
+
+#undef ITEM_CHECK_DISABLED
+
+#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 || foreign_global_anim_lib)
ITEM_CHECK_DISABLED(TOOL_DUPLICATE_ANIM);
ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM);
@@ -853,10 +871,8 @@ void AnimationPlayerEditor::_update_player() {
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();
@@ -877,7 +893,10 @@ void AnimationPlayerEditor::_update_player() {
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);
+
+ bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim);
+
+ track_editor->set_animation(anim, animation_library_is_foreign);
Node *root = player->get_node(player->get_root());
if (root) {
track_editor->set_root(root);
@@ -950,6 +969,10 @@ void AnimationPlayerEditor::_update_name_dialog_library_dropdown() {
}
}
+void AnimationPlayerEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
if (player && pin->is_pressed()) {
return; // Ignore, pinned.
@@ -1426,19 +1449,19 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// Render every past/future step with the capture shader.
RS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid());
- onion.capture.material->set_shader_uniform("bkg_color", GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
- onion.capture.material->set_shader_uniform("differences_only", onion.differences_only);
- onion.capture.material->set_shader_uniform("present", onion.differences_only ? RS::get_singleton()->viewport_get_texture(present_rid) : RID());
+ onion.capture.material->set_shader_parameter("bkg_color", GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+ onion.capture.material->set_shader_parameter("differences_only", onion.differences_only);
+ onion.capture.material->set_shader_parameter("present", onion.differences_only ? RS::get_singleton()->viewport_get_texture(present_rid) : RID());
int step_off_a = onion.past ? -onion.steps : 0;
int step_off_b = onion.future ? onion.steps : 0;
int cidx = 0;
- onion.capture.material->set_shader_uniform("dir_color", onion.force_white_modulate ? Color(1, 1, 1) : Color(EDITOR_GET("editors/animation/onion_layers_past_color")));
+ onion.capture.material->set_shader_parameter("dir_color", onion.force_white_modulate ? Color(1, 1, 1) : Color(EDITOR_GET("editors/animation/onion_layers_past_color")));
for (int step_off = step_off_a; step_off <= step_off_b; step_off++) {
if (step_off == 0) {
// Skip present step and switch to the color of future.
if (!onion.force_white_modulate) {
- onion.capture.material->set_shader_uniform("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color"));
+ onion.capture.material->set_shader_parameter("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color"));
}
continue;
}
@@ -1547,28 +1570,28 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
play_bw_from = memnew(Button);
play_bw_from->set_flat(true);
- play_bw_from->set_tooltip(TTR("Play selected animation backwards from current pos. (A)"));
+ play_bw_from->set_tooltip_text(TTR("Play selected animation backwards from current pos. (A)"));
hb->add_child(play_bw_from);
play_bw = memnew(Button);
play_bw->set_flat(true);
- play_bw->set_tooltip(TTR("Play selected animation backwards from end. (Shift+A)"));
+ play_bw->set_tooltip_text(TTR("Play selected animation backwards from end. (Shift+A)"));
hb->add_child(play_bw);
stop = memnew(Button);
stop->set_flat(true);
stop->set_toggle_mode(true);
hb->add_child(stop);
- stop->set_tooltip(TTR("Stop animation playback. (S)"));
+ stop->set_tooltip_text(TTR("Stop animation playback. (S)"));
play = memnew(Button);
play->set_flat(true);
- play->set_tooltip(TTR("Play selected animation from start. (Shift+D)"));
+ play->set_tooltip_text(TTR("Play selected animation from start. (Shift+D)"));
hb->add_child(play);
play_from = memnew(Button);
play_from->set_flat(true);
- play_from->set_tooltip(TTR("Play selected animation from current pos. (D)"));
+ play_from->set_tooltip_text(TTR("Play selected animation from current pos. (D)"));
hb->add_child(play_from);
frame = memnew(SpinBox);
@@ -1576,7 +1599,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
frame->set_custom_minimum_size(Size2(80, 0) * EDSCALE);
frame->set_stretch_ratio(2);
frame->set_step(0.0001);
- frame->set_tooltip(TTR("Animation position (in seconds)."));
+ frame->set_tooltip_text(TTR("Animation position (in seconds)."));
hb->add_child(memnew(VSeparator));
@@ -1584,7 +1607,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
hb->add_child(scale);
scale->set_h_size_flags(SIZE_EXPAND_FILL);
scale->set_stretch_ratio(1);
- scale->set_tooltip(TTR("Scale animation playback globally for the node."));
+ scale->set_tooltip_text(TTR("Scale animation playback globally for the node."));
scale->hide();
delete_dialog = memnew(ConfirmationDialog);
@@ -1594,7 +1617,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
tool_anim = memnew(MenuButton);
tool_anim->set_shortcut_context(this);
tool_anim->set_flat(false);
- tool_anim->set_tooltip(TTR("Animation Tools"));
+ tool_anim->set_tooltip_text(TTR("Animation Tools"));
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();
@@ -1613,13 +1636,13 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
animation = memnew(OptionButton);
hb->add_child(animation);
animation->set_h_size_flags(SIZE_EXPAND_FILL);
- animation->set_tooltip(TTR("Display list of animations in player."));
+ animation->set_tooltip_text(TTR("Display list of animations in player."));
animation->set_clip_text(true);
autoplay = memnew(Button);
autoplay->set_flat(true);
hb->add_child(autoplay);
- autoplay->set_tooltip(TTR("Autoplay on Load"));
+ autoplay->set_tooltip_text(TTR("Autoplay on Load"));
hb->add_child(memnew(VSeparator));
@@ -1632,12 +1655,12 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
onion_toggle = memnew(Button);
onion_toggle->set_flat(true);
onion_toggle->set_toggle_mode(true);
- onion_toggle->set_tooltip(TTR("Enable Onion Skinning"));
+ onion_toggle->set_tooltip_text(TTR("Enable Onion Skinning"));
onion_toggle->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu).bind(ONION_SKINNING_ENABLE));
hb->add_child(onion_toggle);
onion_skinning = memnew(MenuButton);
- onion_skinning->set_tooltip(TTR("Onion Skinning Options"));
+ onion_skinning->set_tooltip_text(TTR("Onion Skinning Options"));
onion_skinning->get_popup()->add_separator(TTR("Directions"));
// TRANSLATORS: Opposite of "Future", refers to a direction in animation onion skinning.
onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST);
@@ -1660,7 +1683,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
pin = memnew(Button);
pin->set_flat(true);
pin->set_toggle_mode(true);
- pin->set_tooltip(TTR("Pin AnimationPlayer"));
+ pin->set_tooltip_text(TTR("Pin AnimationPlayer"));
hb->add_child(pin);
pin->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed));
@@ -1830,7 +1853,7 @@ void AnimationPlayerEditorPlugin::_update_keying() {
}
void AnimationPlayerEditorPlugin::edit(Object *p_object) {
- anim_editor->set_undo_redo(&get_undo_redo());
+ anim_editor->set_undo_redo(get_undo_redo());
if (!p_object) {
return;
}
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 3b1de070fa..a37a9debef 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -41,6 +41,7 @@
#include "scene/gui/texture_button.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
class AnimationPlayerEditorPlugin;
class AnimationPlayerEditor : public VBoxContainer {
@@ -100,7 +101,7 @@ class AnimationPlayerEditor : public VBoxContainer {
LineEdit *name = nullptr;
OptionButton *library = nullptr;
Label *name_title = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<Texture2D> autoplay_icon;
Ref<Texture2D> reset_icon;
@@ -233,7 +234,7 @@ public:
void ensure_visibility();
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(AnimationPlayer *p_player);
void forward_force_draw_over_viewport(Control *p_overlay);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 473450b292..461326a47b 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
@@ -55,7 +56,11 @@ bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
state_machine = p_node;
+ read_only = false;
+
if (state_machine.is_valid()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(state_machine);
+
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_transition_index = -1;
@@ -65,6 +70,9 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
_update_mode();
_update_graph();
}
+
+ tool_create->set_disabled(read_only);
+ tool_connect->set_disabled(read_only);
}
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
@@ -76,7 +84,9 @@ 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::KEY_DELETE && !k->is_echo()) {
if (selected_node != StringName() || !selected_nodes.is_empty() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -94,9 +104,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseButton> mb = p_event;
// 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());
+ if (!read_only) {
+ 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
@@ -116,26 +128,28 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
//travel
playback->travel(node_rects[i].node_name);
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
return;
}
- 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"));
+ if (!read_only) {
+ 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();
+ 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_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();
- name_edit->grab_focus();
- name_edit->select_all();
+ 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();
+ name_edit->grab_focus();
+ name_edit->select_all();
- prev_name = node_rects[i].node_name;
- return;
+ prev_name = node_rects[i].node_name;
+ return;
+ }
}
if (node_rects[i].edit.has_point(mb->get_position())) { //edit name
@@ -154,7 +168,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<AnimationNode> anode = state_machine->get_node(selected_node);
EditorNode::get_singleton()->push_item(anode.ptr(), "", true);
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
dragging_selected_attempt = true;
dragging_selected = false;
drag_from = mb->get_position();
@@ -214,7 +228,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
_update_mode();
}
@@ -245,7 +259,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
dragging_selected_attempt = false;
dragging_selected = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
// Connect nodes
@@ -253,6 +267,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
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;
+ connection_follows_cursor = true;
connecting_from = node_rects[i].node_name;
connecting_to = mb->get_position();
connecting_to_node = StringName();
@@ -282,7 +297,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
_open_menu(mb->get_position());
}
connecting_to_node = StringName();
- state_machine_draw->update();
+ connection_follows_cursor = false;
+ state_machine_draw->queue_redraw();
}
// Start box selecting
@@ -305,7 +321,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
// 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();
+ state_machine_draw->queue_redraw();
_update_mode();
}
@@ -318,10 +334,10 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while connecting
- if (mm.is_valid() && connecting) {
+ if (mm.is_valid() && connecting && connection_follows_cursor && !read_only) {
connecting_to = mm->get_position();
connecting_to_node = StringName();
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].node_name != connecting_from && node_rects[i].node.has_point(connecting_to)) { //select node since nothing else was selected
@@ -332,7 +348,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while moving a node
- if (mm.is_valid() && dragging_selected_attempt) {
+ if (mm.is_valid() && dragging_selected_attempt && !read_only) {
dragging_selected = true;
drag_ofs = mm->get_position() - drag_from;
snap_x = StringName();
@@ -368,7 +384,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
// Move mouse while moving box select
@@ -398,7 +414,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
if (mm.is_valid()) {
@@ -428,7 +444,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (new_over_node != over_node || new_over_node_what != over_node_what) {
over_node = new_over_node;
over_node_what = new_over_node_what;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
// set tooltip for transition
@@ -462,9 +478,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
to = String(transition_lines[closest].multi_transitions[i].to_node);
tooltip += "\n" + from + " -> " + to;
}
- state_machine_draw->set_tooltip(tooltip);
+ state_machine_draw->set_tooltip_text(tooltip);
} else {
- state_machine_draw->set_tooltip("");
+ state_machine_draw->set_tooltip_text("");
}
}
}
@@ -477,17 +493,21 @@ 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;
+ if (!read_only) {
+ // 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);
+
+ 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)) {
+ if (state_machine->can_edit_node(node_rects[i].node_name)) {
+ cursor_shape = Control::CURSOR_IBEAM;
+ }
+ }
+ break;
}
- break;
}
}
return cursor_shape;
@@ -602,7 +622,7 @@ void AnimationNodeStateMachineEditor::_group_selected_nodes() {
selected_nodes.clear();
selected_nodes.insert(group_name);
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
accept_event();
_update_mode();
}
@@ -703,7 +723,7 @@ void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() {
if (find) {
selected_nodes = new_selected_nodes;
selected_node = StringName();
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
accept_event();
_update_mode();
}
@@ -784,8 +804,7 @@ void AnimationNodeStateMachineEditor::_open_connect_menu(const Vector2 &p_positi
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);
+ _create_submenu(connect_menu, state_machine, connecting_to_node, connecting_to_node, true);
}
connect_menu->add_submenu_item(TTR("To") + " Animation", connecting_to_node);
@@ -817,6 +836,10 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
String prev_path;
Vector<Ref<AnimationNodeStateMachine>> parents = p_parents;
+ if (from_root && p_nodesm->get_prev_state_machine() == nullptr) {
+ return false;
+ }
+
if (from_root) {
AnimationNodeStateMachine *prev = p_nodesm->get_prev_state_machine();
@@ -826,6 +849,8 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
prev_path += "../";
prev = prev->get_prev_state_machine();
}
+ end_menu->add_item("Root", nodes_to_connect.size());
+ nodes_to_connect.push_back(prev_path + state_machine->end_node);
prev_path.remove_at(prev_path.size() - 1);
}
@@ -856,22 +881,22 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
}
if (ansm.is_valid()) {
- bool found = false;
+ bool parent_found = false;
for (int i = 0; i < parents.size(); i++) {
if (parents[i] == ansm) {
path = path.replace_first("/../" + E, "");
- found = true;
+ parent_found = true;
break;
}
}
- if (!found) {
- state_machine_menu->add_item(E, nodes_to_connect.size());
- nodes_to_connect.push_back(path);
- } else {
+ if (parent_found) {
end_menu->add_item(E, nodes_to_connect.size());
nodes_to_connect.push_back(path + "/" + state_machine->end_node);
+ } else {
+ state_machine_menu->add_item(E, nodes_to_connect.size());
+ nodes_to_connect.push_back(path);
}
if (_create_submenu(nodes_menu, ansm, E, path, false, parents)) {
@@ -891,7 +916,7 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
void AnimationNodeStateMachineEditor::_stop_connecting() {
connecting = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_delete_selected() {
@@ -1000,17 +1025,15 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
}
updating = true;
- undo_redo->create_action(TTR("Add Node"));
+ undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos);
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();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
@@ -1028,17 +1051,15 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
}
updating = true;
- undo_redo->create_action(TTR("Add Node"));
+ undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos);
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();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_connect_to(int p_index) {
@@ -1060,16 +1081,16 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
if (!p_nested_action) {
updating = true;
+ undo_redo->create_action(TTR("Add Transition"));
}
- 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) {
+ undo_redo->commit_action();
updating = false;
}
@@ -1457,7 +1478,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
v_scroll->set_value(state_machine->get_graph_offset().y);
updating = false;
- state_machine_play_pos->update();
+ state_machine_play_pos->queue_redraw();
}
void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
@@ -1519,7 +1540,7 @@ void AnimationNodeStateMachineEditor::_update_graph() {
updating = true;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
updating = false;
}
@@ -1530,9 +1551,9 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
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_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), 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")));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
tool_create->set_icon(get_theme_icon(SNAME("ToolAddNode"), SNAME("EditorIcons")));
@@ -1591,34 +1612,34 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
}
if (tidx == -1) { //missing transition, should redraw
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
break;
}
if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) {
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
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();
+ state_machine_draw->queue_redraw();
break;
}
}
@@ -1653,14 +1674,14 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
}
}
- //update if travel state changed
+ //redraw 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();
+ state_machine_draw->queue_redraw();
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();
+ state_machine_play_pos->queue_redraw();
}
{
@@ -1685,7 +1706,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
if (last_play_pos != play_pos) {
last_play_pos = play_pos;
- state_machine_play_pos->update();
+ state_machine_play_pos->queue_redraw();
}
} break;
@@ -1731,7 +1752,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
name_edit_popup->hide();
updating = false;
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_name_edited_focus_out() {
@@ -1748,7 +1769,7 @@ void AnimationNodeStateMachineEditor::_scroll_changed(double) {
}
state_machine->set_graph_offset(Vector2(h_scroll->get_value(), v_scroll->get_value()));
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action) {
@@ -1839,7 +1860,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
selected_multi_transition = TransitionLine();
}
- state_machine_draw->update();
+ state_machine_draw->queue_redraw();
}
void AnimationNodeStateMachineEditor::_update_mode() {
@@ -1847,9 +1868,9 @@ void AnimationNodeStateMachineEditor::_update_mode() {
tool_erase_hb->show();
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.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node);
- tool_erase->set_disabled(nothing_selected || start_end_selected);
+ tool_erase->set_disabled(nothing_selected || start_end_selected || read_only);
- if (selected_nodes.is_empty() || start_end_selected) {
+ if (selected_nodes.is_empty() || start_end_selected || read_only) {
tool_group->set_disabled(true);
tool_group->set_visible(true);
tool_ungroup->set_visible(false);
@@ -1899,7 +1920,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: 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->set_tooltip_text(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), CONNECT_DEFERRED);
tool_create = memnew(Button);
@@ -1907,7 +1928,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
top_hb->add_child(tool_create);
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
- tool_create->set_tooltip(TTR("Create new nodes."));
+ tool_create->set_tooltip_text(TTR("Create new nodes."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED);
tool_connect = memnew(Button);
@@ -1915,7 +1936,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
top_hb->add_child(tool_connect);
tool_connect->set_toggle_mode(true);
tool_connect->set_button_group(bg);
- tool_connect->set_tooltip(TTR("Connect nodes."));
+ tool_connect->set_tooltip_text(TTR("Connect nodes."));
tool_connect->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED);
tool_erase_hb = memnew(HBoxContainer);
@@ -1924,21 +1945,21 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_group = memnew(Button);
tool_group->set_flat(true);
- tool_group->set_tooltip(TTR("Group Selected Node(s)") + " (Ctrl+G)");
+ tool_group->set_tooltip_text(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->set_tooltip_text(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->set_tooltip_text(TTR("Remove selected node or transition."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected).bind(false));
tool_erase->set_disabled(true);
tool_erase_hb->add_child(tool_erase);
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index 165940e639..d0828a5f52 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -40,12 +40,15 @@
#include "scene/gui/tree.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeStateMachine> state_machine;
+ bool read_only = false;
+
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_connect = nullptr;
@@ -76,7 +79,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
bool updating = false;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
static AnimationNodeStateMachineEditor *singleton;
@@ -97,8 +100,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Vector2 add_node_pos;
- ConfirmationDialog *delete_window;
- Tree *delete_tree;
+ ConfirmationDialog *delete_window = nullptr;
+ Tree *delete_tree = nullptr;
bool box_selecting = false;
Point2 box_selecting_from;
@@ -114,6 +117,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
StringName snap_y;
bool connecting = false;
+ bool connection_follows_cursor = false;
StringName connecting_from;
Vector2 connecting_to;
StringName connecting_to_node;
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index bce4c9de8e..ed231c446b 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -59,10 +59,11 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) {
Vector<String> path;
if (tree && tree->has_meta("_tree_edit_path")) {
path = tree->get_meta("_tree_edit_path");
- edit_path(path);
} else {
current_root = ObjectID();
}
+
+ edit_path(path);
}
void AnimationTreeEditor::_path_button_pressed(int p_path) {
@@ -129,6 +130,11 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) {
} else {
current_root = ObjectID();
edited_path = button_path;
+
+ for (int i = 0; i < editors.size(); i++) {
+ editors[i]->edit(Ref<AnimationNode>());
+ editors[i]->hide();
+ }
}
_update_path();
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 8ee162d085..436113093f 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -32,7 +32,7 @@
#include "core/input/input.h"
#include "core/io/json.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/os/keyboard.h"
#include "core/version.h"
#include "editor/editor_file_dialog.h"
@@ -101,10 +101,7 @@ void EditorAssetLibraryItem::_bind_methods() {
EditorAssetLibraryItem::EditorAssetLibraryItem() {
Ref<StyleBoxEmpty> border;
border.instantiate();
- border->set_default_margin(SIDE_LEFT, 5 * EDSCALE);
- border->set_default_margin(SIDE_RIGHT, 5 * EDSCALE);
- border->set_default_margin(SIDE_BOTTOM, 5 * EDSCALE);
- border->set_default_margin(SIDE_TOP, 5 * EDSCALE);
+ border->set_default_margin_all(5 * EDSCALE);
add_theme_style_override("panel", border);
HBoxContainer *hb = memnew(HBoxContainer);
@@ -324,7 +321,7 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
status->set_text(TTR("Can't connect."));
} break;
case HTTPRequest::RESULT_CANT_CONNECT:
- case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR: {
+ case HTTPRequest::RESULT_TLS_HANDSHAKE_ERROR: {
error_text = TTR("Can't connect to host:") + " " + host;
status->set_text(TTR("Can't connect."));
} break;
@@ -487,7 +484,7 @@ void EditorAssetLibraryItemDownload::_make_request() {
retry_button->hide();
download->cancel_request();
- download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
+ download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_asset_" + itos(asset_id)) + ".zip");
Error err = download->request(host);
if (err != OK) {
@@ -577,24 +574,26 @@ 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();
+ error_label->move_to_front();
} 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")));
- 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")));
+ library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
+ downloads_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), 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()) {
+#ifndef ANDROID_ENABLED
// Focus the search box automatically when switching to the Templates tab (in the Project Manager)
// or switching to the AssetLib tab (in the editor).
// The Project Manager's project filter box is automatically focused in the project manager code.
filter->grab_focus();
+#endif
if (initial_loading) {
_repository_changed(0); // Update when shown for the first time.
@@ -649,7 +648,7 @@ void EditorAssetLibrary::shortcut_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed()) {
- if (key->get_keycode_with_modifiers() == (KeyModifierMask::CMD | Key::F) && is_visible_in_tree()) {
+ if (key->is_match(InputEventKey::create_reference(KeyModifierMask::CMD_OR_CTRL | Key::F))) {
filter->grab_focus();
filter->select_all();
accept_event();
@@ -730,7 +729,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
PackedByteArray image_data = p_data;
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());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
if (file.is_valid()) {
@@ -804,7 +803,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) {
for (int i = 0; i < headers.size(); i++) {
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 cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("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();
Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE);
if (file.is_valid()) {
@@ -846,7 +845,7 @@ void EditorAssetLibrary::_update_image_queue() {
List<int> to_delete;
for (KeyValue<int, ImageQueue> &E : image_queue) {
if (!E.value.active && current_images < max_images) {
- String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + E.value.image_url.md5_text());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + E.value.image_url.md5_text());
Vector<String> headers;
if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) {
@@ -1100,7 +1099,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH: {
error_label->set_text(TTR("Connection error, please try again."));
} break;
- case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR:
+ case HTTPRequest::RESULT_TLS_HANDSHAKE_ERROR:
case HTTPRequest::RESULT_CANT_CONNECT: {
error_label->set_text(TTR("Can't connect to host:") + " " + host);
} break;
@@ -1508,10 +1507,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
Ref<StyleBoxEmpty> border2;
border2.instantiate();
- border2->set_default_margin(SIDE_LEFT, 15 * EDSCALE);
- border2->set_default_margin(SIDE_RIGHT, 35 * EDSCALE);
- border2->set_default_margin(SIDE_BOTTOM, 15 * EDSCALE);
- border2->set_default_margin(SIDE_TOP, 15 * EDSCALE);
+ border2->set_default_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE);
PanelContainer *library_vb_border = memnew(PanelContainer);
library_scroll->add_child(library_vb_border);
@@ -1595,12 +1591,12 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
///////
bool AssetLibraryEditorPlugin::is_available() {
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
// Asset Library can't work on Web editor for now as most assets are sourced
// directly from GitHub which does not set CORS.
return false;
#else
- return StreamPeerSSL::is_available();
+ return StreamPeerTLS::is_available();
#endif
}
@@ -1615,7 +1611,7 @@ void AssetLibraryEditorPlugin::make_visible(bool p_visible) {
AssetLibraryEditorPlugin::AssetLibraryEditorPlugin() {
addon_library = memnew(EditorAssetLibrary);
addon_library->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- EditorNode::get_singleton()->get_main_control()->add_child(addon_library);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(addon_library);
addon_library->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
addon_library->hide();
}
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
index 9e551ae0ed..d670197c53 100644
--- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "audio_stream_randomizer_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
void AudioStreamRandomizerEditorPlugin::edit(Object *p_object) {
}
@@ -43,8 +44,8 @@ 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);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited);
if (!randomizer) {
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index 70775c1ee2..46e2fe41af 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -47,6 +47,9 @@ void BoneMapperButton::fetch_textures() {
set_offset(SIDE_TOP, 0);
set_offset(SIDE_BOTTOM, 0);
+ // Hack to avoid handle color darkening...
+ set_modulate(EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25));
+
circle = memnew(TextureRect);
circle->set_texture(get_theme_icon(SNAME("BoneMapperHandleCircle"), SNAME("EditorIcons")));
add_child(circle);
@@ -98,14 +101,24 @@ BoneMapperButton::~BoneMapperButton() {
}
void BoneMapperItem::create_editor() {
- skeleton_bone_selector = memnew(EditorPropertyTextEnum);
- skeleton_bone_selector->setup(skeleton_bone_names, false, true);
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ add_child(hbox);
+
+ skeleton_bone_selector = memnew(EditorPropertyText);
skeleton_bone_selector->set_label(profile_bone_name);
skeleton_bone_selector->set_selectable(false);
+ skeleton_bone_selector->set_h_size_flags(SIZE_EXPAND_FILL);
skeleton_bone_selector->set_object_and_property(bone_map.ptr(), "bone_map/" + String(profile_bone_name));
skeleton_bone_selector->update_property();
skeleton_bone_selector->connect("property_changed", callable_mp(this, &BoneMapperItem::_value_changed));
- add_child(skeleton_bone_selector);
+ hbox->add_child(skeleton_bone_selector);
+
+ picker_button = memnew(Button);
+ picker_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
+ picker_button->connect("pressed", callable_mp(this, &BoneMapperItem::_open_picker));
+ hbox->add_child(picker_button);
+
+ add_child(memnew(HSeparator));
}
void BoneMapperItem::_update_property() {
@@ -114,6 +127,10 @@ void BoneMapperItem::_update_property() {
}
}
+void BoneMapperItem::_open_picker() {
+ emit_signal(SNAME("pick"), profile_bone_name);
+}
+
void BoneMapperItem::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
bone_map->set(p_property, p_value);
}
@@ -133,25 +150,153 @@ void BoneMapperItem::_notification(int p_what) {
}
void BoneMapperItem::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("pick", PropertyInfo(Variant::STRING_NAME, "profile_bone_name")));
}
-BoneMapperItem::BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name) {
+BoneMapperItem::BoneMapperItem(Ref<BoneMap> &p_bone_map, const StringName &p_profile_bone_name) {
bone_map = p_bone_map;
- skeleton_bone_names = p_skeleton_bone_names;
profile_bone_name = p_profile_bone_name;
}
BoneMapperItem::~BoneMapperItem() {
}
+void BonePicker::create_editors() {
+ set_title(TTR("Bone Picker:"));
+
+ VBoxContainer *vbox = memnew(VBoxContainer);
+ add_child(vbox);
+
+ bones = memnew(Tree);
+ bones->set_select_mode(Tree::SELECT_SINGLE);
+ bones->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ bones->set_hide_root(true);
+ bones->connect("item_activated", callable_mp(this, &BonePicker::_confirm));
+ vbox->add_child(bones);
+
+ create_bones_tree(skeleton);
+}
+
+void BonePicker::create_bones_tree(Skeleton3D *p_skeleton) {
+ bones->clear();
+
+ if (!p_skeleton) {
+ return;
+ }
+
+ TreeItem *root = bones->create_item();
+
+ HashMap<int, TreeItem *> items;
+
+ items.insert(-1, root);
+
+ Ref<Texture> bone_icon = get_theme_icon(SNAME("BoneAttachment3D"), SNAME("EditorIcons"));
+
+ Vector<int> bones_to_process = p_skeleton->get_parentless_bones();
+ bool is_first = true;
+ while (bones_to_process.size() > 0) {
+ int current_bone_idx = bones_to_process[0];
+ bones_to_process.erase(current_bone_idx);
+
+ Vector<int> current_bone_child_bones = p_skeleton->get_bone_children(current_bone_idx);
+ int child_bone_size = current_bone_child_bones.size();
+ for (int i = 0; i < child_bone_size; i++) {
+ bones_to_process.push_back(current_bone_child_bones[i]);
+ }
+
+ const int parent_idx = p_skeleton->get_bone_parent(current_bone_idx);
+ TreeItem *parent_item = items.find(parent_idx)->value;
+
+ TreeItem *joint_item = bones->create_item(parent_item);
+ items.insert(current_bone_idx, joint_item);
+
+ joint_item->set_text(0, p_skeleton->get_bone_name(current_bone_idx));
+ joint_item->set_icon(0, bone_icon);
+ joint_item->set_selectable(0, true);
+ joint_item->set_metadata(0, "bones/" + itos(current_bone_idx));
+ if (is_first) {
+ is_first = false;
+ } else {
+ joint_item->set_collapsed(true);
+ }
+ }
+}
+
+void BonePicker::_confirm() {
+ _ok_pressed();
+}
+
+void BonePicker::popup_bones_tree(const Size2i &p_minsize) {
+ popup_centered(p_minsize);
+}
+
+bool BonePicker::has_selected_bone() {
+ TreeItem *selected = bones->get_selected();
+ if (!selected) {
+ return false;
+ }
+ return true;
+}
+
+StringName BonePicker::get_selected_bone() {
+ TreeItem *selected = bones->get_selected();
+ if (!selected) {
+ return StringName();
+ }
+ return selected->get_text(0);
+}
+
+void BonePicker::_bind_methods() {
+}
+
+void BonePicker::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ create_editors();
+ } break;
+ }
+}
+
+BonePicker::BonePicker(Skeleton3D *p_skeleton) {
+ skeleton = p_skeleton;
+}
+
+BonePicker::~BonePicker() {
+}
+
void BoneMapper::create_editor() {
+ // Create Bone picker.
+ picker = memnew(BonePicker(skeleton));
+ picker->connect("confirmed", callable_mp(this, &BoneMapper::_apply_picker_selection));
+ add_child(picker, false, INTERNAL_MODE_FRONT);
+
+ profile_selector = memnew(EditorPropertyResource);
+ profile_selector->setup(bone_map.ptr(), "profile", "SkeletonProfile");
+ profile_selector->set_label("Profile");
+ profile_selector->set_selectable(false);
+ profile_selector->set_object_and_property(bone_map.ptr(), "profile");
+ profile_selector->update_property();
+ profile_selector->connect("property_changed", callable_mp(this, &BoneMapper::_profile_changed));
+ add_child(profile_selector);
+ add_child(memnew(HSeparator));
+
+ HBoxContainer *group_hbox = memnew(HBoxContainer);
+ add_child(group_hbox);
+
profile_group_selector = memnew(EditorPropertyEnum);
profile_group_selector->set_label("Group");
profile_group_selector->set_selectable(false);
+ profile_group_selector->set_h_size_flags(SIZE_EXPAND_FILL);
profile_group_selector->set_object_and_property(this, "current_group_idx");
profile_group_selector->update_property();
profile_group_selector->connect("property_changed", callable_mp(this, &BoneMapper::_value_changed));
- add_child(profile_group_selector);
+ group_hbox->add_child(profile_group_selector);
+
+ clear_mapping_button = memnew(Button);
+ clear_mapping_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")));
+ clear_mapping_button->set_tooltip_text(TTR("Clear mappings in current group."));
+ clear_mapping_button->connect("pressed", callable_mp(this, &BoneMapper::_clear_mapping_current_group));
+ group_hbox->add_child(clear_mapping_button);
bone_mapper_field = memnew(AspectRatioContainer);
bone_mapper_field->set_stretch_mode(AspectRatioContainer::STRETCH_FIT);
@@ -175,9 +320,6 @@ void BoneMapper::create_editor() {
mapper_item_vbox = memnew(VBoxContainer);
add_child(mapper_item_vbox);
- separator = memnew(HSeparator);
- add_child(separator);
-
recreate_items();
}
@@ -201,6 +343,18 @@ void BoneMapper::update_group_idx() {
}
}
+void BoneMapper::_pick_bone(const StringName &p_bone_name) {
+ picker_key_name = p_bone_name;
+ picker->popup_bones_tree(Size2(500, 500) * EDSCALE);
+}
+
+void BoneMapper::_apply_picker_selection() {
+ if (!picker->has_selected_bone()) {
+ return;
+ }
+ bone_map->set_skeleton_bone_name(picker_key_name, picker->get_selected_bone());
+}
+
void BoneMapper::set_current_group_idx(int p_group_idx) {
current_group_idx = p_group_idx;
recreate_editor();
@@ -282,6 +436,7 @@ void BoneMapper::clear_items() {
// Clear items.
int len = bone_mapper_items.size();
for (int i = 0; i < len; i++) {
+ bone_mapper_items[i]->disconnect("pick", callable_mp(this, &BoneMapper::_pick_bone));
mapper_item_vbox->remove_child(bone_mapper_items[i]);
memdelete(bone_mapper_items[i]);
}
@@ -293,16 +448,11 @@ void BoneMapper::recreate_items() {
// Create items by profile.
Ref<SkeletonProfile> profile = bone_map->get_profile();
if (profile.is_valid()) {
- PackedStringArray skeleton_bone_names;
- int len = skeleton->get_bone_count();
- for (int i = 0; i < len; i++) {
- skeleton_bone_names.push_back(skeleton->get_bone_name(i));
- }
-
- len = profile->get_bone_size();
+ int len = profile->get_bone_size();
for (int i = 0; i < len; i++) {
StringName bn = profile->get_bone_name(i);
- bone_mapper_items.append(memnew(BoneMapperItem(bone_map, skeleton_bone_names, bn)));
+ bone_mapper_items.append(memnew(BoneMapperItem(bone_map, bn)));
+ bone_mapper_items[i]->connect("pick", callable_mp(this, &BoneMapper::_pick_bone), CONNECT_DEFERRED);
mapper_item_vbox->add_child(bone_mapper_items[i]);
}
}
@@ -363,11 +513,754 @@ void BoneMapper::_update_state() {
}
}
+void BoneMapper::_clear_mapping_current_group() {
+ if (bone_map.is_valid()) {
+ Ref<SkeletonProfile> profile = bone_map->get_profile();
+ if (profile.is_valid() && profile->get_group_size() > 0) {
+ int len = profile->get_bone_size();
+ for (int i = 0; i < len; i++) {
+ if (profile->get_group(i) == profile->get_group_name(current_group_idx)) {
+ bone_map->_set_skeleton_bone_name(profile->get_bone_name(i), StringName());
+ }
+ }
+ recreate_items();
+ }
+ }
+}
+
+#ifdef MODULE_REGEX_ENABLED
+int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation, int p_parent, int p_child, int p_children_count) {
+ // There may be multiple candidates hit by existing the subsidiary bone.
+ // The one with the shortest name is probably the original.
+ LocalVector<String> hit_list;
+ String shortest = "";
+
+ for (int word_idx = 0; word_idx < p_picklist.size(); word_idx++) {
+ RegEx re = RegEx(p_picklist[word_idx]);
+ if (p_child == -1) {
+ Vector<int> bones_to_process = p_parent == -1 ? p_skeleton->get_parentless_bones() : p_skeleton->get_bone_children(p_parent);
+ while (bones_to_process.size() > 0) {
+ int idx = bones_to_process[0];
+ bones_to_process.erase(idx);
+ Vector<int> children = p_skeleton->get_bone_children(idx);
+ for (int i = 0; i < children.size(); i++) {
+ bones_to_process.push_back(children[i]);
+ }
+
+ if (p_children_count == 0 && children.size() > 0) {
+ continue;
+ }
+ if (p_children_count > 0 && children.size() < p_children_count) {
+ continue;
+ }
+
+ String bn = skeleton->get_bone_name(idx);
+ if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) {
+ hit_list.push_back(bn);
+ }
+ }
+
+ if (hit_list.size() > 0) {
+ shortest = hit_list[0];
+ for (uint32_t i = 0; i < hit_list.size(); i++) {
+ if (hit_list[i].length() < shortest.length()) {
+ shortest = hit_list[i]; // Prioritize parent.
+ }
+ }
+ }
+ } else {
+ int idx = skeleton->get_bone_parent(p_child);
+ while (idx != p_parent && idx >= 0) {
+ Vector<int> children = p_skeleton->get_bone_children(idx);
+ if (p_children_count == 0 && children.size() > 0) {
+ continue;
+ }
+ if (p_children_count > 0 && children.size() < p_children_count) {
+ continue;
+ }
+
+ String bn = skeleton->get_bone_name(idx);
+ if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) {
+ hit_list.push_back(bn);
+ }
+ idx = skeleton->get_bone_parent(idx);
+ }
+
+ if (hit_list.size() > 0) {
+ shortest = hit_list[0];
+ for (uint32_t i = 0; i < hit_list.size(); i++) {
+ if (hit_list[i].length() <= shortest.length()) {
+ shortest = hit_list[i]; // Prioritize parent.
+ }
+ }
+ }
+ }
+
+ if (shortest != "") {
+ break;
+ }
+ }
+
+ if (shortest == "") {
+ return -1;
+ }
+
+ return skeleton->find_bone(shortest);
+}
+
+BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(String p_bone_name) {
+ String fixed_bn = p_bone_name.to_snake_case();
+
+ LocalVector<String> left_words;
+ left_words.push_back("(?<![a-zA-Z])left");
+ left_words.push_back("(?<![a-zA-Z0-9])l(?![a-zA-Z0-9])");
+
+ LocalVector<String> right_words;
+ right_words.push_back("(?<![a-zA-Z])right");
+ right_words.push_back("(?<![a-zA-Z0-9])r(?![a-zA-Z0-9])");
+
+ for (uint32_t i = 0; i < left_words.size(); i++) {
+ RegEx re_l = RegEx(left_words[i]);
+ if (!re_l.search(fixed_bn).is_null()) {
+ return BONE_SEGREGATION_LEFT;
+ }
+ RegEx re_r = RegEx(right_words[i]);
+ if (!re_r.search(fixed_bn).is_null()) {
+ return BONE_SEGREGATION_RIGHT;
+ }
+ }
+
+ return BONE_SEGREGATION_NONE;
+}
+
+void BoneMapper::_run_auto_mapping() {
+ auto_mapping_process(bone_map);
+ recreate_items();
+}
+
+void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
+ WARN_PRINT("Run auto mapping.");
+
+ int bone_idx = -1;
+ Vector<String> picklist; // Use Vector<String> because match words have priority.
+ Vector<int> search_path;
+
+ // 1. Guess Hips
+ picklist.push_back("hip");
+ picklist.push_back("pelvis");
+ picklist.push_back("waist");
+ picklist.push_back("torso");
+ int hips = search_bone_by_name(skeleton, picklist);
+ if (hips == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Hips. Abort auto mapping.");
+ return; // If there is no Hips, we cannot guess bone after then.
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Hips", skeleton->get_bone_name(hips));
+ }
+ picklist.clear();
+
+ // 2. Guess Root
+ bone_idx = skeleton->get_bone_parent(hips);
+ while (bone_idx >= 0) {
+ search_path.push_back(bone_idx);
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ if (search_path.size() == 0) {
+ bone_idx = -1;
+ } else if (search_path.size() == 1) {
+ bone_idx = search_path[0]; // It is only one bone which can be root.
+ } else {
+ bool found = false;
+ for (int i = 0; i < search_path.size(); i++) {
+ RegEx re = RegEx("root");
+ if (!re.search(skeleton->get_bone_name(search_path[i]).to_lower()).is_null()) {
+ bone_idx = search_path[i]; // Name match is preferred.
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (int i = 0; i < search_path.size(); i++) {
+ if (skeleton->get_bone_global_rest(search_path[i]).origin.is_zero_approx()) {
+ bone_idx = search_path[i]; // The bone existing at the origin is appropriate as a root.
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ bone_idx = search_path[search_path.size() - 1]; // Ambiguous, but most parental bone selected.
+ }
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Root."); // Root is not required, so continue.
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Root", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ search_path.clear();
+
+ // 3. Guess Neck
+ picklist.push_back("neck");
+ picklist.push_back("head"); // For no neck model.
+ picklist.push_back("face"); // Same above.
+ int neck = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, hips);
+ picklist.clear();
+
+ // 4. Guess Head
+ picklist.push_back("head");
+ picklist.push_back("face");
+ int head = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck);
+ if (head == -1) {
+ search_path = skeleton->get_bone_children(neck);
+ if (search_path.size() == 1) {
+ head = search_path[0]; // Maybe only one child of the Neck is Head.
+ }
+ }
+ if (head == -1) {
+ if (neck != -1) {
+ head = neck; // The head animation should have more movement.
+ neck = -1;
+ p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
+ } else {
+ WARN_PRINT("Auto Mapping couldn't guess Neck or Head."); // Continued for guessing on the other bones. But abort when guessing spines step.
+ }
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Neck", skeleton->get_bone_name(neck));
+ p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
+ }
+ picklist.clear();
+ search_path.clear();
+
+ int neck_or_head = neck != -1 ? neck : (head != -1 ? head : -1);
+ if (neck_or_head != -1) {
+ // 4-1. Guess Eyes
+ picklist.push_back("eye(?!.*(brow|lash|lid))");
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, neck_or_head);
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftEye.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftEye", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, neck_or_head);
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightEye.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightEye", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 4-2. Guess Jaw
+ picklist.push_back("jaw");
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck_or_head);
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Jaw.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Jaw", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+ }
+
+ // 5. Guess Foots
+ picklist.push_back("foot");
+ picklist.push_back("ankle");
+ int left_foot = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips);
+ if (left_foot == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftFoot.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftFoot", skeleton->get_bone_name(left_foot));
+ }
+ int right_foot = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips);
+ if (right_foot == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightFoot.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightFoot", skeleton->get_bone_name(right_foot));
+ }
+ picklist.clear();
+
+ // 5-1. Guess LowerLegs
+ picklist.push_back("(low|under).*leg");
+ picklist.push_back("knee");
+ picklist.push_back("shin");
+ picklist.push_back("calf");
+ picklist.push_back("leg");
+ int left_lower_leg = -1;
+ if (left_foot != -1) {
+ left_lower_leg = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_foot);
+ }
+ if (left_lower_leg == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftLowerLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftLowerLeg", skeleton->get_bone_name(left_lower_leg));
+ }
+ int right_lower_leg = -1;
+ if (right_foot != -1) {
+ right_lower_leg = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_foot);
+ }
+ if (right_lower_leg == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightLowerLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightLowerLeg", skeleton->get_bone_name(right_lower_leg));
+ }
+ picklist.clear();
+
+ // 5-2. Guess UpperLegs
+ picklist.push_back("up.*leg");
+ picklist.push_back("thigh");
+ picklist.push_back("leg");
+ if (left_lower_leg != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_lower_leg);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftUpperLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftUpperLeg", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ if (right_lower_leg != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_lower_leg);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightUpperLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightUpperLeg", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 5-3. Guess Toes
+ picklist.push_back("toe");
+ picklist.push_back("ball");
+ if (left_foot != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_foot);
+ if (bone_idx == -1) {
+ search_path = skeleton->get_bone_children(left_foot);
+ if (search_path.size() == 1) {
+ bone_idx = search_path[0]; // Maybe only one child of the Foot is Toes.
+ }
+ search_path.clear();
+ }
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftToes.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftToes", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ if (right_foot != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_foot);
+ if (bone_idx == -1) {
+ search_path = skeleton->get_bone_children(right_foot);
+ if (search_path.size() == 1) {
+ bone_idx = search_path[0]; // Maybe only one child of the Foot is Toes.
+ }
+ search_path.clear();
+ }
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightToes.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightToes", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 6. Guess Hands
+ picklist.push_back("hand");
+ picklist.push_back("wrist");
+ picklist.push_back("palm");
+ picklist.push_back("fingers");
+ int left_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, -1, 5);
+ if (left_hand_or_palm == -1) {
+ // Ambiguous, but try again for fewer finger models.
+ left_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips);
+ }
+ int left_hand = left_hand_or_palm; // Check for the presence of a wrist, since bones with five children may be palmar.
+ while (left_hand != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_hand);
+ if (bone_idx == -1) {
+ break;
+ }
+ left_hand = bone_idx;
+ }
+ if (left_hand == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftHand.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftHand", skeleton->get_bone_name(left_hand));
+ }
+ bone_idx = -1;
+ int right_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, -1, 5);
+ if (right_hand_or_palm == -1) {
+ // Ambiguous, but try again for fewer finger models.
+ right_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips);
+ }
+ int right_hand = right_hand_or_palm;
+ while (right_hand != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_hand);
+ if (bone_idx == -1) {
+ break;
+ }
+ right_hand = bone_idx;
+ }
+ if (right_hand == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightHand.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightHand", skeleton->get_bone_name(right_hand));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 6-1. Guess Finger
+ bool named_finger_is_found = false;
+ LocalVector<String> fingers;
+ fingers.push_back("thumb|pollex");
+ fingers.push_back("index|fore");
+ fingers.push_back("middle");
+ fingers.push_back("ring");
+ fingers.push_back("little|pinkie|pinky");
+ if (left_hand_or_palm != -1) {
+ LocalVector<LocalVector<String>> left_fingers_map;
+ left_fingers_map.resize(5);
+ left_fingers_map[0].push_back("LeftThumbMetacarpal");
+ left_fingers_map[0].push_back("LeftThumbProximal");
+ left_fingers_map[0].push_back("LeftThumbDistal");
+ left_fingers_map[1].push_back("LeftIndexProximal");
+ left_fingers_map[1].push_back("LeftIndexIntermediate");
+ left_fingers_map[1].push_back("LeftIndexDistal");
+ left_fingers_map[2].push_back("LeftMiddleProximal");
+ left_fingers_map[2].push_back("LeftMiddleIntermediate");
+ left_fingers_map[2].push_back("LeftMiddleDistal");
+ left_fingers_map[3].push_back("LeftRingProximal");
+ left_fingers_map[3].push_back("LeftRingIntermediate");
+ left_fingers_map[3].push_back("LeftRingDistal");
+ left_fingers_map[4].push_back("LeftLittleProximal");
+ left_fingers_map[4].push_back("LeftLittleIntermediate");
+ left_fingers_map[4].push_back("LeftLittleDistal");
+ for (int i = 0; i < 5; i++) {
+ picklist.push_back(fingers[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_hand_or_palm, -1, 0);
+ if (finger != -1) {
+ while (finger != left_hand_or_palm && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ named_finger_is_found = true;
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ named_finger_is_found = true;
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ named_finger_is_found = true;
+ }
+ }
+ picklist.clear();
+ search_path.clear();
+ }
+
+ // It is a bit corner case, but possibly the finger names are sequentially numbered...
+ if (!named_finger_is_found) {
+ picklist.push_back("finger");
+ RegEx finger_re = RegEx("finger");
+ search_path = skeleton->get_bone_children(left_hand_or_palm);
+ Vector<String> finger_names;
+ for (int i = 0; i < search_path.size(); i++) {
+ String bn = skeleton->get_bone_name(search_path[i]);
+ if (!finger_re.search(bn.to_lower()).is_null()) {
+ finger_names.push_back(bn);
+ }
+ }
+ finger_names.sort(); // Order by lexicographic, normal use cases never have more than 10 fingers in one hand.
+ search_path.clear();
+ for (int i = 0; i < finger_names.size(); i++) {
+ if (i >= 5) {
+ break;
+ }
+ int finger_root = skeleton->find_bone(finger_names[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, finger_root, -1, 0);
+ if (finger != -1) {
+ while (finger != finger_root && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ }
+ search_path.push_back(finger_root);
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ }
+ search_path.clear();
+ }
+ picklist.clear();
+ }
+ }
+ named_finger_is_found = false;
+ if (right_hand_or_palm != -1) {
+ LocalVector<LocalVector<String>> right_fingers_map;
+ right_fingers_map.resize(5);
+ right_fingers_map[0].push_back("RightThumbMetacarpal");
+ right_fingers_map[0].push_back("RightThumbProximal");
+ right_fingers_map[0].push_back("RightThumbDistal");
+ right_fingers_map[1].push_back("RightIndexProximal");
+ right_fingers_map[1].push_back("RightIndexIntermediate");
+ right_fingers_map[1].push_back("RightIndexDistal");
+ right_fingers_map[2].push_back("RightMiddleProximal");
+ right_fingers_map[2].push_back("RightMiddleIntermediate");
+ right_fingers_map[2].push_back("RightMiddleDistal");
+ right_fingers_map[3].push_back("RightRingProximal");
+ right_fingers_map[3].push_back("RightRingIntermediate");
+ right_fingers_map[3].push_back("RightRingDistal");
+ right_fingers_map[4].push_back("RightLittleProximal");
+ right_fingers_map[4].push_back("RightLittleIntermediate");
+ right_fingers_map[4].push_back("RightLittleDistal");
+ for (int i = 0; i < 5; i++) {
+ picklist.push_back(fingers[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_hand_or_palm, -1, 0);
+ if (finger != -1) {
+ while (finger != right_hand_or_palm && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ named_finger_is_found = true;
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ named_finger_is_found = true;
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ named_finger_is_found = true;
+ }
+ }
+ picklist.clear();
+ search_path.clear();
+ }
+
+ // It is a bit corner case, but possibly the finger names are sequentially numbered...
+ if (!named_finger_is_found) {
+ picklist.push_back("finger");
+ RegEx finger_re = RegEx("finger");
+ search_path = skeleton->get_bone_children(right_hand_or_palm);
+ Vector<String> finger_names;
+ for (int i = 0; i < search_path.size(); i++) {
+ String bn = skeleton->get_bone_name(search_path[i]);
+ if (!finger_re.search(bn.to_lower()).is_null()) {
+ finger_names.push_back(bn);
+ }
+ }
+ finger_names.sort(); // Order by lexicographic, normal use cases never have more than 10 fingers in one hand.
+ search_path.clear();
+ for (int i = 0; i < finger_names.size(); i++) {
+ if (i >= 5) {
+ break;
+ }
+ int finger_root = skeleton->find_bone(finger_names[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, finger_root, -1, 0);
+ if (finger != -1) {
+ while (finger != finger_root && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ }
+ search_path.push_back(finger_root);
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ }
+ search_path.clear();
+ }
+ picklist.clear();
+ }
+ }
+
+ // 7. Guess Arms
+ picklist.push_back("shoulder");
+ picklist.push_back("clavicle");
+ picklist.push_back("collar");
+ int left_shoulder = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips);
+ if (left_shoulder == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftShoulder.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftShoulder", skeleton->get_bone_name(left_shoulder));
+ }
+ int right_shoulder = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips);
+ if (right_shoulder == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightShoulder.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightShoulder", skeleton->get_bone_name(right_shoulder));
+ }
+ picklist.clear();
+
+ // 7-1. Guess LowerArms
+ picklist.push_back("(low|fore).*arm");
+ picklist.push_back("elbow");
+ picklist.push_back("arm");
+ int left_lower_arm = -1;
+ if (left_shoulder != -1 && left_hand_or_palm != -1) {
+ left_lower_arm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_shoulder, left_hand_or_palm);
+ }
+ if (left_lower_arm == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftLowerArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftLowerArm", skeleton->get_bone_name(left_lower_arm));
+ }
+ int right_lower_arm = -1;
+ if (right_shoulder != -1 && right_hand_or_palm != -1) {
+ right_lower_arm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_shoulder, right_hand_or_palm);
+ }
+ if (right_lower_arm == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightLowerArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightLowerArm", skeleton->get_bone_name(right_lower_arm));
+ }
+ picklist.clear();
+
+ // 7-2. Guess UpperArms
+ picklist.push_back("up.*arm");
+ picklist.push_back("arm");
+ if (left_shoulder != -1 && left_lower_arm != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_shoulder, left_lower_arm);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftUpperArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftUpperArm", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ if (right_shoulder != -1 && right_lower_arm != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_shoulder, right_lower_arm);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightUpperArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightUpperArm", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 8. Guess UpperChest or Chest
+ if (neck_or_head == -1) {
+ return; // Abort.
+ }
+ int chest_or_upper_chest = skeleton->get_bone_parent(neck_or_head);
+ bool is_appropriate = true;
+ if (left_shoulder != -1) {
+ bone_idx = skeleton->get_bone_parent(left_shoulder);
+ bool detect = false;
+ while (bone_idx != hips && bone_idx >= 0) {
+ if (bone_idx == chest_or_upper_chest) {
+ detect = true;
+ break;
+ }
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ if (!detect) {
+ is_appropriate = false;
+ }
+ bone_idx = -1;
+ }
+ if (right_shoulder != -1) {
+ bone_idx = skeleton->get_bone_parent(right_shoulder);
+ bool detect = false;
+ while (bone_idx != hips && bone_idx >= 0) {
+ if (bone_idx == chest_or_upper_chest) {
+ detect = true;
+ break;
+ }
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ if (!detect) {
+ is_appropriate = false;
+ }
+ bone_idx = -1;
+ }
+ if (!is_appropriate) {
+ if (skeleton->get_bone_parent(left_shoulder) == skeleton->get_bone_parent(right_shoulder)) {
+ chest_or_upper_chest = skeleton->get_bone_parent(left_shoulder);
+ } else {
+ chest_or_upper_chest = -1;
+ }
+ }
+ if (chest_or_upper_chest == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Chest or UpperChest. Abort auto mapping.");
+ return; // Will be not able to guess Spines.
+ }
+
+ // 9. Guess Spines
+ bone_idx = skeleton->get_bone_parent(chest_or_upper_chest);
+ while (bone_idx != hips && bone_idx >= 0) {
+ search_path.push_back(bone_idx);
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ search_path.reverse();
+ if (search_path.size() == 0) {
+ p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(chest_or_upper_chest)); // Maybe chibi model...?
+ } else if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name("Chest", skeleton->get_bone_name(chest_or_upper_chest));
+ } else if (search_path.size() >= 2) {
+ p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name("Chest", skeleton->get_bone_name(search_path[search_path.size() - 1])); // Probably UppeChest's parent is appropriate.
+ p_bone_map->_set_skeleton_bone_name("UpperChest", skeleton->get_bone_name(chest_or_upper_chest));
+ }
+ bone_idx = -1;
+ search_path.clear();
+
+ WARN_PRINT("Finish auto mapping.");
+}
+#endif // MODULE_REGEX_ENABLED
+
void BoneMapper::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
set(p_property, p_value);
recreate_editor();
}
+void BoneMapper::_profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
+ bone_map->set(p_property, p_value);
+
+ // Run auto mapping when setting SkeletonProfileHumanoid by GUI Editor.
+ Ref<SkeletonProfile> profile = bone_map->get_profile();
+ if (profile.is_valid()) {
+ SkeletonProfileHumanoid *hmn = Object::cast_to<SkeletonProfileHumanoid>(profile.ptr());
+ if (hmn) {
+#ifdef MODULE_REGEX_ENABLED
+ _run_auto_mapping();
+#endif // MODULE_REGEX_ENABLED
+ }
+ }
+}
+
void BoneMapper::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current_group_idx", "current_group_idx"), &BoneMapper::set_current_group_idx);
ClassDB::bind_method(D_METHOD("get_current_group_idx"), &BoneMapper::get_current_group_idx);
@@ -444,10 +1337,6 @@ void BoneMapEditor::_notification(int p_what) {
create_editors();
} break;
case NOTIFICATION_EXIT_TREE: {
- if (bone_mapper) {
- remove_child(bone_mapper);
- bone_mapper->queue_delete();
- }
skeleton = nullptr;
} break;
}
diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h
index 339547ea10..55261ab477 100644
--- a/editor/plugins/bone_map_editor_plugin.h
+++ b/editor/plugins/bone_map_editor_plugin.h
@@ -34,6 +34,12 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
+
+#include "modules/modules_enabled.gen.h" // For regex.
+#ifdef MODULE_REGEX_ENABLED
+#include "modules/regex/regex.h"
+#endif
+
#include "scene/3d/skeleton_3d.h"
#include "scene/gui/color_rect.h"
#include "scene/gui/dialogs.h"
@@ -56,7 +62,7 @@ private:
bool selected = false;
bool require = false;
- TextureRect *circle;
+ TextureRect *circle = nullptr;
void fetch_textures();
@@ -79,12 +85,13 @@ class BoneMapperItem : public VBoxContainer {
int button_id = -1;
StringName profile_bone_name;
- PackedStringArray skeleton_bone_names;
Ref<BoneMap> bone_map;
- EditorPropertyTextEnum *skeleton_bone_selector;
+ EditorPropertyText *skeleton_bone_selector = nullptr;
+ Button *picker_button = nullptr;
void _update_property();
+ void _open_picker();
protected:
void _notification(int p_what);
@@ -95,28 +102,57 @@ protected:
public:
void assign_button_id(int p_button_id);
- BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name = StringName());
+ BoneMapperItem(Ref<BoneMap> &p_bone_map, const StringName &p_profile_bone_name = StringName());
~BoneMapperItem();
};
+class BonePicker : public AcceptDialog {
+ GDCLASS(BonePicker, AcceptDialog);
+
+ Skeleton3D *skeleton = nullptr;
+ Tree *bones = nullptr;
+
+public:
+ void popup_bones_tree(const Size2i &p_minsize = Size2i());
+ bool has_selected_bone();
+ StringName get_selected_bone();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+ void _confirm();
+
+private:
+ void create_editors();
+ void create_bones_tree(Skeleton3D *p_skeleton);
+
+public:
+ BonePicker(Skeleton3D *p_skeleton);
+ ~BonePicker();
+};
+
class BoneMapper : public VBoxContainer {
GDCLASS(BoneMapper, VBoxContainer);
- Skeleton3D *skeleton;
+ Skeleton3D *skeleton = nullptr;
Ref<BoneMap> bone_map;
+ EditorPropertyResource *profile_selector = nullptr;
+
Vector<BoneMapperItem *> bone_mapper_items;
- VBoxContainer *mapper_item_vbox;
- HSeparator *separator;
+ Button *clear_mapping_button = nullptr;
+
+ VBoxContainer *mapper_item_vbox = nullptr;
int current_group_idx = 0;
int current_bone_idx = -1;
- AspectRatioContainer *bone_mapper_field;
- EditorPropertyEnum *profile_group_selector;
- ColorRect *profile_bg;
- TextureRect *profile_texture;
+ AspectRatioContainer *bone_mapper_field = nullptr;
+ EditorPropertyEnum *profile_group_selector = nullptr;
+ ColorRect *profile_bg = nullptr;
+ TextureRect *profile_texture = nullptr;
Vector<BoneMapperButton *> bone_mapper_buttons;
void create_editor();
@@ -126,10 +162,31 @@ class BoneMapper : public VBoxContainer {
void update_group_idx();
void _update_state();
+ /* Bone picker */
+ BonePicker *picker = nullptr;
+ StringName picker_key_name;
+ void _pick_bone(const StringName &p_bone_name);
+ void _apply_picker_selection();
+ void _clear_mapping_current_group();
+
+#ifdef MODULE_REGEX_ENABLED
+ /* For auto mapping */
+ enum BoneSegregation {
+ BONE_SEGREGATION_NONE,
+ BONE_SEGREGATION_LEFT,
+ BONE_SEGREGATION_RIGHT
+ };
+ int search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation = BONE_SEGREGATION_NONE, int p_parent = -1, int p_child = -1, int p_children_count = -1);
+ BoneSegregation guess_bone_segregation(String p_bone_name);
+ void auto_mapping_process(Ref<BoneMap> &p_bone_map);
+ void _run_auto_mapping();
+#endif // MODULE_REGEX_ENABLED
+
protected:
void _notification(int p_what);
static void _bind_methods();
virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
+ virtual void _profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
public:
void set_current_group_idx(int p_group_idx);
@@ -144,9 +201,9 @@ public:
class BoneMapEditor : public VBoxContainer {
GDCLASS(BoneMapEditor, VBoxContainer);
- Skeleton3D *skeleton;
+ Skeleton3D *skeleton = nullptr;
Ref<BoneMap> bone_map;
- BoneMapper *bone_mapper;
+ BoneMapper *bone_mapper = nullptr;
void fetch_objects();
void clear_editors();
@@ -162,7 +219,7 @@ public:
class EditorInspectorPluginBoneMap : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginBoneMap, EditorInspectorPlugin);
- BoneMapEditor *editor;
+ BoneMapEditor *editor = nullptr;
public:
virtual bool can_handle(Object *p_object) override;
diff --git a/editor/plugins/camera_3d_editor_plugin.cpp b/editor/plugins/camera_3d_editor_plugin.cpp
index 141837244a..1aedb3b4ce 100644
--- a/editor/plugins/camera_3d_editor_plugin.cpp
+++ b/editor/plugins/camera_3d_editor_plugin.cpp
@@ -98,7 +98,7 @@ void Camera3DEditorPlugin::make_visible(bool p_visible) {
Camera3DEditorPlugin::Camera3DEditorPlugin() {
/* camera_editor = memnew( CameraEditor );
- EditorNode::get_singleton()->get_main_control()->add_child(camera_editor);
+ EditorNode::get_singleton()->get_main_screen_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/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index ac85eb5e1b..070834b33b 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_toaster.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/scene_tree_dock.h"
@@ -222,8 +223,8 @@ public:
grid_step_x->set_value(p_grid_step.x);
grid_step_y->set_value(p_grid_step.y);
primary_grid_steps->set_value(p_primary_grid_steps);
- rotation_offset->set_value(Math::rad2deg(p_rotation_offset));
- rotation_step->set_value(Math::rad2deg(p_rotation_step));
+ rotation_offset->set_value(Math::rad_to_deg(p_rotation_offset));
+ rotation_step->set_value(Math::rad_to_deg(p_rotation_step));
scale_step->set_value(p_scale_step);
}
@@ -231,8 +232,8 @@ public:
p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value());
p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value());
p_primary_grid_steps = int(primary_grid_steps->get_value());
- p_rotation_offset = Math::deg2rad(rotation_offset->get_value());
- p_rotation_step = Math::deg2rad(rotation_step->get_value());
+ p_rotation_offset = Math::deg_to_rad(rotation_offset->get_value());
+ p_rotation_step = Math::deg_to_rad(rotation_step->get_value());
p_scale_step = scale_step->get_value();
}
};
@@ -486,21 +487,21 @@ void CanvasItemEditor::shortcut_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) {
- viewport->update();
+ viewport->queue_redraw();
}
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();
+ viewport->queue_redraw();
} 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) {
grid_step_multiplier--;
}
- viewport->update();
+ viewport->queue_redraw();
}
}
}
@@ -757,7 +758,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
}
}
}
- viewport->update();
+ viewport->queue_redraw();
return still_selected;
}
@@ -874,15 +875,15 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
}
}
}
- undo_redo->add_do_method(viewport, "update");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
void CanvasItemEditor::_snap_changed() {
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();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_selection_result_pressed(int p_result) {
@@ -982,7 +983,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
case GRID_VISIBILITY_SHOW_WHEN_SNAPPING:
case GRID_VISIBILITY_HIDE:
grid_visibility = (GridVisibility)p_id;
- viewport->update();
+ viewport->queue_redraw();
view_menu->get_popup()->hide();
return;
}
@@ -1009,7 +1010,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
break;
}
}
- viewport->update();
+ viewport->queue_redraw();
}
bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
@@ -1104,7 +1105,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
drag_to = xform.affine_inverse().xform(m->get_position());
dragged_guide_pos = xform.xform(snap_point(drag_to, SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES));
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -1127,14 +1128,14 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->create_action(TTR("Move Vertical Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} else {
vguides.push_back(edited.x);
undo_redo->create_action(TTR("Create Vertical Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
} else {
@@ -1147,7 +1148,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides);
}
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -1160,14 +1161,14 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->create_action(TTR("Move Horizontal Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} else {
hguides.push_back(edited.y);
undo_redo->create_action(TTR("Create Horizontal Guide"));
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
} else {
@@ -1180,7 +1181,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
}
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -1196,7 +1197,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides);
undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides);
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -1204,7 +1205,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1379,7 +1380,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1393,7 +1394,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() == MouseButton::LEFT && b->is_pressed()) {
- if ((b->is_command_pressed() && !b->is_alt_pressed() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
+ if ((b->is_command_or_control_pressed() && !b->is_alt_pressed() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
// Remove not movable nodes
@@ -1429,7 +1430,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
//Rotate the opposite way if the canvas item's compounded scale has an uneven number of negative elements
bool opposite = (canvas_item->get_global_transform().get_scale().sign().dot(canvas_item->get_transform().get_scale().sign()) == 0);
canvas_item->_edit_set_rotation(snap_angle(canvas_item->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), canvas_item->_edit_get_rotation()));
- viewport->update();
+ viewport->queue_redraw();
}
return true;
}
@@ -1446,7 +1447,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
drag_selection,
vformat(TTR("Rotate CanvasItem \"%s\" to %d degrees"),
drag_selection[0]->get_name(),
- Math::rad2deg(drag_selection[0]->_edit_get_rotation())),
+ Math::rad_to_deg(drag_selection[0]->_edit_get_rotation())),
true);
}
@@ -1462,7 +1463,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1624,7 +1625,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1823,7 +1824,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -1833,7 +1834,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -1962,7 +1963,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -1970,7 +1971,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -2095,7 +2096,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -2105,7 +2106,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -2213,7 +2214,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
_reset_drag();
}
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -2338,7 +2339,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (!b->is_shift_pressed()) {
// Clear the selection if not additive
editor_selection->clear();
- viewport->update();
+ viewport->queue_redraw();
selected_from_canvas = true;
};
@@ -2414,21 +2415,21 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
if (b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
// Cancel box selection
_reset_drag();
- viewport->update();
+ viewport->queue_redraw();
return true;
}
if (m.is_valid()) {
// Update box selection
box_selecting_to = transform.affine_inverse().xform(m->get_position());
- viewport->update();
+ viewport->queue_redraw();
return true;
}
}
@@ -2436,7 +2437,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) {
// Unselect everything
editor_selection->clear();
- viewport->update();
+ viewport->queue_redraw();
}
return false;
}
@@ -2462,12 +2463,12 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
ruler_tool_active = false;
}
- viewport->update();
+ viewport->queue_redraw();
return true;
}
if (m.is_valid() && (ruler_tool_active || (grid_snap_active && previous_origin != ruler_tool_origin))) {
- viewport->update();
+ viewport->queue_redraw();
return true;
}
@@ -2479,7 +2480,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
if (m.is_valid()) {
Point2 click = transform.affine_inverse().xform(m->get_position());
- // Checks if the hovered items changed, update the viewport if so
+ // Checks if the hovered items changed, redraw the viewport if so
Vector<_SelectResult> hovering_results_items;
_get_canvas_items_at_pos(click, hovering_results_items);
hovering_results_items.sort();
@@ -2501,7 +2502,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
hovering_results_tmp.push_back(hover_result);
}
- // Check if changed, if so, update.
+ // Check if changed, if so, redraw.
bool changed = false;
if (hovering_results_tmp.size() == hovering_results.size()) {
for (int i = 0; i < hovering_results_tmp.size(); i++) {
@@ -2518,7 +2519,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
if (changed) {
hovering_results = hovering_results_tmp;
- viewport->update();
+ viewport->queue_redraw();
}
return true;
@@ -2957,6 +2958,9 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 corner = Point2(begin.x, end.y);
Vector2 length_vector = (begin - end).abs() / zoom;
+ const real_t horizontal_angle_rad = length_vector.angle();
+ const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
+
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"));
@@ -2973,6 +2977,42 @@ void CanvasItemEditor::_draw_ruler_tool() {
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);
+ // Draw lines.
+ viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3));
+
+ bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x));
+ 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));
+
+ // Angle arcs.
+ int arc_point_count = 8;
+ real_t arc_radius_max_length_percent = 0.1;
+ real_t ruler_length = length_vector.length() * zoom;
+ real_t arc_max_radius = 50.0;
+ real_t arc_line_width = 2.0;
+
+ const Vector2 end_to_begin = (end - begin);
+
+ real_t arc_1_start_angle = end_to_begin.x < 0
+ ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0)
+ : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
+ real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
+ // Constrain arc to triangle height & max size.
+ real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
+
+ real_t arc_2_start_angle = end_to_begin.x < 0
+ ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad)
+ : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
+ real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
+ // Constrain arc to triangle width & max size.
+ real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
+
+ viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
+ viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
+ }
+
+ // Draw text.
if (begin.is_equal_approx(end)) {
viewport->draw_string_outline(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
@@ -2984,17 +3024,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_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();
- const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
const int horizontal_angle = round(180 * horizontal_angle_rad / Math_PI);
const int vertical_angle = round(180 * vertical_angle_rad / Math_PI);
@@ -3031,32 +3061,6 @@ void CanvasItemEditor::_draw_ruler_tool() {
}
viewport->draw_string_outline(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, 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);
-
- // Angle arcs
- int arc_point_count = 8;
- real_t arc_radius_max_length_percent = 0.1;
- real_t ruler_length = length_vector.length() * zoom;
- real_t arc_max_radius = 50.0;
- real_t arc_line_width = 2.0;
-
- const Vector2 end_to_begin = (end - begin);
-
- real_t arc_1_start_angle = end_to_begin.x < 0
- ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0)
- : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
- real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
- // Constrain arc to triangle height & max size
- real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
-
- real_t arc_2_start_angle = end_to_begin.x < 0
- ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad)
- : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
- real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
- // Constrain arc to triangle width & max size
- real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
-
- viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
- viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
}
if (grid_snap_active) {
@@ -3672,7 +3676,7 @@ void CanvasItemEditor::_draw_transform_message() {
} break;
case DRAG_ROTATE: {
- real_t delta = Math::rad2deg(current_transform.get_rotation() - original_transform.get_rotation());
+ real_t delta = Math::rad_to_deg(current_transform.get_rotation() - original_transform.get_rotation());
transform_message = TTR("Rotating:") + " " + FORMAT(delta) + String::utf8(" °");
} break;
@@ -3823,7 +3827,7 @@ void CanvasItemEditor::_draw_viewport() {
void CanvasItemEditor::update_viewport() {
_update_scrollbars();
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::set_current_tool(Tool p_tool) {
@@ -3891,7 +3895,7 @@ void CanvasItemEditor::_notification(int p_what) {
Transform2D xform = canvas_item->get_transform();
if (rect != se->prev_rect || xform != se->prev_xform) {
- viewport->update();
+ viewport->queue_redraw();
se->prev_rect = rect;
se->prev_xform = xform;
}
@@ -3913,7 +3917,7 @@ void CanvasItemEditor::_notification(int p_what) {
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();
+ viewport->queue_redraw();
}
}
@@ -3929,7 +3933,7 @@ void CanvasItemEditor::_notification(int p_what) {
for (KeyValue<BoneKey, BoneList> &E : bone_list) {
Object *b = ObjectDB::get_instance(E.key.from);
if (!b) {
- viewport->update();
+ viewport->queue_redraw();
break;
}
@@ -3942,23 +3946,21 @@ void CanvasItemEditor::_notification(int p_what) {
if (global_xform != E.value.xform) {
E.value.xform = global_xform;
- viewport->update();
+ viewport->queue_redraw();
}
Bone2D *bone = Object::cast_to<Bone2D>(b);
if (bone && bone->get_length() != E.value.length) {
E.value.length = bone->get_length();
- viewport->update();
+ viewport->queue_redraw();
}
}
} break;
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);
- }
+ select_sb->set_margin_size_all(4);
+ select_sb->set_default_margin_all(4);
AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
_keying_changed();
@@ -3988,6 +3990,10 @@ void CanvasItemEditor::_selection_changed() {
selected_from_canvas = false;
}
+void CanvasItemEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
Array selection = editor_selection->get_selected_nodes();
if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) {
@@ -4098,7 +4104,7 @@ void CanvasItemEditor::_update_scroll(real_t) {
view_offset.x = h_scroll->get_value();
view_offset.y = v_scroll->get_value();
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) {
@@ -4140,12 +4146,12 @@ void CanvasItemEditor::_shortcut_zoom_set(real_t p_zoom) {
void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) {
smart_snap_active = p_status;
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
grid_snap_active = p_status;
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::_button_override_camera(bool p_pressed) {
@@ -4166,7 +4172,7 @@ void CanvasItemEditor::_button_tool_select(int p_index) {
tool = (Tool)p_index;
- viewport->update();
+ viewport->queue_redraw();
_update_cursor();
}
@@ -4253,11 +4259,11 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
if (p_game_running) {
override_camera_button->set_disabled(false);
- override_camera_button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
+ override_camera_button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
} else {
override_camera_button->set_disabled(true);
override_camera_button->set_pressed(false);
- override_camera_button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
+ override_camera_button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
}
}
@@ -4268,25 +4274,25 @@ void CanvasItemEditor::_popup_callback(int p_op) {
show_origin = !show_origin;
int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN);
view_menu->get_popup()->set_item_checked(idx, show_origin);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_VIEWPORT: {
show_viewport = !show_viewport;
int idx = view_menu->get_popup()->get_item_index(SHOW_VIEWPORT);
view_menu->get_popup()->set_item_checked(idx, show_viewport);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_EDIT_LOCKS: {
show_edit_locks = !show_edit_locks;
int idx = view_menu->get_popup()->get_item_index(SHOW_EDIT_LOCKS);
view_menu->get_popup()->set_item_checked(idx, show_edit_locks);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_TRANSFORMATION_GIZMOS: {
show_transformation_gizmos = !show_transformation_gizmos;
int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS);
view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SNAP_USE_NODE_PARENT: {
snap_node_parent = !snap_node_parent;
@@ -4332,7 +4338,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
snap_relative = !snap_relative;
int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE);
snap_config_menu->get_popup()->set_item_checked(idx, snap_relative);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SNAP_USE_PIXEL: {
snap_pixel = !snap_pixel;
@@ -4362,20 +4368,20 @@ void CanvasItemEditor::_popup_callback(int p_op) {
show_helpers = !show_helpers;
int idx = view_menu->get_popup()->get_item_index(SHOW_HELPERS);
view_menu->get_popup()->set_item_checked(idx, show_helpers);
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_RULERS: {
show_rulers = !show_rulers;
int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS);
view_menu->get_popup()->set_item_checked(idx, show_rulers);
_update_scrollbars();
- viewport->update();
+ viewport->queue_redraw();
} break;
case SHOW_GUIDES: {
show_guides = !show_guides;
int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES);
view_menu->get_popup()->set_item_checked(idx, show_guides);
- viewport->update();
+ viewport->queue_redraw();
} break;
case LOCK_SELECTED: {
undo_redo->create_action(TTR("Lock Selected"));
@@ -4395,8 +4401,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");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
case UNLOCK_SELECTED: {
@@ -4417,8 +4423,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");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
case GROUP_SELECTED: {
@@ -4439,8 +4445,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");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
case UNGROUP_SELECTED: {
@@ -4461,8 +4467,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");
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_do_method(viewport, "queue_redraw");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
} break;
@@ -4582,7 +4588,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
undo_redo->add_do_method(root, "remove_meta", "_edit_vertical_guides_");
undo_redo->add_undo_method(root, "set_meta", "_edit_vertical_guides_", vguides);
}
- undo_redo->add_undo_method(viewport, "update");
+ undo_redo->add_undo_method(viewport, "queue_redraw");
undo_redo->commit_action();
}
@@ -4696,7 +4702,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
real_t scale_y = viewport->get_size().y / rect.size.y;
zoom = scale_x < scale_y ? scale_x : scale_y;
zoom *= 0.90;
- viewport->update();
+ viewport->queue_redraw();
zoom_widget->set_zoom(zoom);
call_deferred(SNAME("_popup_callback"), VIEW_CENTER_TO_SELECTION);
}
@@ -4922,7 +4928,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
if (update_scrollbars) {
_update_scrollbars();
}
- viewport->update();
+ viewport->queue_redraw();
}
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
@@ -4972,7 +4978,7 @@ CanvasItemEditor::CanvasItemEditor() {
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((CanvasItem *)this, &CanvasItem::queue_redraw));
editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed));
SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
@@ -5020,17 +5026,36 @@ CanvasItemEditor::CanvasItemEditor() {
controls_vb->set_begin(Point2(5, 5));
// To ensure that scripts can parse the list of shortcuts correctly, we have to define
- // those shortcuts one by one. Define shortcut before using it (by EditorZoomWidget)
- 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_ARRAY("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"), { (int32_t)Key::KEY_1, (int32_t)(KeyModifierMask::CMD | Key::KEY_0) });
- 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);
+ // those shortcuts one by one. Define shortcut before using it (by EditorZoomWidget).
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_3.125_percent", TTR("Zoom to 3.125%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_5), int32_t(KeyModifierMask::SHIFT | Key::KP_5) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_6.25_percent", TTR("Zoom to 6.25%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_4), int32_t(KeyModifierMask::SHIFT | Key::KP_4) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_12.5_percent", TTR("Zoom to 12.5%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_3), int32_t(KeyModifierMask::SHIFT | Key::KP_3) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_25_percent", TTR("Zoom to 25%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_2), int32_t(KeyModifierMask::SHIFT | Key::KP_2) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_50_percent", TTR("Zoom to 50%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_1), int32_t(KeyModifierMask::SHIFT | Key::KP_1) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"),
+ { int32_t(Key::KEY_1), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KEY_0), int32_t(Key::KP_1), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KP_0) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_200_percent", TTR("Zoom to 200%"),
+ { int32_t(Key::KEY_2), int32_t(Key::KP_2) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_400_percent", TTR("Zoom to 400%"),
+ { int32_t(Key::KEY_3), int32_t(Key::KP_3) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_800_percent", TTR("Zoom to 800%"),
+ { int32_t(Key::KEY_4), int32_t(Key::KP_4) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_1600_percent", TTR("Zoom to 1600%"),
+ { int32_t(Key::KEY_5), int32_t(Key::KP_5) });
zoom_widget = memnew(EditorZoomWidget);
controls_vb->add_child(zoom_widget);
@@ -5077,7 +5102,7 @@ CanvasItemEditor::CanvasItemEditor() {
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_context(this);
- 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."));
+ select_button->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + 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_OR_CTRL) + TTR("RMB: Add node at position clicked."));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5088,7 +5113,7 @@ CanvasItemEditor::CanvasItemEditor() {
move_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_MOVE));
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"));
+ move_button->set_tooltip_text(TTR("Move Mode"));
rotate_button = memnew(Button);
rotate_button->set_flat(true);
@@ -5097,7 +5122,7 @@ CanvasItemEditor::CanvasItemEditor() {
rotate_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_ROTATE));
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"));
+ rotate_button->set_tooltip_text(TTR("Rotate Mode"));
scale_button = memnew(Button);
scale_button->set_flat(true);
@@ -5106,7 +5131,7 @@ CanvasItemEditor::CanvasItemEditor() {
scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_SCALE));
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("Shift: Scale proportionally."));
+ scale_button->set_tooltip_text(TTR("Shift: Scale proportionally."));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5115,14 +5140,14 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(list_select_button);
list_select_button->set_toggle_mode(true);
list_select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_LIST_SELECT));
- list_select_button->set_tooltip(TTR("Show list of selectable nodes at position clicked."));
+ list_select_button->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
pivot_button = memnew(Button);
pivot_button->set_flat(true);
main_menu_hbox->add_child(pivot_button);
pivot_button->set_toggle_mode(true);
pivot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_EDIT_PIVOT));
- pivot_button->set_tooltip(TTR("Click to change object's rotation pivot."));
+ pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot."));
pan_button = memnew(Button);
pan_button->set_flat(true);
@@ -5131,7 +5156,7 @@ CanvasItemEditor::CanvasItemEditor() {
pan_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_PAN));
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."));
+ pan_button->set_tooltip_text(TTR("You can also use Pan View shortcut (Space by default) to pan in any mode."));
ruler_button = memnew(Button);
ruler_button->set_flat(true);
@@ -5140,7 +5165,7 @@ CanvasItemEditor::CanvasItemEditor() {
ruler_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_RULER));
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"));
+ ruler_button->set_tooltip_text(TTR("Ruler Mode"));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5149,7 +5174,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(smart_snap_button);
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_tooltip_text(TTR("Toggle smart snapping."));
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);
@@ -5158,7 +5183,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(grid_snap_button);
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_tooltip_text(TTR("Toggle grid snapping."));
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);
@@ -5166,7 +5191,7 @@ CanvasItemEditor::CanvasItemEditor() {
snap_config_menu->set_shortcut_context(this);
main_menu_hbox->add_child(snap_config_menu);
snap_config_menu->set_h_size_flags(SIZE_SHRINK_END);
- snap_config_menu->set_tooltip(TTR("Snapping Options"));
+ snap_config_menu->set_tooltip_text(TTR("Snapping Options"));
snap_config_menu->set_switch_on_hover(true);
PopupMenu *p = snap_config_menu->get_popup();
@@ -5200,47 +5225,47 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(lock_button);
lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(LOCK_SELECTED));
- lock_button->set_tooltip(TTR("Lock selected node, preventing selection and movement."));
+ lock_button->set_tooltip_text(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)"), KeyModifierMask::CMD | Key::L));
+ lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::L));
unlock_button = memnew(Button);
unlock_button->set_flat(true);
main_menu_hbox->add_child(unlock_button);
unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNLOCK_SELECTED));
- unlock_button->set_tooltip(TTR("Unlock selected node, allowing selection and movement."));
+ unlock_button->set_tooltip_text(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)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L));
+ unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::L));
group_button = memnew(Button);
group_button->set_flat(true);
main_menu_hbox->add_child(group_button);
group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(GROUP_SELECTED));
- group_button->set_tooltip(TTR("Make selected node's children not selectable."));
+ group_button->set_tooltip_text(TTR("Make selected node's children 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)"), KeyModifierMask::CMD | Key::G));
+ group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G));
ungroup_button = memnew(Button);
ungroup_button->set_flat(true);
main_menu_hbox->add_child(ungroup_button);
ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNGROUP_SELECTED));
- ungroup_button->set_tooltip(TTR("Make selected node's children selectable."));
+ ungroup_button->set_tooltip_text(TTR("Make selected node's children selectable."));
// 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)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
+ ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G));
main_menu_hbox->add_child(memnew(VSeparator));
skeleton_menu = memnew(MenuButton);
skeleton_menu->set_shortcut_context(this);
main_menu_hbox->add_child(skeleton_menu);
- skeleton_menu->set_tooltip(TTR("Skeleton Options"));
+ skeleton_menu->set_tooltip_text(TTR("Skeleton Options"));
skeleton_menu->set_switch_on_hover(true);
p = skeleton_menu->get_popup();
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)"), KeyModifierMask::CMD | KeyModifierMask::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_OR_CTRL | KeyModifierMask::SHIFT | Key::B), SKELETON_MAKE_BONES);
p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5274,7 +5299,7 @@ CanvasItemEditor::CanvasItemEditor() {
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));
+ grid_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/toggle_grid", TTR("Toggle Grid"), KeyModifierMask::CMD_OR_CTRL | Key::APOSTROPHE));
p->add_child(grid_menu);
p->add_submenu_item(TTR("Grid"), "GridMenu");
@@ -5291,7 +5316,7 @@ CanvasItemEditor::CanvasItemEditor() {
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"), KeyModifierMask::SHIFT | KeyModifierMask::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_OR_CTRL | Key::P), PREVIEW_CANVAS_SCALE);
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5313,7 +5338,7 @@ CanvasItemEditor::CanvasItemEditor() {
key_loc_button->set_pressed(true);
key_loc_button->set_focus_mode(FOCUS_NONE);
key_loc_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_POS));
- key_loc_button->set_tooltip(TTR("Translation mask for inserting keys."));
+ key_loc_button->set_tooltip_text(TTR("Translation mask for inserting keys."));
animation_hb->add_child(key_loc_button);
key_rot_button = memnew(Button);
@@ -5322,7 +5347,7 @@ CanvasItemEditor::CanvasItemEditor() {
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
key_rot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_ROT));
- key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys."));
+ key_rot_button->set_tooltip_text(TTR("Rotation mask for inserting keys."));
animation_hb->add_child(key_rot_button);
key_scale_button = memnew(Button);
@@ -5330,14 +5355,14 @@ CanvasItemEditor::CanvasItemEditor() {
key_scale_button->set_toggle_mode(true);
key_scale_button->set_focus_mode(FOCUS_NONE);
key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_SCALE));
- key_scale_button->set_tooltip(TTR("Scale mask for inserting keys."));
+ key_scale_button->set_tooltip_text(TTR("Scale mask for inserting keys."));
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_KEY));
- key_insert_button->set_tooltip(TTR("Insert keys (based on mask)."));
+ key_insert_button->set_tooltip_text(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_context(this);
animation_hb->add_child(key_insert_button);
@@ -5346,14 +5371,14 @@ CanvasItemEditor::CanvasItemEditor() {
key_auto_insert_button->set_flat(true);
key_auto_insert_button->set_toggle_mode(true);
key_auto_insert_button->set_focus_mode(FOCUS_NONE);
- key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time."));
+ key_auto_insert_button->set_tooltip_text(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time."));
key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key")));
key_auto_insert_button->set_shortcut_context(this);
animation_hb->add_child(key_auto_insert_button);
animation_menu = memnew(MenuButton);
animation_menu->set_shortcut_context(this);
- animation_menu->set_tooltip(TTR("Animation Key and Pose Options"));
+ animation_menu->set_tooltip_text(TTR("Animation Key and Pose Options"));
animation_hb->add_child(animation_menu);
animation_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
animation_menu->set_switch_on_hover(true);
@@ -5361,7 +5386,7 @@ CanvasItemEditor::CanvasItemEditor() {
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)"), KeyModifierMask::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_OR_CTRL + 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);
@@ -5400,7 +5425,7 @@ CanvasItemEditor::CanvasItemEditor() {
CanvasItemEditor *CanvasItemEditor::singleton = nullptr;
void CanvasItemEditorPlugin::edit(Object *p_object) {
- canvas_item_editor->set_undo_redo(&get_undo_redo());
+ canvas_item_editor->set_undo_redo(EditorNode::get_undo_redo());
canvas_item_editor->edit(Object::cast_to<CanvasItem>(p_object));
}
@@ -5432,7 +5457,7 @@ void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) {
CanvasItemEditorPlugin::CanvasItemEditorPlugin() {
canvas_item_editor = memnew(CanvasItemEditor);
canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- EditorNode::get_singleton()->get_main_control()->add_child(canvas_item_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(canvas_item_editor);
canvas_item_editor->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
canvas_item_editor->hide();
}
@@ -5536,51 +5561,39 @@ bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_targe
void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point) {
// 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;
- }
- child->set_name(name);
+ child->set_name(Node::adjust_name_casing(name));
Ref<Texture2D> texture = ResourceCache::get_ref(path);
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", 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);
+ editor_data->get_undo_redo()->add_do_method(parent, "add_child", child, true);
+ 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(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(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ 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(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", 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));
+ 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));
}
if (Object::cast_to<TouchScreenButton>(child) || Object::cast_to<TextureButton>(child)) {
- editor_data->get_undo_redo().add_do_property(child, "texture_normal", texture);
+ editor_data->get_undo_redo()->add_do_property(child, "texture_normal", texture);
} else {
- editor_data->get_undo_redo().add_do_property(child, "texture", texture);
+ editor_data->get_undo_redo()->add_do_property(child, "texture", texture);
}
// make visible for certain node type
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);
+ editor_data->get_undo_redo()->add_do_property(child, "rect_size", texture_size);
} else if (Object::cast_to<Polygon2D>(child)) {
Size2 texture_size = texture->get_size();
Vector<Vector2> list = {
@@ -5589,7 +5602,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
Vector2(texture_size.width, texture_size.height),
Vector2(0, texture_size.height)
};
- editor_data->get_undo_redo().add_do_property(child, "polygon", list);
+ editor_data->get_undo_redo()->add_do_property(child, "polygon", list);
}
// Compute the global position
@@ -5598,7 +5611,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
// there's nothing to be used as source position so snapping will work as absolute if enabled
target_position = canvas_item_editor->snap_point(target_position);
- editor_data->get_undo_redo().add_do_method(child, "set_global_position", target_position);
+ editor_data->get_undo_redo()->add_do_method(child, "set_global_position", target_position);
}
bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
@@ -5623,15 +5636,15 @@ 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, 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);
+ 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", 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));
+ 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 *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene);
if (instance_ci) {
@@ -5645,7 +5658,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
// 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);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_position", target_pos);
}
return true;
@@ -5663,7 +5676,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
Vector<String> error_files;
- editor_data->get_undo_redo().create_action(TTR("Create Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Create Node"));
for (int i = 0; i < selected_files.size(); i++) {
String path = selected_files[i];
@@ -5694,7 +5707,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
}
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
if (error_files.size() > 0) {
String files_str;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 04fd819dec..0a840d6fd6 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -45,6 +45,7 @@
class EditorData;
class CanvasItemEditorViewport;
class ViewPanner;
+class EditorUndoRedoManager;
class CanvasItemEditorSelectedItem : public Object {
GDCLASS(CanvasItemEditorSelectedItem, Object);
@@ -214,7 +215,7 @@ private:
int primary_grid_steps = 8;
int grid_step_multiplier = 0;
- real_t snap_rotation_step = Math::deg2rad(15.0);
+ real_t snap_rotation_step = Math::deg_to_rad(15.0);
real_t snap_rotation_offset = 0.0;
real_t snap_scale_step = 0.1f;
bool smart_snap_active = false;
@@ -400,7 +401,7 @@ private:
void _prepare_grid_menu();
void _on_grid_menu_id_pressed(int p_id);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
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);
@@ -547,7 +548,7 @@ public:
Tool get_current_tool() { return tool; }
void set_current_tool(Tool p_tool);
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(CanvasItem *p_canvas_item);
void focus_selection();
diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp
index 18c38e7ab8..a8d255f997 100644
--- a/editor/plugins/cast_2d_editor_plugin.cpp
+++ b/editor/plugins/cast_2d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/ray_cast_2d.h"
#include "scene/2d/shape_cast_2d.h"
diff --git a/editor/plugins/cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h
index d9c0cc4a06..ceed9b9111 100644
--- a/editor/plugins/cast_2d_editor_plugin.h
+++ b/editor/plugins/cast_2d_editor_plugin.h
@@ -35,13 +35,14 @@
#include "scene/2d/node_2d.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class Cast2DEditor : public Control {
GDCLASS(Cast2DEditor, Control);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
- Node2D *node;
+ Node2D *node = nullptr;
bool pressed = false;
Point2 original_target_position;
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index af20064a8d..11992ad10e 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -33,6 +33,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/resources/capsule_shape_2d.h"
#include "scene/resources/circle_shape_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index f7de05ddd1..49e0820ae9 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -35,6 +35,7 @@
#include "scene/2d/collision_shape_2d.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class CollisionShape2DEditor : public Control {
GDCLASS(CollisionShape2DEditor, Control);
@@ -61,7 +62,7 @@ class CollisionShape2DEditor : public Control {
Point2(1, -1),
};
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
CollisionShape2D *node = nullptr;
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index 2756e45cf4..bb6092755e 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -31,10 +31,14 @@
#include "control_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/gui/separator.h"
+// Inspector controls.
+
void ControlPositioningWarning::_update_warning() {
if (!control_node) {
title_icon->set_texture(nullptr);
@@ -49,7 +53,7 @@ void ControlPositioningWarning::_update_warning() {
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_icon->set_texture(get_theme_icon(SNAME("ContainerLayout"), 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 {
@@ -65,14 +69,14 @@ 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."));
+ set_tooltip_text(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."));
+ set_tooltip_text(TTR("Expand positioning hint."));
}
hint_icon->set_texture(arrow);
@@ -448,37 +452,280 @@ bool EditorInspectorPluginControl::parse_property(Object *p_object, const Varian
return false;
}
-void ControlEditorToolbar::_set_anchors_and_offsets_preset(Control::LayoutPreset p_preset) {
+// Toolbars controls.
+
+Size2 ControlEditorPopupButton::get_minimum_size() const {
+ Vector2 base_size = Vector2(26, 26) * EDSCALE;
+
+ if (arrow_icon.is_null()) {
+ return base_size;
+ }
+
+ Vector2 final_size;
+ final_size.x = base_size.x + arrow_icon->get_width();
+ final_size.y = MAX(base_size.y, arrow_icon->get_height());
+
+ return final_size;
+}
+
+void ControlEditorPopupButton::toggled(bool p_pressed) {
+ if (!p_pressed) {
+ return;
+ }
+
+ Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
+
+ popup_panel->set_size(Size2(size.width, 0));
+ Point2 gp = get_screen_position();
+ gp.y += size.y;
+ if (is_layout_rtl()) {
+ gp.x += size.width - popup_panel->get_size().width;
+ }
+ popup_panel->set_position(gp);
+
+ popup_panel->popup();
+}
+
+void ControlEditorPopupButton::_popup_visibility_changed(bool p_visible) {
+ set_pressed(p_visible);
+}
+
+void ControlEditorPopupButton::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ arrow_icon = get_theme_icon("select_arrow", "Tree");
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ if (arrow_icon.is_valid()) {
+ Vector2 arrow_pos = Point2(26, 0) * EDSCALE;
+ arrow_pos.y = get_size().y / 2 - arrow_icon->get_height() / 2;
+ draw_texture(arrow_icon, arrow_pos);
+ }
+ } break;
+
+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
+ popup_panel->set_layout_direction((Window::LayoutDirection)get_layout_direction());
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible_in_tree()) {
+ popup_panel->hide();
+ }
+ } break;
+ }
+}
+
+ControlEditorPopupButton::ControlEditorPopupButton() {
+ set_flat(true);
+ set_toggle_mode(true);
+ set_focus_mode(FOCUS_NONE);
+
+ popup_panel = memnew(PopupPanel);
+ popup_panel->set_theme_type_variation("ControlEditorPopupPanel");
+ add_child(popup_panel);
+ popup_panel->connect("about_to_popup", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(true));
+ popup_panel->connect("popup_hide", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(false));
+
+ popup_vbox = memnew(VBoxContainer);
+ popup_panel->add_child(popup_vbox);
+}
+
+void ControlEditorPresetPicker::_add_row_button(HBoxContainer *p_row, const int p_preset, const String &p_name) {
+ ERR_FAIL_COND(preset_buttons.has(p_preset));
+
+ Button *b = memnew(Button);
+ b->set_custom_minimum_size(Size2i(36, 36) * EDSCALE);
+ b->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ b->set_tooltip_text(p_name);
+ b->set_flat(true);
+ p_row->add_child(b);
+ b->connect("pressed", callable_mp(this, &ControlEditorPresetPicker::_preset_button_pressed).bind(p_preset));
+
+ preset_buttons[p_preset] = b;
+}
+
+void ControlEditorPresetPicker::_add_separator(BoxContainer *p_box, Separator *p_separator) {
+ p_separator->add_theme_constant_override("separation", grid_separation);
+ p_separator->set_custom_minimum_size(Size2i(1, 1));
+ p_box->add_child(p_separator);
+}
+
+void AnchorPresetPicker::_preset_button_pressed(const int p_preset) {
+ emit_signal("anchors_preset_selected", p_preset);
+}
+
+void AnchorPresetPicker::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ preset_buttons[PRESET_TOP_LEFT]->set_icon(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER_TOP]->set_icon(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_TOP_RIGHT]->set_icon(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_CENTER_LEFT]->set_icon(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER]->set_icon(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER_RIGHT]->set_icon(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_BOTTOM_LEFT]->set_icon(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER_BOTTOM]->set_icon(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_BOTTOM_RIGHT]->set_icon(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_TOP_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_HCENTER_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_BOTTOM_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_LEFT_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_VCENTER_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_RIGHT_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_FULL_RECT]->set_icon(get_theme_icon(SNAME("ControlAlignFullRect"), SNAME("EditorIcons")));
+ } break;
+ }
+}
+
+void AnchorPresetPicker::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("anchors_preset_selected", PropertyInfo(Variant::INT, "preset")));
+}
+
+AnchorPresetPicker::AnchorPresetPicker() {
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ main_vb->add_theme_constant_override("separation", grid_separation);
+ add_child(main_vb);
+
+ HBoxContainer *top_row = memnew(HBoxContainer);
+ top_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ top_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(top_row);
+
+ _add_row_button(top_row, PRESET_TOP_LEFT, TTR("Top Left"));
+ _add_row_button(top_row, PRESET_CENTER_TOP, TTR("Center Top"));
+ _add_row_button(top_row, PRESET_TOP_RIGHT, TTR("Top Right"));
+ _add_separator(top_row, memnew(VSeparator));
+ _add_row_button(top_row, PRESET_TOP_WIDE, TTR("Top Wide"));
+
+ HBoxContainer *mid_row = memnew(HBoxContainer);
+ mid_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ mid_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(mid_row);
+
+ _add_row_button(mid_row, PRESET_CENTER_LEFT, TTR("Center Left"));
+ _add_row_button(mid_row, PRESET_CENTER, TTR("Center"));
+ _add_row_button(mid_row, PRESET_CENTER_RIGHT, TTR("Center Right"));
+ _add_separator(mid_row, memnew(VSeparator));
+ _add_row_button(mid_row, PRESET_HCENTER_WIDE, TTR("HCenter Wide"));
+
+ HBoxContainer *bot_row = memnew(HBoxContainer);
+ bot_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ bot_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(bot_row);
+
+ _add_row_button(bot_row, PRESET_BOTTOM_LEFT, TTR("Bottom Left"));
+ _add_row_button(bot_row, PRESET_CENTER_BOTTOM, TTR("Center Bottom"));
+ _add_row_button(bot_row, PRESET_BOTTOM_RIGHT, TTR("Bottom Right"));
+ _add_separator(bot_row, memnew(VSeparator));
+ _add_row_button(bot_row, PRESET_BOTTOM_WIDE, TTR("Bottom Wide"));
+
+ _add_separator(main_vb, memnew(HSeparator));
+
+ HBoxContainer *extra_row = memnew(HBoxContainer);
+ extra_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ extra_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(extra_row);
+
+ _add_row_button(extra_row, PRESET_LEFT_WIDE, TTR("Left Wide"));
+ _add_row_button(extra_row, PRESET_VCENTER_WIDE, TTR("VCenter Wide"));
+ _add_row_button(extra_row, PRESET_RIGHT_WIDE, TTR("Right Wide"));
+ _add_separator(extra_row, memnew(VSeparator));
+ _add_row_button(extra_row, PRESET_FULL_RECT, TTR("Full Rect"));
+}
+
+void SizeFlagPresetPicker::_preset_button_pressed(const int p_preset) {
+ int flags = (SizeFlags)p_preset;
+ if (expand_button->is_pressed()) {
+ flags |= SIZE_EXPAND;
+ }
+
+ emit_signal("size_flags_selected", flags);
+}
+
+void SizeFlagPresetPicker::set_allowed_flags(Vector<SizeFlags> &p_flags) {
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_disabled(!p_flags.has(SIZE_SHRINK_BEGIN));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_disabled(!p_flags.has(SIZE_SHRINK_CENTER));
+ preset_buttons[SIZE_SHRINK_END]->set_disabled(!p_flags.has(SIZE_SHRINK_END));
+ preset_buttons[SIZE_FILL]->set_disabled(!p_flags.has(SIZE_FILL));
+
+ expand_button->set_disabled(!p_flags.has(SIZE_EXPAND));
+ if (p_flags.has(SIZE_EXPAND)) {
+ expand_button->set_tooltip_text(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags."));
+ } else {
+ expand_button->set_pressed(false);
+ expand_button->set_tooltip_text(TTR("Some parents of the selected nodes do not support the Expand flag."));
+ }
+}
+
+void SizeFlagPresetPicker::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ if (vertical) {
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_icon(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_icon(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_END]->set_icon(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")));
+
+ preset_buttons[SIZE_FILL]->set_icon(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")));
+ } else {
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_icon(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_icon(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_END]->set_icon(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")));
+
+ preset_buttons[SIZE_FILL]->set_icon(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")));
+ }
+ } break;
+ }
+}
+
+void SizeFlagPresetPicker::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("size_flags_selected", PropertyInfo(Variant::INT, "size_flags")));
+}
+
+SizeFlagPresetPicker::SizeFlagPresetPicker(bool p_vertical) {
+ vertical = p_vertical;
+
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ add_child(main_vb);
+
+ HBoxContainer *main_row = memnew(HBoxContainer);
+ main_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ main_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(main_row);
+
+ _add_row_button(main_row, SIZE_SHRINK_BEGIN, TTR("Shrink Begin"));
+ _add_row_button(main_row, SIZE_SHRINK_CENTER, TTR("Shrink Center"));
+ _add_row_button(main_row, SIZE_SHRINK_END, TTR("Shrink End"));
+ _add_separator(main_row, memnew(VSeparator));
+ _add_row_button(main_row, SIZE_FILL, TTR("Fill"));
+
+ expand_button = memnew(CheckBox);
+ expand_button->set_flat(true);
+ expand_button->set_text(TTR("Align with Expand"));
+ expand_button->set_tooltip_text(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags."));
+ main_vb->add_child(expand_button);
+}
+
+// Toolbar.
+
+void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
+ LayoutPreset preset = (LayoutPreset)p_preset;
List<Node *> selection = editor_selection->get_selected_node_list();
- undo_redo->create_action(TTR("Change Anchors and Offsets"));
+ undo_redo->create_action(TTR("Change Anchors, Offsets, Grow Direction"));
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_FULL_RECT:
- undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_MINSIZE);
- break;
- }
+ undo_redo->add_do_property(control, "anchors_preset", preset);
undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
}
}
@@ -489,10 +736,10 @@ void ControlEditorToolbar::_set_anchors_and_offsets_preset(Control::LayoutPreset
anchor_mode_button->set_pressed(anchors_mode);
}
-void ControlEditorToolbar::_set_anchors_and_offsets_to_keep_ratio() {
+void ControlEditorToolbar::_anchors_to_current_ratio() {
List<Node *> selection = editor_selection->get_selected_node_list();
- undo_redo->create_action(TTR("Change Anchors and Offsets"));
+ undo_redo->create_action(TTR("Change Anchors, Offsets (Keep Ratio)"));
for (Node *E : selection) {
Control *control = Object::cast_to<Control>(E);
@@ -521,44 +768,41 @@ void ControlEditorToolbar::_set_anchors_and_offsets_to_keep_ratio() {
undo_redo->commit_action();
}
-void ControlEditorToolbar::_set_anchors_preset(Control::LayoutPreset p_preset) {
- List<Node *> selection = editor_selection->get_selected_node_list();
+void ControlEditorToolbar::_anchor_mode_toggled(bool p_status) {
+ List<Control *> selection = _get_edited_controls();
+ for (Control *E : selection) {
+ if (Object::cast_to<Container>(E->get_parent())) {
+ continue;
+ }
- 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());
+ if (p_status) {
+ E->set_meta("_edit_use_anchors_", true);
+ } else {
+ E->remove_meta("_edit_use_anchors_");
}
}
- undo_redo->commit_action();
+ anchors_mode = p_status;
+ CanvasItemEditor::get_singleton()->update_viewport();
}
-void ControlEditorToolbar::_set_container_h_preset(Control::SizeFlags p_preset) {
+void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertical) {
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());
- }
+ if (p_vertical) {
+ undo_redo->create_action(TTR("Change Vertical Size Flags"));
+ } else {
+ undo_redo->create_action(TTR("Change Horizontal Size Flags"));
}
- 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);
+ if (p_vertical) {
+ undo_redo->add_do_method(control, "set_v_size_flags", p_flags);
+ } else {
+ undo_redo->add_do_method(control, "set_h_size_flags", p_flags);
+ }
undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
}
}
@@ -594,400 +838,205 @@ Vector2 ControlEditorToolbar::_position_to_anchor(const Control *p_control, Vect
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->get_meta("_edit_lock_", false);
}
-List<Control *> ControlEditorToolbar::_get_edited_controls(bool retrieve_locked, bool remove_controls_if_parent_in_selection) {
+List<Control *> ControlEditorToolbar::_get_edited_controls() {
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))) {
+ if (control && control->is_visible_in_tree() && control->get_viewport() == EditorNode::get_singleton()->get_scene_root() && !_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_FULL_RECT: {
- _set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- } 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_FULL_RECT: {
- _set_anchors_preset(Control::PRESET_FULL_RECT);
- } 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;
+ // Update toolbar visibility.
+ bool has_controls = false;
+ bool has_control_parents = false;
+ bool has_container_parents = false;
+
+ // Also update which size flags can be configured for the selected nodes.
+ Vector<SizeFlags> allowed_h_flags = {
+ SIZE_SHRINK_BEGIN,
+ SIZE_SHRINK_CENTER,
+ SIZE_SHRINK_END,
+ SIZE_FILL,
+ SIZE_EXPAND,
+ };
+ Vector<SizeFlags> allowed_v_flags = {
+ SIZE_SHRINK_BEGIN,
+ SIZE_SHRINK_CENTER,
+ SIZE_SHRINK_END,
+ SIZE_FILL,
+ SIZE_EXPAND,
+ };
- List<Node *> selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
+ for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
+ Control *control = Object::cast_to<Control>(E.key);
if (!control) {
continue;
}
+ has_controls = true;
- nb_controls++;
+ if (Object::cast_to<Control>(control->get_parent())) {
+ has_control_parents = true;
+ }
if (Object::cast_to<Container>(control->get_parent())) {
- continue;
+ has_container_parents = true;
+
+ Container *parent_container = Object::cast_to<Container>(control->get_parent());
+
+ Vector<int> container_h_flags = parent_container->get_allowed_size_flags_horizontal();
+ Vector<SizeFlags> tmp_flags = allowed_h_flags.duplicate();
+ for (int i = 0; i < allowed_h_flags.size(); i++) {
+ if (!container_h_flags.has((int)allowed_h_flags[i])) {
+ tmp_flags.erase(allowed_h_flags[i]);
+ }
+ }
+ allowed_h_flags = tmp_flags;
+
+ Vector<int> container_v_flags = parent_container->get_allowed_size_flags_vertical();
+ tmp_flags = allowed_v_flags.duplicate();
+ for (int i = 0; i < allowed_v_flags.size(); i++) {
+ if (!container_v_flags.has((int)allowed_v_flags[i])) {
+ tmp_flags.erase(allowed_v_flags[i]);
+ }
+ }
+ allowed_v_flags = tmp_flags;
}
+ }
+
+ // Set general toolbar visibility.
+ set_visible(has_controls);
+
+ // Set anchor tools visibility.
+ if (has_controls && (!has_control_parents || !has_container_parents)) {
+ anchors_button->set_visible(true);
+ anchor_mode_button->set_visible(true);
+
+ // Update anchor mode.
+ int nb_valid_controls = 0;
+ int nb_anchors_mode = 0;
- nb_valid_controls++;
- if (control->get_meta("_edit_use_anchors_", false)) {
- nb_anchors_mode++;
+ 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;
+ }
+
+ nb_valid_controls++;
+ if (control->get_meta("_edit_use_anchors_", false)) {
+ nb_anchors_mode++;
+ }
}
+
+ anchors_mode = (nb_valid_controls == nb_anchors_mode);
+ anchor_mode_button->set_pressed(anchors_mode);
+ } else {
+ anchors_button->set_visible(false);
+ anchor_mode_button->set_visible(false);
+ anchor_mode_button->set_pressed(false);
}
- anchors_mode = (nb_valid_controls == nb_anchors_mode);
- anchor_mode_button->set_pressed(anchors_mode);
+ // Set container tools visibility.
+ if (has_controls && (!has_control_parents || has_container_parents)) {
+ containers_button->set_visible(true);
- if (nb_controls > 0) {
- set_physics_process(true);
+ // Update allowed size flags.
+ if (has_container_parents) {
+ container_h_picker->set_allowed_flags(allowed_h_flags);
+ container_v_picker->set_allowed_flags(allowed_v_flags);
+ } else {
+ Vector<SizeFlags> allowed_all_flags = {
+ SIZE_SHRINK_BEGIN,
+ SIZE_SHRINK_CENTER,
+ SIZE_SHRINK_END,
+ SIZE_FILL,
+ SIZE_EXPAND,
+ };
+
+ container_h_picker->set_allowed_flags(allowed_all_flags);
+ container_v_picker->set_allowed_flags(allowed_all_flags);
+ }
} else {
- set_physics_process(false);
- set_visible(false);
+ containers_button->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("ControlAlignFullRect"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_AND_OFFSETS_PRESET_FULL_RECT);
- 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("ControlAlignFullRect"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_PRESET_FULL_RECT);
-
+ case NOTIFICATION_THEME_CHANGED: {
+ anchors_button->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
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);
- }
+ containers_button->set_icon(get_theme_icon(SNAME("ContainerLayout"), SNAME("EditorIcons")));
} 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);
+ add_child(memnew(VSeparator));
- PopupMenu *p = anchor_presets_menu->get_popup();
- p->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
+ // Anchor and offset tools.
+ anchors_button = memnew(ControlEditorPopupButton);
+ anchors_button->set_tooltip_text(TTR("Presets for the anchor and offset values of a Control node."));
+ add_child(anchors_button);
- 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));
+ Label *anchors_label = memnew(Label);
+ anchors_label->set_text(TTR("Anchor preset"));
+ anchors_button->get_popup_hbox()->add_child(anchors_label);
+ AnchorPresetPicker *anchors_picker = memnew(AnchorPresetPicker);
+ anchors_picker->set_h_size_flags(SIZE_SHRINK_CENTER);
+ anchors_button->get_popup_hbox()->add_child(anchors_picker);
+ anchors_picker->connect("anchors_preset_selected", callable_mp(this, &ControlEditorToolbar::_anchors_preset_selected));
+
+ anchors_button->get_popup_hbox()->add_child(memnew(HSeparator));
+
+ Button *keep_ratio_button = memnew(Button);
+ keep_ratio_button->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
+ keep_ratio_button->set_text(TTR("Set to Current Ratio"));
+ keep_ratio_button->set_tooltip_text(TTR("Adjust anchors and offsets to match the current rect size."));
+ anchors_button->get_popup_hbox()->add_child(keep_ratio_button);
+ keep_ratio_button->connect("pressed", callable_mp(this, &ControlEditorToolbar::_anchors_to_current_ratio));
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."));
+ anchor_mode_button->set_tooltip_text(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));
-
+ anchor_mode_button->connect("toggled", callable_mp(this, &ControlEditorToolbar::_anchor_mode_toggled));
+
+ // Container tools.
+ containers_button = memnew(ControlEditorPopupButton);
+ containers_button->set_tooltip_text(TTR("Sizing settings for children of a Container node."));
+ add_child(containers_button);
+
+ Label *container_h_label = memnew(Label);
+ container_h_label->set_text(TTR("Horizontal alignment"));
+ containers_button->get_popup_hbox()->add_child(container_h_label);
+ container_h_picker = memnew(SizeFlagPresetPicker(false));
+ containers_button->get_popup_hbox()->add_child(container_h_picker);
+ container_h_picker->connect("size_flags_selected", callable_mp(this, &ControlEditorToolbar::_container_flags_selected).bind(false));
+
+ containers_button->get_popup_hbox()->add_child(memnew(HSeparator));
+
+ Label *container_v_label = memnew(Label);
+ container_v_label->set_text(TTR("Vertical alignment"));
+ containers_button->get_popup_hbox()->add_child(container_v_label);
+ container_v_picker = memnew(SizeFlagPresetPicker(true));
+ containers_button->get_popup_hbox()->add_child(container_v_picker);
+ container_v_picker->connect("size_flags_selected", callable_mp(this, &ControlEditorToolbar::_container_flags_selected).bind(true));
+
+ // Editor connections.
undo_redo = EditorNode::get_singleton()->get_undo_redo();
editor_selection = EditorNode::get_singleton()->get_editor_selection();
editor_selection->add_editor_plugin(this);
@@ -998,6 +1047,8 @@ ControlEditorToolbar::ControlEditorToolbar() {
ControlEditorToolbar *ControlEditorToolbar::singleton = nullptr;
+// Editor plugin.
+
ControlEditorPlugin::ControlEditorPlugin() {
toolbar = memnew(ControlEditorToolbar);
toolbar->hide();
diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h
index 11389bc095..22267cbc04 100644
--- a/editor/plugins/control_editor_plugin.h
+++ b/editor/plugins/control_editor_plugin.h
@@ -33,14 +33,20 @@
#include "editor/editor_plugin.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/button.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/popup.h"
+#include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h"
+class EditorUndoRedoManager;
+
+// Inspector controls.
class ControlPositioningWarning : public MarginContainer {
GDCLASS(ControlPositioningWarning, MarginContainer);
@@ -125,102 +131,101 @@ public:
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;
};
+// Toolbar controls.
+class ControlEditorPopupButton : public Button {
+ GDCLASS(ControlEditorPopupButton, Button);
+
+ Ref<Texture2D> arrow_icon;
+
+ PopupPanel *popup_panel = nullptr;
+ VBoxContainer *popup_vbox = nullptr;
+
+ void _popup_visibility_changed(bool p_visible);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ virtual Size2 get_minimum_size() const override;
+ virtual void toggled(bool p_pressed) override;
+
+ VBoxContainer *get_popup_hbox() const { return popup_vbox; }
+
+ ControlEditorPopupButton();
+};
+
+class ControlEditorPresetPicker : public MarginContainer {
+ GDCLASS(ControlEditorPresetPicker, MarginContainer);
+
+ virtual void _preset_button_pressed(const int p_preset) {}
+
+protected:
+ static constexpr int grid_separation = 0;
+ HashMap<int, Button *> preset_buttons;
+
+ void _add_row_button(HBoxContainer *p_row, const int p_preset, const String &p_name);
+ void _add_separator(BoxContainer *p_box, Separator *p_separator);
+
+public:
+ ControlEditorPresetPicker() {}
+};
+
+class AnchorPresetPicker : public ControlEditorPresetPicker {
+ GDCLASS(AnchorPresetPicker, ControlEditorPresetPicker);
+
+ virtual void _preset_button_pressed(const int p_preset) override;
+
+protected:
+ void _notification(int p_notification);
+ static void _bind_methods();
+
+public:
+ AnchorPresetPicker();
+};
+
+class SizeFlagPresetPicker : public ControlEditorPresetPicker {
+ GDCLASS(SizeFlagPresetPicker, ControlEditorPresetPicker);
+
+ CheckBox *expand_button = nullptr;
+
+ bool vertical = false;
+
+ virtual void _preset_button_pressed(const int p_preset) override;
+
+protected:
+ void _notification(int p_notification);
+ static void _bind_methods();
+
+public:
+ void set_allowed_flags(Vector<SizeFlags> &p_flags);
+
+ SizeFlagPresetPicker(bool p_vertical);
+};
+
class ControlEditorToolbar : public HBoxContainer {
GDCLASS(ControlEditorToolbar, HBoxContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
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_FULL_RECT,
-
- 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_FULL_RECT,
-
- // 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_FULL_RECT,
-
- 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;
-
+ ControlEditorPopupButton *anchors_button = nullptr;
+ ControlEditorPopupButton *containers_button = nullptr;
Button *anchor_mode_button = nullptr;
+ SizeFlagPresetPicker *container_h_picker = nullptr;
+ SizeFlagPresetPicker *container_v_picker = 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);
+ void _anchors_preset_selected(int p_preset);
+ void _anchors_to_current_ratio();
+ void _anchor_mode_toggled(bool p_status);
+ void _container_flags_selected(int p_flags, bool p_vertical);
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);
+ List<Control *> _get_edited_controls();
void _selection_changed();
protected:
@@ -236,6 +241,7 @@ public:
ControlEditorToolbar();
};
+// Editor plugin.
class ControlEditorPlugin : public EditorPlugin {
GDCLASS(ControlEditorPlugin, EditorPlugin);
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index a7c3c32120..e56fd5dfe3 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -34,9 +34,10 @@
#include "core/io/image_loader.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/separator.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
void CPUParticles2DEditorPlugin::edit(Object *p_object) {
particles = Object::cast_to<CPUParticles2D>(p_object);
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h
index cc59bc924f..06ca208463 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.h
@@ -39,6 +39,7 @@
class EditorPlugin;
class SpinBox;
class EditorFileDialog;
+class EditorUndoRedoManager;
class CPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin);
@@ -70,7 +71,7 @@ class CPUParticles2DEditorPlugin : public EditorPlugin {
String source_emission_file;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _file_selected(const String &p_file);
void _menu_callback(int p_idx);
void _generate_emission_mask();
diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
index 775c2dbb2a..ad12b8bef0 100644
--- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp
@@ -126,7 +126,7 @@ void CPUParticles3DEditorPlugin::make_visible(bool p_visible) {
CPUParticles3DEditorPlugin::CPUParticles3DEditorPlugin() {
particles_editor = memnew(CPUParticles3DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(particles_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(particles_editor);
particles_editor->hide();
}
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 8aeab684e3..8d1df0b32c 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -87,7 +87,7 @@ void CurveEditor::set_curve(Ref<Curve> curve) {
_hover_point = -1;
_selected_tangent = TANGENT_NONE;
- update();
+ queue_redraw();
// Note: if you edit a curve, then set another, and try to undo,
// it will normally apply on the previous curve, but you won't see it
@@ -139,14 +139,14 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
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();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
- ur.create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent"));
- ur.add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data());
- ur.add_undo_method(*_curve_ref, "_set_data", _undo_data);
+ ur->create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent"));
+ ur->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data());
+ ur->add_undo_method(*_curve_ref, "_set_data", _undo_data);
// Note: this will trigger one more "changed" signal even if nothing changes,
// but it's ok since it would have fired every frame during the drag anyways
- ur.commit_action();
+ ur->commit_action();
_has_undo_data = false;
}
@@ -301,17 +301,17 @@ void CurveEditor::on_preset_item_selected(int preset_id) {
break;
}
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Load Curve Preset"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Load Curve Preset"));
- ur.add_do_method(&curve, "_set_data", curve.get_data());
- ur.add_undo_method(&curve, "_set_data", previous_data);
+ ur->add_do_method(&curve, "_set_data", curve.get_data());
+ ur->add_undo_method(&curve, "_set_data", previous_data);
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::_curve_changed() {
- update();
+ queue_redraw();
// Point count can change in case of undo
if (_selected_point >= _curve_ref->get_point_count()) {
set_selected_point(-1);
@@ -435,8 +435,8 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const {
void CurveEditor::add_point(Vector2 pos) {
ERR_FAIL_COND(_curve_ref.is_null());
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Remove Curve Point"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Remove Curve Point"));
Vector2 point_pos = get_world_pos(pos);
if (point_pos.y < 0.0) {
@@ -449,22 +449,22 @@ void CurveEditor::add_point(Vector2 pos) {
int i = _curve_ref->add_point(point_pos);
_curve_ref->remove_point(i);
- ur.add_do_method(*_curve_ref, "add_point", point_pos);
- ur.add_undo_method(*_curve_ref, "remove_point", i);
+ ur->add_do_method(*_curve_ref, "add_point", point_pos);
+ ur->add_undo_method(*_curve_ref, "remove_point", i);
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::remove_point(int index) {
ERR_FAIL_COND(_curve_ref.is_null());
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Remove Curve Point"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Remove Curve Point"));
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.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode);
+ ur->add_do_method(*_curve_ref, "remove_point", index);
+ 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);
@@ -474,14 +474,14 @@ void CurveEditor::remove_point(int index) {
set_hover_point_index(-1);
}
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::toggle_linear(TangentIndex tangent) {
ERR_FAIL_COND(_curve_ref.is_null());
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Toggle Curve Linear Tangent"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Toggle Curve Linear Tangent"));
if (tangent == TANGENT_NONE) {
tangent = _selected_tangent;
@@ -493,8 +493,8 @@ void CurveEditor::toggle_linear(TangentIndex tangent) {
Curve::TangentMode prev_mode = _curve_ref->get_point_left_mode(_selected_point);
Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR;
- ur.add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode);
- ur.add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode);
+ ur->add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode);
+ ur->add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode);
} else {
bool is_linear = _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR;
@@ -502,24 +502,24 @@ void CurveEditor::toggle_linear(TangentIndex tangent) {
Curve::TangentMode prev_mode = _curve_ref->get_point_right_mode(_selected_point);
Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR;
- ur.add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode);
- ur.add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode);
+ ur->add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode);
+ ur->add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode);
}
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::set_selected_point(int index) {
if (index != _selected_point) {
_selected_point = index;
- update();
+ queue_redraw();
}
}
void CurveEditor::set_hover_point_index(int index) {
if (index != _hover_point) {
_hover_point = index;
- update();
+ queue_redraw();
}
}
@@ -579,7 +579,7 @@ template <typename T>
static void plot_curve_accurate(const Curve &curve, float step, T plot_func) {
if (curve.get_point_count() <= 1) {
// Not enough points to make a curve, so it's just a straight line
- float y = curve.interpolate(0);
+ float y = curve.sample(0);
plot_func(Vector2(0, y), Vector2(1.f, y), true);
} else {
@@ -603,7 +603,7 @@ static void plot_curve_accurate(const Curve &curve, float step, T plot_func) {
for (float x = step; x < len; x += step) {
pos.x = a.x + x;
- pos.y = curve.interpolate_local_nocheck(i - 1, x);
+ pos.y = curve.sample_local_nocheck(i - 1, x);
plot_func(prev_pos, pos, true);
prev_pos = pos;
}
@@ -640,7 +640,7 @@ void CurveEditor::_draw() {
// Background
Vector2 view_size = get_rect().size;
- draw_style_box(get_theme_stylebox(SNAME("bg"), SNAME("Tree")), Rect2(Point2(), view_size));
+ draw_style_box(get_theme_stylebox(SNAME("panel"), SNAME("Tree")), Rect2(Point2(), view_size));
// Grid
@@ -817,7 +817,7 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons
int prev_y = 0;
for (int x = 0; x < im.get_width(); ++x) {
float t = static_cast<float>(x) / im.get_width();
- float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y;
+ float v = (curve.sample_baked(t) - curve.get_min_value()) / range_y;
int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height());
// Plot point
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index c572b5b7fe..40e7dfead2 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -40,7 +40,7 @@
#include "editor/plugins/script_editor_plugin.h"
#include "scene/gui/menu_button.h"
-DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
+DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) {
EditorDebuggerServer::initialize();
ED_SHORTCUT("debugger/step_into", TTR("Step Into"), Key::F11);
@@ -61,30 +61,29 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
// Main editor debug menu.
debug_menu = p_debug_menu;
- 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(-1,
+ debug_menu->set_hide_on_checkable_item_selection(false);
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
+ debug_menu->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(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network Filesystem")), RUN_FILE_SERVER);
+ debug_menu->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(-1,
+ debug_menu->add_separator();
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
+ debug_menu->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_paths", TTR("Visible Paths")), RUN_DEBUG_PATHS);
- p->set_item_tooltip(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_paths", TTR("Visible Paths")), RUN_DEBUG_PATHS);
+ debug_menu->set_item_tooltip(-1,
TTR("When this option is enabled, curve resources used by path nodes 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(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
+ debug_menu->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(-1,
+ debug_menu->add_separator();
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
+ debug_menu->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(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Synchronize Script Changes")), RUN_RELOAD_SCRIPTS);
+ debug_menu->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
@@ -92,9 +91,9 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
instances_menu->set_name("run_instances");
instances_menu->set_hide_on_checkable_item_selection(false);
- p->add_child(instances_menu);
- p->add_separator();
- p->add_submenu_item(TTR("Run Multiple Instances"), "run_instances");
+ debug_menu->add_child(instances_menu);
+ debug_menu->add_separator();
+ debug_menu->add_submenu_item(TTR("Run Multiple Instances"), "run_instances");
instances_menu->add_radio_check_item(TTR("Run 1 Instance"));
instances_menu->set_item_metadata(0, 1);
@@ -106,7 +105,7 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
instances_menu->set_item_metadata(3, 4);
instances_menu->set_item_checked(0, true);
instances_menu->connect("index_pressed", callable_mp(this, &DebuggerEditorPlugin::_select_run_count));
- p->connect("id_pressed", callable_mp(this, &DebuggerEditorPlugin::_menu_option));
+ debug_menu->connect("id_pressed", callable_mp(this, &DebuggerEditorPlugin::_menu_option));
}
DebuggerEditorPlugin::~DebuggerEditorPlugin() {
@@ -125,7 +124,7 @@ void DebuggerEditorPlugin::_select_run_count(int p_index) {
void DebuggerEditorPlugin::_menu_option(int p_option) {
switch (p_option) {
case RUN_FILE_SERVER: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_FILE_SERVER));
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_FILE_SERVER));
if (ischecked) {
file_server->stop();
@@ -133,45 +132,45 @@ void DebuggerEditorPlugin::_menu_option(int p_option) {
file_server->start();
}
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_FILE_SERVER), !ischecked);
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_FILE_SERVER), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_file_server", !ischecked);
} break;
case RUN_LIVE_DEBUG: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_LIVE_DEBUG));
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_LIVE_DEBUG));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_LIVE_DEBUG), !ischecked);
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_LIVE_DEBUG), !ischecked);
EditorDebuggerNode::get_singleton()->set_live_debugging(!ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_live_debug", !ischecked);
} break;
case RUN_DEPLOY_REMOTE_DEBUG: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEPLOY_REMOTE_DEBUG));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEPLOY_REMOTE_DEBUG), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_deploy_remote_debug", !ischecked);
} break;
case RUN_DEBUG_COLLISONS: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_COLLISONS));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_COLLISONS), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_COLLISONS));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_COLLISONS), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_collisons", !ischecked);
} break;
case RUN_DEBUG_PATHS: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_PATHS));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_PATHS), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_PATHS));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_PATHS), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_paths", !ischecked);
} break;
case RUN_DEBUG_NAVIGATION: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_NAVIGATION));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_NAVIGATION), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_navigation", !ischecked);
} break;
case RUN_RELOAD_SCRIPTS: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_RELOAD_SCRIPTS));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_RELOAD_SCRIPTS), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_RELOAD_SCRIPTS));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_RELOAD_SCRIPTS), !ischecked);
ScriptEditor::get_singleton()->set_live_auto_reload_running_scripts(!ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_reload_scripts", !ischecked);
diff --git a/editor/plugins/debugger_editor_plugin.h b/editor/plugins/debugger_editor_plugin.h
index fb963385cd..d8871128c3 100644
--- a/editor/plugins/debugger_editor_plugin.h
+++ b/editor/plugins/debugger_editor_plugin.h
@@ -41,7 +41,7 @@ class DebuggerEditorPlugin : public EditorPlugin {
GDCLASS(DebuggerEditorPlugin, EditorPlugin);
private:
- MenuButton *debug_menu = nullptr;
+ PopupMenu *debug_menu = nullptr;
EditorFileServer *file_server = nullptr;
PopupMenu *instances_menu = nullptr;
@@ -64,7 +64,7 @@ public:
virtual String get_name() const override { return "Debugger"; }
bool has_main_screen() const override { return false; }
- DebuggerEditorPlugin(MenuButton *p_menu);
+ DebuggerEditorPlugin(PopupMenu *p_menu);
~DebuggerEditorPlugin();
};
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 0196214ceb..59b8f31720 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -201,7 +201,7 @@ Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const Ref<Resource> &p_from,
for (int i = 0; i < bm->get_size().width; i++) {
for (int j = 0; j < bm->get_size().height; j++) {
- if (bm->get_bit(Point2i(i, j))) {
+ if (bm->get_bit(i, j)) {
w[j * (int)bm->get_size().width + i] = 255;
} else {
w[j * (int)bm->get_size().width + i] = 0;
@@ -255,7 +255,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const Ref<Resource> &p_f
Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ cache_base = temp_path.path_join("resthumb-" + cache_base);
//does not have it, try to load a cached thumbnail
@@ -307,7 +307,7 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const Ref<Resource> &p_from
if (material->get_shader_mode() == Shader::MODE_SPATIAL) {
RS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_generate_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
preview_done.wait();
@@ -342,6 +342,12 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
RS::get_singleton()->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 0, 3)));
RS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes = RS::get_singleton()->camera_attributes_create();
+ RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, 1.0, 0.000032552); // Matches default CameraAttributesPhysical to work well with default DirectionalLight3Ds.
+ RS::get_singleton()->camera_set_camera_attributes(camera, camera_attributes);
+ }
+
light = RS::get_singleton()->directional_light_create();
light_instance = RS::get_singleton()->instance_create2(light, scenario);
RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
@@ -440,6 +446,7 @@ EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
RS::get_singleton()->free(light2);
RS::get_singleton()->free(light_instance2);
RS::get_singleton()->free(camera);
+ RS::get_singleton()->free(camera_attributes);
RS::get_singleton()->free(scenario);
}
@@ -702,7 +709,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const Ref<Resource> &p_from, co
xform.origin.z -= rot_aabb.size.z * 2;
RS::get_singleton()->instance_set_transform(mesh_instance, xform);
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_generate_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
preview_done.wait();
@@ -743,6 +750,12 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
//RS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
RS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes = RS::get_singleton()->camera_attributes_create();
+ RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, 1.0, 0.000032552); // Matches default CameraAttributesPhysical to work well with default DirectionalLight3Ds.
+ RS::get_singleton()->camera_set_camera_attributes(camera, camera_attributes);
+ }
+
light = RS::get_singleton()->directional_light_create();
light_instance = RS::get_singleton()->instance_create2(light, scenario);
RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
@@ -768,6 +781,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
RS::get_singleton()->free(light2);
RS::get_singleton()->free(light_instance2);
RS::get_singleton()->free(camera);
+ RS::get_singleton()->free(camera_attributes);
RS::get_singleton()->free(scenario);
}
@@ -812,7 +826,7 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path,
const float fg = c.get_luminance() < 0.5 ? 1.0 : 0.0;
sampled_font->draw_string(canvas_item, pos, sample, HORIZONTAL_ALIGNMENT_LEFT, -1.f, 50, Color(fg, fg, fg));
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Object::CONNECT_ONE_SHOT);
preview_done.wait();
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index 163cfe79f9..efb2c80cfd 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -91,6 +91,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
+ RID camera_attributes;
Semaphore preview_done;
void _generate_frame_started();
@@ -133,6 +134,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
RID light2;
RID light_instance2;
RID camera;
+ RID camera_attributes;
Semaphore preview_done;
void _generate_frame_started();
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index cadb974345..2df951518e 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -100,11 +100,6 @@ bool EditorPropertyFontOTObject::_get(const StringName &p_name, Variant &r_ret)
return false;
}
-void EditorPropertyFontOTObject::_bind_methods() {
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &EditorPropertyFontOTObject::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorPropertyFontOTObject::property_get_revert);
-}
-
void EditorPropertyFontOTObject::set_dict(const Dictionary &p_dict) {
dict = p_dict;
}
@@ -121,7 +116,7 @@ Dictionary EditorPropertyFontOTObject::get_defaults() {
return defaults_dict;
}
-bool EditorPropertyFontOTObject::property_can_revert(const String &p_name) {
+bool EditorPropertyFontOTObject::_property_can_revert(const StringName &p_name) const {
String name = p_name;
if (name.begins_with("keys")) {
@@ -136,18 +131,19 @@ bool EditorPropertyFontOTObject::property_can_revert(const String &p_name) {
return false;
}
-Variant EditorPropertyFontOTObject::property_get_revert(const String &p_name) {
+bool EditorPropertyFontOTObject::_property_get_revert(const StringName &p_name, Variant &r_property) const {
String name = p_name;
if (name.begins_with("keys")) {
int key = name.get_slicec('/', 1).to_int();
if (defaults_dict.has(key)) {
Vector3i range = defaults_dict[key];
- return range.z;
+ r_property = range.z;
+ return true;
}
}
- return Variant();
+ return false;
}
/*************************************************************************/
@@ -294,7 +290,7 @@ void EditorPropertyFontMetaOverride::update_property() {
} else {
prop->set_label(TranslationServer::get_singleton()->get_locale_name(name));
}
- prop->set_tooltip(name);
+ prop->set_tooltip_text(name);
prop->set_selectable(false);
prop->connect("property_changed", callable_mp(this, &EditorPropertyFontMetaOverride::_property_changed));
@@ -491,7 +487,7 @@ void EditorPropertyOTVariation::update_property() {
String name = TS->tag_to_name(name_tag);
prop->set_label(name.capitalize());
- prop->set_tooltip(name);
+ prop->set_tooltip_text(name);
prop->set_selectable(false);
prop->connect("property_changed", callable_mp(this, &EditorPropertyOTVariation::_property_changed));
@@ -770,7 +766,7 @@ void EditorPropertyOTFeatures::update_property() {
disp_name = vformat("%s (%s)", disp_name, info["label"].operator String());
}
prop->set_label(disp_name);
- prop->set_tooltip(name);
+ prop->set_tooltip_text(name);
prop->set_selectable(false);
prop->connect("property_changed", callable_mp(this, &EditorPropertyOTFeatures::_property_changed));
@@ -946,7 +942,7 @@ Size2 FontPreview::get_minimum_size() const {
void FontPreview::set_data(const Ref<Font> &p_f) {
prev_font = p_f;
- update();
+ queue_redraw();
}
FontPreview::FontPreview() {
diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h
index 3eaa2fdc17..41dde3cc59 100644
--- a/editor/plugins/font_config_plugin.h
+++ b/editor/plugins/font_config_plugin.h
@@ -66,7 +66,8 @@ class EditorPropertyFontOTObject : public RefCounted {
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
- static void _bind_methods();
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
public:
void set_dict(const Dictionary &p_dict);
@@ -75,9 +76,6 @@ public:
void set_defaults(const Dictionary &p_dict);
Dictionary get_defaults();
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
-
EditorPropertyFontOTObject(){};
};
diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h
index b5eca46ad3..e1d68d97b5 100644
--- a/editor/plugins/gdextension_export_plugin.h
+++ b/editor/plugins/gdextension_export_plugin.h
@@ -36,6 +36,7 @@
class GDExtensionExportPlugin : public EditorExportPlugin {
protected:
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features);
+ virtual String _get_name() const { return "GDExtension"; }
};
void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index 8e6687c836..e2d19c34e6 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -34,10 +34,11 @@
#include "core/io/image_loader.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.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"
+#include "scene/resources/particle_process_material.h"
void GPUParticles2DEditorPlugin::edit(Object *p_object) {
particles = Object::cast_to<GPUParticles2D>(p_object);
@@ -111,7 +112,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
cpu_particles->set_process_mode(particles->get_process_mode());
cpu_particles->set_z_index(particles->get_z_index());
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", particles, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -166,9 +167,9 @@ void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
}
void GPUParticles2DEditorPlugin::_generate_emission_mask() {
- Ref<ParticlesMaterial> pm = particles->get_process_material();
+ Ref<ParticleProcessMaterial> pm = particles->get_process_material();
if (!pm.is_valid()) {
- EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material"));
+ EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticleProcessMaterial process material"));
return;
}
@@ -319,7 +320,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
if (valid_normals.size()) {
- pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+ pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
Vector<uint8_t> normdata;
normdata.resize(w * h * 2 * sizeof(float)); //use RG texture
@@ -338,7 +339,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
pm->set_emission_normal_texture(ImageTexture::create_from_image(img));
} else {
- pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
+ pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS);
}
}
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h
index bf49a82166..0229b57c10 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.h
@@ -38,6 +38,7 @@
#include "scene/gui/spin_box.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class GPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin);
@@ -75,7 +76,7 @@ class GPUParticles2DEditorPlugin : public EditorPlugin {
String source_emission_file;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _file_selected(const String &p_file);
void _menu_callback(int p_idx);
void _generate_visibility_rect();
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 6750f1aa9c..d91cbb6571 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -32,10 +32,11 @@
#include "core/io/resource_loader.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.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"
+#include "scene/resources/particle_process_material.h"
bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) {
bool use_normals = emission_fill->get_selected() == 1;
@@ -254,9 +255,9 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
}
} break;
case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
- Ref<ParticlesMaterial> material = node->get_process_material();
+ Ref<ParticleProcessMaterial> material = node->get_process_material();
if (material.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
+ EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticleProcessMaterial' is required."));
return;
}
@@ -271,7 +272,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
cpu_particles->set_visible(node->is_visible());
cpu_particles->set_process_mode(node->get_process_mode());
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles3D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -321,7 +322,7 @@ void GPUParticles3DEditor::_generate_aabb() {
node->set_emitting(false);
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Generate Visibility AABB"));
ur->add_do_method(node, "set_visibility_aabb", rect);
ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
@@ -365,11 +366,11 @@ void GPUParticles3DEditor::_generate_emission_points() {
Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
Ref<ImageTexture> tex = ImageTexture::create_from_image(image);
- Ref<ParticlesMaterial> material = node->get_process_material();
+ Ref<ParticleProcessMaterial> material = node->get_process_material();
ERR_FAIL_COND(material.is_null());
if (normals.size() > 0) {
- material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+ material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
material->set_emission_point_count(point_count);
material->set_emission_point_texture(tex);
@@ -391,7 +392,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
material->set_emission_normal_texture(ImageTexture::create_from_image(image2));
} else {
- material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
+ material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS);
material->set_emission_point_count(point_count);
material->set_emission_point_texture(tex);
}
@@ -453,7 +454,7 @@ void GPUParticles3DEditorPlugin::make_visible(bool p_visible) {
GPUParticles3DEditorPlugin::GPUParticles3DEditorPlugin() {
particles_editor = memnew(GPUParticles3DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(particles_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(particles_editor);
particles_editor->hide();
}
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
index b54cb515e4..59d665342f 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
@@ -101,7 +101,7 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_notification(int p_what) {
return;
}
- bake->set_tooltip(text);
+ bake->set_tooltip_text(text);
} break;
}
}
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
new file mode 100644
index 0000000000..c13b162db6
--- /dev/null
+++ b/editor/plugins/gradient_editor.cpp
@@ -0,0 +1,492 @@
+/*************************************************************************/
+/* gradient_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 "gradient_editor.h"
+
+#include "core/os/keyboard.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
+
+void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
+ 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"));
+ queue_redraw();
+}
+
+int GradientEditor::_get_point_from_pos(int x) {
+ int result = -1;
+ int total_w = get_size().width - get_size().height - draw_spacing;
+ float min_distance = 1e20;
+ for (int i = 0; i < points.size(); i++) {
+ // Check if we clicked at point.
+ float distance = ABS(x - points[i].offset * total_w);
+ float min = (draw_point_width / 2 * 1.7); //make it easier to grab
+ if (distance <= min && distance < min_distance) {
+ result = i;
+ min_distance = distance;
+ }
+ }
+ return result;
+}
+
+void GradientEditor::_show_color_picker() {
+ if (grabbed == -1) {
+ return;
+ }
+ picker->set_pick_color(points[grabbed].color);
+ Size2 minsize = popup->get_contents_minimum_size();
+ bool show_above = false;
+ if (get_global_position().y + get_size().y + minsize.y > get_viewport_rect().size.y) {
+ show_above = true;
+ }
+ if (show_above) {
+ popup->set_position(get_screen_position() - Vector2(0, minsize.y));
+ } else {
+ popup->set_position(get_screen_position() + Vector2(0, get_size().y));
+ }
+ popup->popup();
+}
+
+void GradientEditor::_gradient_changed() {
+ if (editing) {
+ return;
+ }
+
+ editing = true;
+ Vector<Gradient::Point> points = gradient->get_points();
+ set_points(points);
+ set_interpolation_mode(gradient->get_interpolation_mode());
+ queue_redraw();
+ editing = false;
+}
+
+void GradientEditor::_ramp_changed() {
+ editing = true;
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
+ 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;
+}
+
+void GradientEditor::_color_changed(const Color &p_color) {
+ if (grabbed == -1) {
+ return;
+ }
+ points.write[grabbed].color = p_color;
+ queue_redraw();
+ emit_signal(SNAME("ramp_changed"));
+}
+
+void GradientEditor::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) {
+ ERR_FAIL_COND(p_offsets.size() != p_colors.size());
+ points.clear();
+ for (int i = 0; i < p_offsets.size(); i++) {
+ Gradient::Point p;
+ p.offset = p_offsets[i];
+ p.color = p_colors[i];
+ points.push_back(p);
+ }
+
+ points.sort();
+ queue_redraw();
+}
+
+Vector<float> GradientEditor::get_offsets() const {
+ Vector<float> ret;
+ for (int i = 0; i < points.size(); i++) {
+ ret.push_back(points[i].offset);
+ }
+ return ret;
+}
+
+Vector<Color> GradientEditor::get_colors() const {
+ Vector<Color> ret;
+ for (int i = 0; i < points.size(); i++) {
+ ret.push_back(points[i].color);
+ }
+ return ret;
+}
+
+void GradientEditor::set_points(Vector<Gradient::Point> &p_points) {
+ if (points.size() != p_points.size()) {
+ grabbed = -1;
+ }
+ points.clear();
+ points = p_points;
+ points.sort();
+}
+
+Vector<Gradient::Point> &GradientEditor::get_points() {
+ return points;
+}
+
+void GradientEditor::set_interpolation_mode(Gradient::InterpolationMode p_interp_mode) {
+ interpolation_mode = p_interp_mode;
+}
+
+Gradient::InterpolationMode GradientEditor::get_interpolation_mode() {
+ return interpolation_mode;
+}
+
+ColorPicker *GradientEditor::get_picker() {
+ return picker;
+}
+
+PopupPanel *GradientEditor::get_popup() {
+ return popup;
+}
+
+Size2 GradientEditor::get_minimum_size() const {
+ return Size2(0, 60) * EDSCALE;
+}
+
+void GradientEditor::gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
+ Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && grabbed != -1) {
+ points.remove_at(grabbed);
+ grabbed = -1;
+ grabbing = false;
+ queue_redraw();
+ emit_signal(SNAME("ramp_changed"));
+ accept_event();
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ // Show color picker on double click.
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) {
+ grabbed = _get_point_from_pos(mb->get_position().x);
+ _show_color_picker();
+ accept_event();
+ }
+
+ // Delete point on right click.
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
+ grabbed = _get_point_from_pos(mb->get_position().x);
+ if (grabbed != -1) {
+ points.remove_at(grabbed);
+ grabbed = -1;
+ grabbing = false;
+ queue_redraw();
+ emit_signal(SNAME("ramp_changed"));
+ accept_event();
+ }
+ }
+
+ // Hold alt key to duplicate selected color.
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed() && mb->is_alt_pressed()) {
+ int x = mb->get_position().x;
+ grabbed = _get_point_from_pos(x);
+
+ if (grabbed != -1) {
+ int total_w = get_size().width - get_size().height - draw_spacing;
+ Gradient::Point new_point = points[grabbed];
+ new_point.offset = CLAMP(x / float(total_w), 0, 1);
+
+ points.push_back(new_point);
+ points.sort();
+ for (int i = 0; i < points.size(); ++i) {
+ if (points[i].offset == new_point.offset) {
+ grabbed = i;
+ break;
+ }
+ }
+
+ emit_signal(SNAME("ramp_changed"));
+ queue_redraw();
+ }
+ }
+
+ // Select.
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
+ queue_redraw();
+ int x = mb->get_position().x;
+ int total_w = get_size().width - get_size().height - draw_spacing;
+
+ //Check if color selector was clicked.
+ if (x > total_w + draw_spacing) {
+ _show_color_picker();
+ return;
+ }
+
+ grabbing = true;
+
+ grabbed = _get_point_from_pos(x);
+ //grab or select
+ if (grabbed != -1) {
+ return;
+ }
+
+ // Insert point.
+ Gradient::Point new_point;
+ new_point.offset = CLAMP(x / float(total_w), 0, 1);
+
+ Gradient::Point prev;
+ Gradient::Point next;
+
+ int pos = -1;
+ for (int i = 0; i < points.size(); i++) {
+ if (points[i].offset < new_point.offset) {
+ pos = i;
+ }
+ }
+
+ if (pos == -1) {
+ prev.color = Color(0, 0, 0);
+ prev.offset = 0;
+ if (points.size()) {
+ next = points[0];
+ } else {
+ next.color = Color(1, 1, 1);
+ next.offset = 1.0;
+ }
+ } else {
+ if (pos == points.size() - 1) {
+ next.color = Color(1, 1, 1);
+ next.offset = 1.0;
+ } else {
+ next = points[pos + 1];
+ }
+ prev = points[pos];
+ }
+
+ new_point.color = prev.color.lerp(next.color, (new_point.offset - prev.offset) / (next.offset - prev.offset));
+
+ points.push_back(new_point);
+ points.sort();
+ for (int i = 0; i < points.size(); i++) {
+ if (points[i].offset == new_point.offset) {
+ grabbed = i;
+ break;
+ }
+ }
+
+ emit_signal(SNAME("ramp_changed"));
+ }
+
+ if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
+ if (grabbing) {
+ grabbing = false;
+ emit_signal(SNAME("ramp_changed"));
+ }
+ queue_redraw();
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid() && grabbing) {
+ int total_w = get_size().width - get_size().height - draw_spacing;
+
+ int x = mm->get_position().x;
+
+ float newofs = CLAMP(x / float(total_w), 0, 1);
+
+ // Snap to "round" coordinates if holding Ctrl.
+ // Be more precise if holding Shift as well.
+ if (mm->is_ctrl_pressed()) {
+ newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1);
+ } else if (mm->is_shift_pressed()) {
+ // Snap to nearest point if holding just Shift
+ const float snap_threshold = 0.03;
+ float smallest_ofs = snap_threshold;
+ bool found = false;
+ int nearest_point = 0;
+ for (int i = 0; i < points.size(); ++i) {
+ if (i != grabbed) {
+ float temp_ofs = ABS(points[i].offset - newofs);
+ if (temp_ofs < smallest_ofs) {
+ smallest_ofs = temp_ofs;
+ nearest_point = i;
+ if (found) {
+ break;
+ }
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ if (points[nearest_point].offset < newofs) {
+ newofs = points[nearest_point].offset + 0.00001;
+ } else {
+ newofs = points[nearest_point].offset - 0.00001;
+ }
+ newofs = CLAMP(newofs, 0, 1);
+ }
+ }
+
+ bool valid = true;
+ for (int i = 0; i < points.size(); i++) {
+ if (points[i].offset == newofs && i != grabbed) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (!valid || grabbed == -1) {
+ return;
+ }
+ points.write[grabbed].offset = newofs;
+
+ points.sort();
+ for (int i = 0; i < points.size(); i++) {
+ if (points[i].offset == newofs) {
+ grabbed = i;
+ break;
+ }
+ }
+
+ emit_signal(SNAME("ramp_changed"));
+
+ queue_redraw();
+ }
+}
+
+void GradientEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (!picker->is_connected("color_changed", callable_mp(this, &GradientEditor::_color_changed))) {
+ picker->connect("color_changed", callable_mp(this, &GradientEditor::_color_changed));
+ }
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ draw_spacing = BASE_SPACING * get_theme_default_base_scale();
+ draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale();
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ int w = get_size().x;
+ int h = get_size().y;
+
+ if (w == 0 || h == 0) {
+ return; // Safety check. We have division by 'h'. And in any case there is nothing to draw with such size.
+ }
+
+ int total_w = get_size().width - get_size().height - draw_spacing;
+
+ // Draw checker pattern for ramp.
+ draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true);
+
+ // Draw color ramp.
+ gradient_cache->set_points(points);
+ gradient_cache->set_interpolation_mode(interpolation_mode);
+ preview_texture->set_gradient(gradient_cache);
+ draw_texture_rect(preview_texture, Rect2(0, 0, total_w, h));
+
+ // Draw point markers.
+ for (int i = 0; i < points.size(); i++) {
+ Color col = points[i].color.inverted();
+ col.a = 0.9;
+
+ draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col);
+ Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2);
+ draw_rect(rect, points[i].color, true);
+ draw_rect(rect, col, false);
+ if (grabbed == i) {
+ rect = rect.grow(-1);
+ if (has_focus()) {
+ draw_rect(rect, Color(1, 0, 0, 0.9), false);
+ } else {
+ draw_rect(rect, Color(0.6, 0, 0, 0.9), false);
+ }
+
+ rect = rect.grow(-1);
+ draw_rect(rect, col, false);
+ }
+ }
+
+ // Draw "button" for color selector.
+ draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true);
+ if (grabbed != -1) {
+ // Draw with selection color.
+ draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color);
+ } else {
+ // If no color selected draw grey color with 'X' on top.
+ draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1));
+ draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6));
+ draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6));
+ }
+
+ // Draw borders around color ramp if in focus.
+ if (has_focus()) {
+ draw_line(Vector2(-1, -1), Vector2(total_w + 1, -1), Color(1, 1, 1, 0.6));
+ draw_line(Vector2(total_w + 1, -1), Vector2(total_w + 1, h + 1), Color(1, 1, 1, 0.6));
+ draw_line(Vector2(total_w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6));
+ draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6));
+ }
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible()) {
+ grabbing = false;
+ }
+ } break;
+ }
+}
+
+void GradientEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("ramp_changed"));
+}
+
+GradientEditor::GradientEditor() {
+ set_focus_mode(FOCUS_ALL);
+
+ popup = memnew(PopupPanel);
+ picker = memnew(ColorPicker);
+ popup->add_child(picker);
+ popup->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(GradientEditor::get_picker()));
+
+ gradient_cache.instantiate();
+ preview_texture.instantiate();
+
+ preview_texture->set_width(1024);
+ add_child(popup, false, INTERNAL_MODE_FRONT);
+}
+
+GradientEditor::~GradientEditor() {
+}
diff --git a/editor/plugins/gradient_editor.h b/editor/plugins/gradient_editor.h
new file mode 100644
index 0000000000..816b539ba2
--- /dev/null
+++ b/editor/plugins/gradient_editor.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* gradient_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 GRADIENT_EDITOR_H
+#define GRADIENT_EDITOR_H
+
+#include "scene/gui/color_picker.h"
+#include "scene/gui/popup.h"
+#include "scene/resources/gradient.h"
+
+class GradientEditor : public Control {
+ GDCLASS(GradientEditor, Control);
+
+ PopupPanel *popup = nullptr;
+ ColorPicker *picker = nullptr;
+
+ bool grabbing = false;
+ int grabbed = -1;
+ Vector<Gradient::Point> points;
+ Gradient::InterpolationMode interpolation_mode = Gradient::GRADIENT_INTERPOLATE_LINEAR;
+
+ bool editing = false;
+ Ref<Gradient> gradient;
+ Ref<Gradient> gradient_cache;
+ Ref<GradientTexture1D> preview_texture;
+
+ // Make sure to use the scaled value below.
+ const int BASE_SPACING = 3;
+ const int BASE_POINT_WIDTH = 8;
+
+ int draw_spacing = BASE_SPACING;
+ int draw_point_width = BASE_POINT_WIDTH;
+
+ void _gradient_changed();
+ void _ramp_changed();
+ void _color_changed(const Color &p_color);
+
+ int _get_point_from_pos(int x);
+ void _show_color_picker();
+
+protected:
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_gradient(const Ref<Gradient> &p_gradient);
+ void reverse_gradient();
+
+ void set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors);
+
+ Vector<float> get_offsets() const;
+ Vector<Color> get_colors() const;
+ void set_points(Vector<Gradient::Point> &p_points);
+ Vector<Gradient::Point> &get_points();
+
+ void set_interpolation_mode(Gradient::InterpolationMode p_interp_mode);
+ Gradient::InterpolationMode get_interpolation_mode();
+
+ ColorPicker *get_picker();
+ PopupPanel *get_popup();
+
+ virtual Size2 get_minimum_size() const override;
+
+ GradientEditor();
+ virtual ~GradientEditor();
+};
+
+#endif // GRADIENT_EDITOR_H
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index 542aee879b..0f412aaefd 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -34,64 +34,9 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
-Size2 GradientEditor::get_minimum_size() const {
- return Size2(0, 60) * EDSCALE;
-}
-
-void GradientEditor::_gradient_changed() {
- if (editing) {
- return;
- }
-
- 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"), 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;
-}
-
-void GradientEditor::_bind_methods() {
-}
-
-void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
- 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() {
- GradientEdit::get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(GradientEdit::get_picker()));
- editing = false;
-}
-
-///////////////////////
-
void GradientReverseButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -134,7 +79,7 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) {
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."));
+ reverse_btn->set_tooltip_text(TTR("Reverse/mirror gradient."));
}
void EditorInspectorPluginGradient::_reverse_button_pressed() {
diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h
index 26bf76fecd..ab191d83e2 100644
--- a/editor/plugins/gradient_editor_plugin.h
+++ b/editor/plugins/gradient_editor_plugin.h
@@ -32,26 +32,7 @@
#define GRADIENT_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
-#include "scene/gui/gradient_edit.h"
-
-class GradientEditor : public GradientEdit {
- GDCLASS(GradientEditor, GradientEdit);
-
- bool editing;
- Ref<Gradient> gradient;
-
- void _gradient_changed();
- void _ramp_changed();
-
-protected:
- static void _bind_methods();
-
-public:
- virtual Size2 get_minimum_size() const override;
- void set_gradient(const Ref<Gradient> &p_gradient);
- void reverse_gradient();
- GradientEditor();
-};
+#include "gradient_editor.h"
class GradientReverseButton : public BaseButton {
GDCLASS(GradientReverseButton, BaseButton);
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index df45d6c290..dc01a52bb3 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/box_container.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/separator.h"
@@ -88,17 +89,17 @@ void GradientTexture2DEditorRect::gui_input(const Ref<InputEvent> &p_event) {
void GradientTexture2DEditorRect::set_texture(Ref<GradientTexture2D> &p_texture) {
texture = p_texture;
- texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update));
+ texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
}
void GradientTexture2DEditorRect::set_snap_enabled(bool p_snap_enabled) {
snap_enabled = p_snap_enabled;
- update();
+ queue_redraw();
}
void GradientTexture2DEditorRect::set_snap_size(float p_snap_size) {
snap_size = p_snap_size;
- update();
+ queue_redraw();
}
void GradientTexture2DEditorRect::_notification(int p_what) {
@@ -175,7 +176,7 @@ void GradientTexture2DEditorRect::_notification(int p_what) {
}
GradientTexture2DEditorRect::GradientTexture2DEditorRect() {
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
checkerboard = memnew(TextureRect);
checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE);
@@ -222,20 +223,20 @@ void GradientTexture2DEditor::_notification(int p_what) {
}
GradientTexture2DEditor::GradientTexture2DEditor() {
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
HFlowContainer *toolbar = memnew(HFlowContainer);
add_child(toolbar);
reverse_button = memnew(Button);
- reverse_button->set_tooltip(TTR("Swap Gradient Fill Points"));
+ reverse_button->set_tooltip_text(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_tooltip_text(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));
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.h b/editor/plugins/gradient_texture_2d_editor_plugin.h
index 93c49b1e6f..9faf33152a 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.h
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.h
@@ -34,6 +34,8 @@
#include "editor/editor_plugin.h"
#include "editor/editor_spin_slider.h"
+class EditorUndoRedoManager;
+
class GradientTexture2DEditorRect : public Control {
GDCLASS(GradientTexture2DEditorRect, Control);
@@ -44,7 +46,7 @@ class GradientTexture2DEditorRect : public Control {
};
Ref<GradientTexture2D> texture;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool snap_enabled = false;
float snap_size = 0;
@@ -74,7 +76,7 @@ class GradientTexture2DEditor : public VBoxContainer {
GDCLASS(GradientTexture2DEditor, VBoxContainer);
Ref<GradientTexture2D> texture;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Button *reverse_button = nullptr;
Button *snap_button = nullptr;
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 1b4d98fc3f..fe7713f175 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -30,45 +30,73 @@
#include "material_editor_plugin.h"
+#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/subviewport_container.h"
#include "scene/resources/fog_material.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
#include "scene/resources/sky_material.h"
-void MaterialEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_READY: {
- //get_scene()->connect("node_removed",this,"_node_removed");
+void MaterialEditor::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() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
+ rot.x -= mm->get_relative().y * 0.01;
+ rot.y -= mm->get_relative().x * 0.01;
- if (first_enter) {
- //it's in propertyeditor so.. could be moved around
+ rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2);
+ _update_rotation();
+ }
+}
- 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")));
+void MaterialEditor::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
- 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")));
+ theme_cache.light_1_on = get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons"));
+ theme_cache.light_1_off = get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons"));
+ theme_cache.light_2_on = get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons"));
+ theme_cache.light_2_off = get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons"));
- first_enter = false;
- }
+ theme_cache.sphere_on = get_theme_icon(SNAME("MaterialPreviewSphere"), SNAME("EditorIcons"));
+ theme_cache.sphere_off = get_theme_icon(SNAME("MaterialPreviewSphereOff"), SNAME("EditorIcons"));
+ theme_cache.box_on = get_theme_icon(SNAME("MaterialPreviewCube"), SNAME("EditorIcons"));
+ theme_cache.box_off = get_theme_icon(SNAME("MaterialPreviewCubeOff"), SNAME("EditorIcons"));
+
+ theme_cache.checkerboard = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
+}
+
+void MaterialEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ light_1_switch->set_normal_texture(theme_cache.light_1_on);
+ light_1_switch->set_pressed_texture(theme_cache.light_1_off);
+ light_2_switch->set_normal_texture(theme_cache.light_2_on);
+ light_2_switch->set_pressed_texture(theme_cache.light_2_off);
+
+ sphere_switch->set_normal_texture(theme_cache.sphere_off);
+ sphere_switch->set_pressed_texture(theme_cache.sphere_on);
+ box_switch->set_normal_texture(theme_cache.box_off);
+ box_switch->set_pressed_texture(theme_cache.box_on);
} break;
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(theme_cache.checkerboard, Rect2(Point2(), size), true);
} break;
}
}
+void MaterialEditor::_update_rotation() {
+ Transform3D t;
+ t.basis.rotate(Vector3(0, 1, 0), -rot.y);
+ t.basis.rotate(Vector3(1, 0, 0), -rot.x);
+ rotation->set_transform(t);
+}
+
void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) {
material = p_material;
camera->set_environment(p_env);
@@ -94,6 +122,10 @@ void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_en
} else {
hide();
}
+
+ rot.x = Math::deg_to_rad(-15.0);
+ rot.y = Math::deg_to_rad(30.0);
+ _update_rotation();
}
void MaterialEditor::_button_pressed(Node *p_button) {
@@ -122,9 +154,6 @@ void MaterialEditor::_button_pressed(Node *p_button) {
}
}
-void MaterialEditor::_bind_methods() {
-}
-
MaterialEditor::MaterialEditor() {
// canvas item
@@ -152,14 +181,18 @@ MaterialEditor::MaterialEditor() {
vc->add_child(viewport);
viewport->set_disable_input(true);
viewport->set_transparent_background(true);
- viewport->set_msaa(Viewport::MSAA_4X);
+ viewport->set_msaa_3d(Viewport::MSAA_4X);
camera = memnew(Camera3D);
- camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 3)));
+ camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1)));
// Use low field of view so the sphere/box is fully encompassed within the preview,
// without much distortion.
camera->set_perspective(20, 0.1, 10);
camera->make_current();
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ camera->set_attributes(camera_attributes);
+ }
viewport->add_child(camera);
light1 = memnew(DirectionalLight3D);
@@ -171,18 +204,17 @@ MaterialEditor::MaterialEditor() {
light2->set_color(Color(0.7, 0.7, 0.7));
viewport->add_child(light2);
+ rotation = memnew(Node3D);
+ viewport->add_child(rotation);
+
sphere_instance = memnew(MeshInstance3D);
- viewport->add_child(sphere_instance);
+ rotation->add_child(sphere_instance);
box_instance = memnew(MeshInstance3D);
- viewport->add_child(box_instance);
+ rotation->add_child(box_instance);
- Transform3D box_xform;
- box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0));
- box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0));
- box_xform.basis.scale(Vector3(0.7, 0.7, 0.7));
- box_xform.origin.y = 0.05;
- box_instance->set_transform(box_xform);
+ box_instance->set_transform(Transform3D() * 0.25);
+ sphere_instance->set_transform(Transform3D() * 0.375);
sphere_mesh.instantiate();
sphere_instance->set_mesh(sphere_mesh);
@@ -225,8 +257,6 @@ MaterialEditor::MaterialEditor() {
vb_light->add_child(light_2_switch);
light_2_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed).bind(light_2_switch));
- first_enter = true;
-
if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) {
box_instance->hide();
} else {
@@ -261,10 +291,8 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
}
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;
- }
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo.is_valid());
// 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
@@ -340,17 +368,17 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
// Texture parameter has to be treated specially since StandardMaterial3D saved it
// as RID but ShaderMaterial needs Texture itself
Ref<Texture2D> texture = mat->get_texture_by_name(E.name);
if (texture.is_valid()) {
- smat->set_shader_uniform(E.name, texture);
+ smat->set_shader_parameter(E.name, texture);
} else {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
}
@@ -386,17 +414,17 @@ Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_reso
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
// Texture parameter has to be treated specially since ORMMaterial3D saved it
// as RID but ShaderMaterial needs Texture itself
Ref<Texture2D> texture = mat->get_texture_by_name(E.name);
if (texture.is_valid()) {
- smat->set_shader_uniform(E.name, texture);
+ smat->set_shader_parameter(E.name, texture);
} else {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
}
@@ -406,17 +434,17 @@ Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_reso
return smat;
}
-String ParticlesMaterialConversionPlugin::converts_to() const {
+String ParticleProcessMaterialConversionPlugin::converts_to() const {
return "ShaderMaterial";
}
-bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
- Ref<ParticlesMaterial> mat = p_resource;
+bool ParticleProcessMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+ Ref<ParticleProcessMaterial> mat = p_resource;
return mat.is_valid();
}
-Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
- Ref<ParticlesMaterial> mat = p_resource;
+Ref<Resource> ParticleProcessMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
+ Ref<ParticleProcessMaterial> mat = p_resource;
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
@@ -432,11 +460,11 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -471,11 +499,11 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -510,11 +538,11 @@ Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource>
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -549,11 +577,11 @@ Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -588,11 +616,11 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -627,11 +655,11 @@ Ref<Resource> FogMaterialConversionPlugin::convert(const Ref<Resource> &p_resour
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->get_shader_parameter_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_uniform(E.name, value);
+ smat->set_shader_parameter(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index fc3da5fd9f..8e64434d8b 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -45,16 +45,20 @@ class SubViewportContainer;
class MaterialEditor : public Control {
GDCLASS(MaterialEditor, Control);
+ Vector2 rot = Vector2();
+
HBoxContainer *layout_2d = nullptr;
ColorRect *rect_instance = nullptr;
SubViewportContainer *vc = nullptr;
SubViewport *viewport = nullptr;
+ Node3D *rotation = nullptr;
MeshInstance3D *sphere_instance = nullptr;
MeshInstance3D *box_instance = nullptr;
DirectionalLight3D *light1 = nullptr;
DirectionalLight3D *light2 = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<SphereMesh> sphere_mesh;
Ref<BoxMesh> box_mesh;
@@ -69,13 +73,25 @@ class MaterialEditor : public Control {
Ref<Material> material;
+ struct ThemeCache {
+ Ref<Texture2D> light_1_on;
+ Ref<Texture2D> light_1_off;
+ Ref<Texture2D> light_2_on;
+ Ref<Texture2D> light_2_off;
+ Ref<Texture2D> sphere_on;
+ Ref<Texture2D> sphere_off;
+ Ref<Texture2D> box_on;
+ Ref<Texture2D> box_off;
+ Ref<Texture2D> checkerboard;
+ } theme_cache;
+
void _button_pressed(Node *p_button);
- bool first_enter;
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
-
- static void _bind_methods();
+ void gui_input(const Ref<InputEvent> &p_event) override;
+ void _update_rotation();
public:
void edit(Ref<Material> p_material, const Ref<Environment> &p_env);
@@ -122,8 +138,8 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};
-class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin {
- GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin);
+class ParticleProcessMaterialConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(ParticleProcessMaterialConversionPlugin, EditorResourceConversionPlugin);
public:
virtual String converts_to() const override;
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 31c9f1e387..be26baaea5 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -30,6 +30,7 @@
#include "mesh_editor_plugin.h"
+#include "core/config/project_settings.h"
#include "editor/editor_scale.h"
void MeshEditor::gui_input(const Ref<InputEvent> &p_event) {
@@ -48,20 +49,22 @@ void MeshEditor::gui_input(const Ref<InputEvent> &p_event) {
}
}
+void MeshEditor::_update_theme_item_cache() {
+ SubViewportContainer::_update_theme_item_cache();
+
+ theme_cache.light_1_on = get_theme_icon(SNAME("MaterialPreviewLight1"), SNAME("EditorIcons"));
+ theme_cache.light_1_off = get_theme_icon(SNAME("MaterialPreviewLight1Off"), SNAME("EditorIcons"));
+ theme_cache.light_2_on = get_theme_icon(SNAME("MaterialPreviewLight2"), SNAME("EditorIcons"));
+ theme_cache.light_2_off = get_theme_icon(SNAME("MaterialPreviewLight2Off"), SNAME("EditorIcons"));
+}
+
void MeshEditor::_notification(int p_what) {
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;
- }
+ case NOTIFICATION_THEME_CHANGED: {
+ light_1_switch->set_normal_texture(theme_cache.light_1_on);
+ light_1_switch->set_pressed_texture(theme_cache.light_1_off);
+ light_2_switch->set_normal_texture(theme_cache.light_2_on);
+ light_2_switch->set_pressed_texture(theme_cache.light_2_off);
} break;
}
}
@@ -77,8 +80,8 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) {
mesh = p_mesh;
mesh_instance->set_mesh(mesh);
- rot_x = Math::deg2rad(-15.0);
- rot_y = Math::deg2rad(30.0);
+ rot_x = Math::deg_to_rad(-15.0);
+ rot_y = Math::deg_to_rad(30.0);
_update_rotation();
AABB aabb = mesh->get_aabb();
@@ -112,13 +115,18 @@ MeshEditor::MeshEditor() {
viewport->set_world_3d(world_3d); //use own world
add_child(viewport);
viewport->set_disable_input(true);
- viewport->set_msaa(Viewport::MSAA_4X);
+ viewport->set_msaa_3d(Viewport::MSAA_4X);
set_stretch(true);
camera = memnew(Camera3D);
camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1)));
camera->set_perspective(45, 0.1, 10);
viewport->add_child(camera);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ camera->set_attributes(camera_attributes);
+ }
+
light1 = memnew(DirectionalLight3D);
light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0)));
viewport->add_child(light1);
@@ -154,8 +162,6 @@ MeshEditor::MeshEditor() {
vb_light->add_child(light_2_switch);
light_2_switch->connect("pressed", callable_mp(this, &MeshEditor::_button_pressed).bind(light_2_switch));
- first_enter = true;
-
rot_x = 0;
rot_y = 0;
}
diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h
index fb61f03485..6394cb1171 100644
--- a/editor/plugins/mesh_editor_plugin.h
+++ b/editor/plugins/mesh_editor_plugin.h
@@ -36,6 +36,7 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/subviewport_container.h"
+#include "scene/resources/camera_attributes.h"
#include "scene/resources/material.h"
class MeshEditor : public SubViewportContainer {
@@ -50,18 +51,25 @@ class MeshEditor : public SubViewportContainer {
DirectionalLight3D *light1 = nullptr;
DirectionalLight3D *light2 = nullptr;
Camera3D *camera = nullptr;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<Mesh> mesh;
TextureButton *light_1_switch = nullptr;
TextureButton *light_2_switch = nullptr;
- void _button_pressed(Node *p_button);
- bool first_enter;
+ struct ThemeCache {
+ Ref<Texture2D> light_1_on;
+ Ref<Texture2D> light_1_off;
+ Ref<Texture2D> light_2_on;
+ Ref<Texture2D> light_2_off;
+ } theme_cache;
+ void _button_pressed(Node *p_button);
void _update_rotation();
protected:
+ virtual void _update_theme_item_cache() override;
void _notification(int p_what);
void gui_input(const Ref<InputEvent> &p_event) override;
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 5fb885ad1f..c502d47669 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/navigation_region_3d.h"
@@ -60,7 +61,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: {
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
List<Node *> selection = editor_selection->get_selected_node_list();
@@ -147,7 +148,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Trimesh Static Shape"));
@@ -177,7 +178,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
if (simplify) {
ur->create_action(TTR("Create Simplified Convex Shape"));
@@ -217,7 +218,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Multiple Convex Shapes"));
@@ -254,7 +255,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Navigation Mesh"));
ur->add_do_method(node, "add_child", nmi, true);
@@ -311,7 +312,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Unwrap UV2"));
ur->add_do_method(node, "set_mesh", unwrapped_mesh);
@@ -470,7 +471,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
mi->set_mesh(mesho);
Node *owner = get_tree()->get_edited_scene_root();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Outline"));
@@ -566,7 +567,7 @@ void MeshInstance3DEditorPlugin::make_visible(bool p_visible) {
MeshInstance3DEditorPlugin::MeshInstance3DEditorPlugin() {
mesh_editor = memnew(MeshInstance3DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(mesh_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(mesh_editor);
mesh_editor->options->hide();
}
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 319f6ee9de..420ebe5942 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -319,7 +319,7 @@ void MeshLibraryEditorPlugin::make_visible(bool p_visible) {
MeshLibraryEditorPlugin::MeshLibraryEditorPlugin() {
mesh_library_editor = memnew(MeshLibraryEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(mesh_library_editor);
+ EditorNode::get_singleton()->get_main_screen_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();
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index fc4dc5bc2f..b0e206b020 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -379,7 +379,7 @@ void MultiMeshEditorPlugin::make_visible(bool p_visible) {
MultiMeshEditorPlugin::MultiMeshEditorPlugin() {
multimesh_editor = memnew(MultiMeshEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(multimesh_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(multimesh_editor);
multimesh_editor->options->hide();
}
diff --git a/editor/plugins/navigation_link_2d_editor_plugin.cpp b/editor/plugins/navigation_link_2d_editor_plugin.cpp
new file mode 100644
index 0000000000..b72f639fbf
--- /dev/null
+++ b/editor/plugins/navigation_link_2d_editor_plugin.cpp
@@ -0,0 +1,191 @@
+/*************************************************************************/
+/* navigation_link_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 "navigation_link_2d_editor_plugin.h"
+
+#include "canvas_item_editor_plugin.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "servers/navigation_server_3d.h"
+
+void NavigationLink2DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ get_tree()->connect("node_removed", callable_mp(this, &NavigationLink2DEditor::_node_removed));
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &NavigationLink2DEditor::_node_removed));
+ } break;
+ }
+}
+
+void NavigationLink2DEditor::_node_removed(Node *p_node) {
+ if (p_node == node) {
+ node = nullptr;
+ }
+}
+
+bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+ if (!node || !node->is_visible_in_tree()) {
+ return false;
+ }
+
+ real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
+ 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()) {
+ // Start location
+ if (xform.xform(node->get_start_location()).distance_to(mb->get_position()) < grab_threshold) {
+ start_grabbed = true;
+ original_start_location = node->get_start_location();
+
+ return true;
+ } else {
+ start_grabbed = false;
+ }
+
+ // End location
+ if (xform.xform(node->get_end_location()).distance_to(mb->get_position()) < grab_threshold) {
+ end_grabbed = true;
+ original_end_location = node->get_end_location();
+
+ return true;
+ } else {
+ end_grabbed = false;
+ }
+ } else {
+ if (start_grabbed) {
+ undo_redo->create_action(TTR("Set start_location"));
+ undo_redo->add_do_method(node, "set_start_location", node->get_start_location());
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(node, "set_start_location", original_start_location);
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
+ undo_redo->commit_action();
+
+ start_grabbed = false;
+
+ return true;
+ }
+
+ if (end_grabbed) {
+ undo_redo->create_action(TTR("Set end_location"));
+ undo_redo->add_do_method(node, "set_end_location", node->get_end_location());
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(node, "set_end_location", original_end_location);
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
+ undo_redo->commit_action();
+
+ end_grabbed = false;
+
+ return true;
+ }
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ 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);
+
+ if (start_grabbed) {
+ node->set_start_location(point);
+ canvas_item_editor->update_viewport();
+
+ return true;
+ }
+
+ if (end_grabbed) {
+ node->set_end_location(point);
+ canvas_item_editor->update_viewport();
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void NavigationLink2DEditor::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();
+ Vector2 global_start_location = gt.xform(node->get_start_location());
+ Vector2 global_end_location = gt.xform(node->get_end_location());
+
+ // Only drawing the handles here, since the debug rendering will fill in the rest.
+ const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
+ p_overlay->draw_texture(handle, global_start_location - handle->get_size() / 2);
+ p_overlay->draw_texture(handle, global_end_location - handle->get_size() / 2);
+}
+
+void NavigationLink2DEditor::edit(NavigationLink2D *p_node) {
+ if (!canvas_item_editor) {
+ canvas_item_editor = CanvasItemEditor::get_singleton();
+ }
+
+ if (p_node) {
+ node = p_node;
+ } else {
+ node = nullptr;
+ }
+
+ canvas_item_editor->update_viewport();
+}
+
+NavigationLink2DEditor::NavigationLink2DEditor() {
+ undo_redo = EditorNode::get_undo_redo();
+}
+
+///////////////////////
+
+void NavigationLink2DEditorPlugin::edit(Object *p_object) {
+ editor->edit(Object::cast_to<NavigationLink2D>(p_object));
+}
+
+bool NavigationLink2DEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<NavigationLink2D>(p_object) != nullptr;
+}
+
+void NavigationLink2DEditorPlugin::make_visible(bool p_visible) {
+ if (!p_visible) {
+ edit(nullptr);
+ }
+}
+
+NavigationLink2DEditorPlugin::NavigationLink2DEditorPlugin() {
+ editor = memnew(NavigationLink2DEditor);
+ EditorNode::get_singleton()->get_gui_base()->add_child(editor);
+}
diff --git a/editor/plugins/navigation_link_2d_editor_plugin.h b/editor/plugins/navigation_link_2d_editor_plugin.h
new file mode 100644
index 0000000000..0a3d9b8810
--- /dev/null
+++ b/editor/plugins/navigation_link_2d_editor_plugin.h
@@ -0,0 +1,83 @@
+/*************************************************************************/
+/* navigation_link_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 NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
+#define NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "scene/2d/navigation_link_2d.h"
+
+class CanvasItemEditor;
+class EditorUndoRedoManager;
+
+class NavigationLink2DEditor : public Control {
+ GDCLASS(NavigationLink2DEditor, Control);
+
+ Ref<EditorUndoRedoManager> undo_redo;
+ CanvasItemEditor *canvas_item_editor = nullptr;
+ NavigationLink2D *node = nullptr;
+
+ bool start_grabbed = false;
+ Vector2 original_start_location;
+
+ bool end_grabbed = false;
+ Vector2 original_end_location;
+
+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(NavigationLink2D *p_node);
+
+ NavigationLink2DEditor();
+};
+
+class NavigationLink2DEditorPlugin : public EditorPlugin {
+ GDCLASS(NavigationLink2DEditorPlugin, EditorPlugin);
+
+ NavigationLink2DEditor *editor = nullptr;
+
+public:
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { editor->forward_canvas_draw_over_viewport(p_overlay); }
+
+ virtual String get_name() const override { return "NavigationLink2D"; }
+ 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;
+
+ NavigationLink2DEditorPlugin();
+};
+
+#endif // NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index e8f143a637..ec6ea7f39b 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -35,6 +35,7 @@
#include "core/math/geometry_3d.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/audio_stream_player_3d.h"
@@ -51,14 +52,15 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
+#include "scene/3d/marker_3d.h"
#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/navigation_link_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/occluder_instance_3d.h"
-#include "scene/3d/position_3d.h"
#include "scene/3d/ray_cast_3d.h"
#include "scene/3d/reflection_probe.h"
#include "scene/3d/shape_cast_3d.h"
-#include "scene/3d/soft_dynamic_body_3d.h"
+#include "scene/3d/soft_body_3d.h"
#include "scene/3d/spring_arm_3d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body_3d.h"
@@ -1294,7 +1296,7 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec
//min_p = p_arc_xform.affine_inverse().xform(min_p);
float a = (Math_PI * 0.5) - Vector2(min_p.x, -min_p.z).angle();
- return Math::rad2deg(a);
+ return Math::rad_to_deg(a);
}
void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -1347,13 +1349,13 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore);
} else if (p_id == 0) {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore);
ur->commit_action();
} else if (p_id == 1) {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore);
@@ -1364,7 +1366,8 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
- Color color = light->get_color();
+ Color color = light->get_color().srgb_to_linear() * light->get_correlated_color().srgb_to_linear();
+ color = color.linear_to_srgb();
// Make the gizmo color as bright as possible for better visibility
color.set_hsv(color.get_h(), color.get_s(), 1);
@@ -1420,8 +1423,8 @@ void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int i = 0; i < 120; i++) {
// Create a circle
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -1457,13 +1460,13 @@ void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
SpotLight3D *sl = Object::cast_to<SpotLight3D>(light);
float r = sl->get_param(Light3D::PARAM_RANGE);
- float w = r * Math::sin(Math::deg2rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
- float d = r * Math::cos(Math::deg2rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+ float w = r * Math::sin(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+ float d = r * Math::cos(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
for (int i = 0; i < 120; i++) {
// Draw a circle
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
@@ -1544,8 +1547,8 @@ void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo
float closest_angle = 1e20;
for (int i = 0; i < 180; i++) {
- float a = Math::deg2rad((float)i);
- float an = Math::deg2rad((float)(i + 1));
+ float a = Math::deg_to_rad((float)i);
+ float an = Math::deg_to_rad((float)(i + 1));
Vector3 from(Math::sin(a), 0, -Math::cos(a));
Vector3 to(Math::sin(an), 0, -Math::cos(an));
@@ -1571,7 +1574,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi
player->set_emission_angle(p_restore);
} else {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle"));
ur->add_do_method(player, "set_emission_angle", player->get_emission_angle());
ur->add_undo_method(player, "set_emission_angle", p_restore);
@@ -1627,8 +1630,8 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int i = 0; i < 120; i++) {
// Create a circle.
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -1670,8 +1673,8 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (player->is_emission_angle_enabled()) {
const float pc = player->get_emission_angle();
- const float ofs = -Math::cos(Math::deg2rad(pc));
- const float radius = Math::sin(Math::deg2rad(pc));
+ const float ofs = -Math::cos(Math::deg_to_rad(pc));
+ const float radius = Math::sin(Math::deg_to_rad(pc));
Vector<Vector3> points_primary;
points_primary.resize(200);
@@ -1706,7 +1709,7 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(points_secondary, material_secondary);
Vector<Vector3> handles;
- const float ha = Math::deg2rad(player->get_emission_angle());
+ const float ha = Math::deg_to_rad(player->get_emission_angle());
handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha)));
p_gizmo->add_handles(handles, get_material("handles"));
}
@@ -1814,7 +1817,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("fov", p_restore);
} else {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Camera FOV"));
ur->add_do_property(camera, "fov", camera->get_fov());
ur->add_undo_property(camera, "fov", p_restore);
@@ -1825,7 +1828,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("size", p_restore);
} else {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Camera Size"));
ur->add_do_property(camera, "size", camera->get_size());
ur->add_undo_property(camera, "size", p_restore);
@@ -1871,7 +1874,7 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
// The real FOV is halved for accurate representation
float fov = camera->get_fov() / 2.0;
- Vector3 side = Vector3(Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)));
+ Vector3 side = Vector3(Math::sin(Math::deg_to_rad(fov)), 0, -Math::cos(Math::deg_to_rad(fov)));
Vector3 nside = side;
nside.x = -nside.x;
Vector3 up = Vector3(0, side.x, 0);
@@ -1943,7 +1946,7 @@ MeshInstance3DGizmoPlugin::MeshInstance3DGizmoPlugin() {
}
bool MeshInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftDynamicBody3D>(p_spatial) == nullptr;
+ return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftBody3D>(p_spatial) == nullptr;
}
String MeshInstance3DGizmoPlugin::get_gizmo_name() const {
@@ -2141,7 +2144,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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);
@@ -2155,7 +2158,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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);
@@ -2169,7 +2172,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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);
@@ -2291,7 +2294,7 @@ void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///
-Position3DGizmoPlugin::Position3DGizmoPlugin() {
+Marker3DGizmoPlugin::Marker3DGizmoPlugin() {
pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
cursor_points = Vector<Vector3>();
@@ -2315,7 +2318,7 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() {
// Use the axis color which is brighter for the positive axis.
// Use a darkened axis color for the negative axis.
- // This makes it possible to see in which direction the Position3D node is rotated
+ // This makes it possible to see in which direction the Marker3D node is rotated
// (which can be important depending on how it's used).
const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_x_color"), SNAME("Editor"));
cursor_colors.push_back(color_x);
@@ -2351,19 +2354,19 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() {
pos3d_mesh->surface_set_material(0, mat);
}
-bool Position3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<Position3D>(p_spatial) != nullptr;
+bool Marker3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Marker3D>(p_spatial) != nullptr;
}
-String Position3DGizmoPlugin::get_gizmo_name() const {
- return "Position3D";
+String Marker3DGizmoPlugin::get_gizmo_name() const {
+ return "Marker3D";
}
-int Position3DGizmoPlugin::get_priority() const {
+int Marker3DGizmoPlugin::get_priority() const {
return -1;
}
-void Position3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+void Marker3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
p_gizmo->add_mesh(pos3d_mesh);
p_gizmo->add_collision_segments(cursor_points);
@@ -2642,8 +2645,8 @@ void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
float r = car_wheel->get_radius();
const int skip = 10;
for (int i = 0; i <= 360; i += skip) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + skip);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + skip);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -2686,30 +2689,30 @@ void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///////////
-SoftDynamicBody3DGizmoPlugin::SoftDynamicBody3DGizmoPlugin() {
+SoftBody3DGizmoPlugin::SoftBody3DGizmoPlugin() {
Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
create_handle_material("handles");
}
-bool SoftDynamicBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<SoftDynamicBody3D>(p_spatial) != nullptr;
+bool SoftBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<SoftBody3D>(p_spatial) != nullptr;
}
-String SoftDynamicBody3DGizmoPlugin::get_gizmo_name() const {
- return "SoftDynamicBody3D";
+String SoftBody3DGizmoPlugin::get_gizmo_name() const {
+ return "SoftBody3D";
}
-int SoftDynamicBody3DGizmoPlugin::get_priority() const {
+int SoftBody3DGizmoPlugin::get_priority() const {
return -1;
}
-bool SoftDynamicBody3DGizmoPlugin::is_selectable_when_hidden() const {
+bool SoftBody3DGizmoPlugin::is_selectable_when_hidden() const {
return true;
}
-void SoftDynamicBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
+void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
p_gizmo->clear();
@@ -2745,22 +2748,22 @@ void SoftDynamicBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_triangles(tm);
}
-String SoftDynamicBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- return "SoftDynamicBody3D pin point";
+String SoftBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ return "SoftBody3D pin point";
}
-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());
+Variant SoftBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(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, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
+void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
soft_body->pin_point_toggle(p_id);
}
-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());
+bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
return soft_body->is_point_pinned(p_id);
}
@@ -2870,7 +2873,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Notifier AABB"));
ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
ur->add_undo_method(notifier, "set_aabb", p_restore);
@@ -3061,7 +3064,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Particles AABB"));
ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb());
ur->add_undo_method(particles, "set_visibility_aabb", p_restore);
@@ -3227,7 +3230,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Radius"));
ur->add_do_method(sn, "set_radius", sn->call("get_radius"));
ur->add_undo_method(sn, "set_radius", p_restore);
@@ -3240,7 +3243,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Box Shape Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
@@ -3271,8 +3274,8 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -3499,7 +3502,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
@@ -3651,7 +3654,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Decal Extents"));
ur->add_do_method(decal, "set_extents", decal->get_extents());
ur->add_undo_method(decal, "set_extents", restore);
@@ -3791,7 +3794,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_undo_method(probe, "set_extents", restore);
@@ -4406,7 +4409,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
@@ -4420,7 +4423,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(ss.ptr(), "set_size", ss->get_size());
ur->add_undo_method(ss.ptr(), "set_size", p_restore);
@@ -4437,7 +4440,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (p_id == 0) {
ur->create_action(TTR("Change Capsule Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4462,7 +4465,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4487,7 +4490,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Separation Ray Shape Length"));
ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
ur->add_undo_method(ss.ptr(), "set_length", p_restore);
@@ -4516,8 +4519,8 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -4588,8 +4591,8 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3 d(0, height * 0.5 - radius, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
@@ -4659,8 +4662,8 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3 d(0, height * 0.5, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
@@ -4997,6 +5000,175 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
+////
+
+NavigationLink3DGizmoPlugin::NavigationLink3DGizmoPlugin() {
+ create_material("navigation_link_material", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_color());
+ create_material("navigation_link_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_disabled_color());
+ create_handle_material("handles");
+}
+
+bool NavigationLink3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<NavigationLink3D>(p_spatial) != nullptr;
+}
+
+String NavigationLink3DGizmoPlugin::get_gizmo_name() const {
+ return "NavigationLink3D";
+}
+
+int NavigationLink3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+
+ RID nav_map = link->get_world_3d()->get_navigation_map();
+ real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map);
+ Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map);
+ Vector3::Axis up_axis = up_vector.max_axis_index();
+
+ Vector3 start_location = link->get_start_location();
+ Vector3 end_location = link->get_end_location();
+
+ Ref<Material> link_material = get_material("navigation_link_material", p_gizmo);
+ Ref<Material> link_material_disabled = get_material("navigation_link_material_disabled", p_gizmo);
+ Ref<Material> handles_material = get_material("handles");
+
+ p_gizmo->clear();
+
+ // Draw line between the points.
+ Vector<Vector3> lines;
+ lines.append(start_location);
+ lines.append(end_location);
+
+ // Draw start location search radius
+ for (int i = 0; i < 30; i++) {
+ // Create a circle
+ const float ra = Math::deg_to_rad((float)(i * 12));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 12));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
+
+ // Draw axis-aligned circle
+ switch (up_axis) {
+ case Vector3::AXIS_X:
+ lines.append(start_location + Vector3(0, a.x, a.y));
+ lines.append(start_location + Vector3(0, b.x, b.y));
+ break;
+ case Vector3::AXIS_Y:
+ lines.append(start_location + Vector3(a.x, 0, a.y));
+ lines.append(start_location + Vector3(b.x, 0, b.y));
+ break;
+ case Vector3::AXIS_Z:
+ lines.append(start_location + Vector3(a.x, a.y, 0));
+ lines.append(start_location + Vector3(b.x, b.y, 0));
+ break;
+ }
+ }
+
+ // Draw end location search radius
+ for (int i = 0; i < 30; i++) {
+ // Create a circle
+ const float ra = Math::deg_to_rad((float)(i * 12));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 12));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
+
+ // Draw axis-aligned circle
+ switch (up_axis) {
+ case Vector3::AXIS_X:
+ lines.append(end_location + Vector3(0, a.x, a.y));
+ lines.append(end_location + Vector3(0, b.x, b.y));
+ break;
+ case Vector3::AXIS_Y:
+ lines.append(end_location + Vector3(a.x, 0, a.y));
+ lines.append(end_location + Vector3(b.x, 0, b.y));
+ break;
+ case Vector3::AXIS_Z:
+ lines.append(end_location + Vector3(a.x, a.y, 0));
+ lines.append(end_location + Vector3(b.x, b.y, 0));
+ break;
+ }
+ }
+
+ p_gizmo->add_lines(lines, link->is_enabled() ? link_material : link_material_disabled);
+ p_gizmo->add_collision_segments(lines);
+
+ Vector<Vector3> handles;
+ handles.append(start_location);
+ handles.append(end_location);
+ p_gizmo->add_handles(handles, handles_material);
+}
+
+String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ return p_id == 0 ? TTR("Start Location") : TTR("End Location");
+}
+
+Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+ return p_id == 0 ? link->get_start_location() : link->get_end_location();
+}
+
+void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+
+ Transform3D gt = link->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
+
+ Transform3D ct = p_camera->get_global_transform();
+ Vector3 cam_dir = ct.basis.get_column(Vector3::AXIS_Z);
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 location = p_id == 0 ? link->get_start_location() : link->get_end_location();
+ Plane move_plane = Plane(cam_dir, gt.xform(location));
+
+ Vector3 intersection;
+ if (!move_plane.intersects_ray(ray_from, ray_dir, &intersection)) {
+ return;
+ }
+
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ double snap = Node3DEditor::get_singleton()->get_translate_snap();
+ intersection.snap(Vector3(snap, snap, snap));
+ }
+
+ location = gi.xform(intersection);
+ if (p_id == 0) {
+ link->set_start_location(location);
+ } else if (p_id == 1) {
+ link->set_end_location(location);
+ }
+}
+
+void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+
+ if (p_cancel) {
+ if (p_id == 0) {
+ link->set_start_location(p_restore);
+ } else {
+ link->set_end_location(p_restore);
+ }
+ return;
+ }
+
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ if (p_id == 0) {
+ ur->create_action(TTR("Change Start Location"));
+ ur->add_do_method(link, "set_start_location", link->get_start_location());
+ ur->add_undo_method(link, "set_start_location", p_restore);
+ } else {
+ ur->create_action(TTR("Change End Location"));
+ ur->add_do_method(link, "set_end_location", link->get_end_location());
+ ur->add_undo_method(link, "set_end_location", p_restore);
+ }
+
+ ur->commit_action();
+}
+
//////
#define BODY_A_RADIUS 0.25
@@ -5202,8 +5374,8 @@ void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_ba
//swing
for (int i = 0; i < 360; i += 10) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 10);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 10);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
@@ -5220,12 +5392,12 @@ void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_ba
r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(1, 0, 0))).origin);
/// Twist
- float ts = Math::rad2deg(p_twist);
+ float ts = Math::rad_to_deg(p_twist);
ts = MIN(ts, 720);
for (int i = 0; i < int(ts); i += 5) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 5);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 5);
float c = i / 720.0;
float cn = (i + 5) / 720.0;
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c;
@@ -5745,7 +5917,7 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Fog Volume Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 739bf1b929..5924f8571a 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -334,8 +334,8 @@ public:
Label3DGizmoPlugin();
};
-class Position3DGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(Position3DGizmoPlugin, EditorNode3DGizmoPlugin);
+class Marker3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(Marker3DGizmoPlugin, EditorNode3DGizmoPlugin);
Ref<ArrayMesh> pos3d_mesh;
Vector<Vector3> cursor_points;
@@ -346,7 +346,7 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- Position3DGizmoPlugin();
+ Marker3DGizmoPlugin();
};
class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin {
@@ -409,8 +409,8 @@ public:
VehicleWheel3DGizmoPlugin();
};
-class SoftDynamicBody3DGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(SoftDynamicBody3DGizmoPlugin, EditorNode3DGizmoPlugin);
+class SoftBody3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(SoftBody3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
@@ -424,7 +424,7 @@ public:
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();
+ SoftBody3DGizmoPlugin();
};
class VisibleOnScreenNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin {
@@ -631,6 +631,23 @@ public:
NavigationRegion3DGizmoPlugin();
};
+class NavigationLink3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(NavigationLink3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ 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;
+
+ NavigationLink3DGizmoPlugin();
+};
+
class JointGizmosDrawer {
public:
static Basis look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 6afc6798d0..b9f3015837 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -46,6 +46,7 @@
#include "editor/scene_tree_dock.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/decal.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/physics_body_3d.h"
@@ -98,7 +99,7 @@ void ViewportRotationControl::_notification(int p_what) {
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();
+ queue_redraw();
if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) {
connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited));
@@ -246,13 +247,13 @@ void ViewportRotationControl::_update_focus() {
}
if (focused_axis != original_focus) {
- update();
+ queue_redraw();
}
}
void ViewportRotationControl::_on_mouse_exited() {
focused_axis = -2;
- update();
+ queue_redraw();
}
void ViewportRotationControl::set_viewport(Node3DEditorViewport *p_viewport) {
@@ -341,7 +342,7 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
camera->set_global_transform(to_camera_transform(camera_cursor));
if (orthogonal) {
- float half_fov = Math::deg2rad(get_fov()) / 2.0;
+ float half_fov = Math::deg_to_rad(get_fov()) / 2.0;
float height = 2.0 * cursor.distance * Math::tan(half_fov);
camera->set_orthogonal(height, get_znear(), get_zfar());
} else {
@@ -349,7 +350,7 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
}
update_transform_gizmo_view();
- rotation_control->update();
+ rotation_control->queue_redraw();
spatial_editor->update_grid();
}
}
@@ -1585,7 +1586,7 @@ 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) {
+ if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_or_control_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
begin_transform(TRANSFORM_ROTATE, false);
break;
}
@@ -1613,7 +1614,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
- surface->update();
+ surface->queue_redraw();
} else {
if (_edit.gizmo.is_valid()) {
_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, false);
@@ -1631,7 +1632,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (cursor.region_select) {
_select_region();
cursor.region_select = false;
- surface->update();
+ surface->queue_redraw();
}
}
@@ -1656,7 +1657,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.mode = TRANSFORM_NONE;
set_message("");
}
- surface->update();
+ surface->queue_redraw();
}
} break;
@@ -1740,7 +1741,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (cursor.region_select) {
cursor.region_end = m->get_position();
- surface->update();
+ surface->queue_redraw();
return;
}
@@ -2143,7 +2144,7 @@ void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, cons
}
const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
- const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ const real_t radians_per_pixel = Math::deg_to_rad(degrees_per_pixel);
const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
@@ -2176,7 +2177,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
// 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 real_t radians_per_pixel = Math::deg_to_rad(degrees_per_pixel);
const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
@@ -2243,12 +2244,12 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) {
void Node3DEditorViewport::scale_fov(real_t p_fov_offset) {
cursor.fov_scale = CLAMP(cursor.fov_scale + p_fov_offset, 0.1, 2.5);
- surface->update();
+ surface->queue_redraw();
}
void Node3DEditorViewport::reset_fov() {
cursor.fov_scale = 1.0;
- surface->update();
+ surface->queue_redraw();
}
void Node3DEditorViewport::scale_cursor_distance(real_t scale) {
@@ -2267,7 +2268,7 @@ void Node3DEditorViewport::scale_cursor_distance(real_t scale) {
}
zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
- surface->update();
+ surface->queue_redraw();
}
void Node3DEditorViewport::scale_freelook_speed(real_t scale) {
@@ -2280,7 +2281,7 @@ void Node3DEditorViewport::scale_freelook_speed(real_t scale) {
}
zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
- surface->update();
+ surface->queue_redraw();
}
Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const {
@@ -2374,12 +2375,12 @@ void Node3DEditorPlugin::edited_scene_changed() {
void Node3DEditorViewport::_project_settings_changed() {
//update shadow atlas if changed
- int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_size");
- bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_16_bits");
- int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv");
- int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv");
- int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv");
- int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv");
+ int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_size");
+ bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_16_bits");
+ int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv");
+ int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv");
+ int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv");
+ int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv");
viewport->set_positional_shadow_atlas_size(shadowmap_size);
viewport->set_positional_shadow_atlas_16_bits(shadowmap_16_bits);
@@ -2392,8 +2393,8 @@ void Node3DEditorViewport::_project_settings_changed() {
// Update MSAA, screen-space AA and debanding if changed
- const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa");
- viewport->set_msaa(Viewport::MSAA(msaa_mode));
+ const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa_3d");
+ viewport->set_msaa_3d(Viewport::MSAA(msaa_mode));
const int ssaa_mode = GLOBAL_GET("rendering/anti_aliasing/quality/screen_space_aa");
viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
const bool use_taa = GLOBAL_GET("rendering/anti_aliasing/quality/use_taa");
@@ -2453,7 +2454,7 @@ void Node3DEditorViewport::_notification(int p_what) {
if (zoom_indicator_delay > 0) {
zoom_indicator_delay -= delta;
if (zoom_indicator_delay <= 0) {
- surface->update();
+ surface->queue_redraw();
zoom_limit_label->hide();
}
}
@@ -2471,7 +2472,7 @@ void Node3DEditorViewport::_notification(int p_what) {
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();
+ surface->queue_redraw();
}
}
@@ -2537,13 +2538,13 @@ void Node3DEditorViewport::_notification(int p_what) {
if (message_time > 0) {
if (message != last_message) {
- surface->update();
+ surface->queue_redraw();
last_message = message;
}
message_time -= get_physics_process_delta_time();
if (message_time < 0) {
- surface->update();
+ surface->queue_redraw();
}
}
@@ -2623,14 +2624,14 @@ void Node3DEditorViewport::_notification(int p_what) {
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)));
+ Math::remap(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)));
+ Math::remap(gpu_time, 0, 30, 0, 1)));
const double fps = 1000.0 / gpu_time;
fps_label->set_text(vformat(TTR("FPS: %d"), fps));
@@ -2638,7 +2639,7 @@ void Node3DEditorViewport::_notification(int p_what) {
fps_label->add_theme_color_override(
"font_color",
frame_time_gradient->get_color_at_offset(
- Math::range_lerp(fps, 110, 10, 0, 1)));
+ Math::remap(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));
@@ -2972,6 +2973,13 @@ void Node3DEditorViewport::_menu_option(int p_option) {
xform.scale_basis(sp->get_scale());
}
+ if (Object::cast_to<Decal>(E)) {
+ // Adjust rotation to match Decal's default orientation.
+ // This makes the decal "look" in the same direction as the camera,
+ // rather than pointing down relative to the camera orientation.
+ xform.basis.rotate_local(Vector3(1, 0, 0), Math_TAU * 0.25);
+ }
+
undo_redo->add_do_method(sp, "set_global_transform", xform);
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
}
@@ -2999,7 +3007,16 @@ void Node3DEditorViewport::_menu_option(int p_option) {
continue;
}
- undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_euler_normalized());
+ Basis basis = camera_transform.basis;
+
+ if (Object::cast_to<Decal>(E)) {
+ // Adjust rotation to match Decal's default orientation.
+ // This makes the decal "look" in the same direction as the camera,
+ // rather than pointing down relative to the camera orientation.
+ basis.rotate_local(Vector3(1, 0, 0), Math_TAU * 0.25);
+ }
+
+ undo_redo->add_do_method(sp, "set_rotation", basis.get_euler_normalized());
undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation());
}
undo_redo->commit_action();
@@ -3339,13 +3356,13 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) {
if (!preview) {
preview_camera->hide();
}
- surface->update();
+ surface->queue_redraw();
} else {
previewing = preview;
previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
- surface->update();
+ surface->queue_redraw();
}
}
@@ -3367,7 +3384,7 @@ void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) {
preview_camera->show();
}
view_menu->show();
- surface->update();
+ surface->queue_redraw();
}
}
@@ -3602,7 +3619,7 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) {
previewing = Object::cast_to<Camera3D>(pv);
previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene));
RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace
- surface->update();
+ surface->queue_redraw();
preview_camera->set_pressed(true);
preview_camera->show();
}
@@ -3964,19 +3981,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
// 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);
+ mesh_instance->set_name(Node::adjust_name_casing(name));
instantiated_scene = mesh_instance;
} else {
@@ -4003,15 +4008,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, 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);
+ 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", 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));
+ 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) {
@@ -4024,7 +4029,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
global_transform.basis *= node3d->get_transform().basis;
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_global_transform", global_transform);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", global_transform);
}
return true;
@@ -4035,15 +4040,15 @@ void Node3DEditorViewport::_perform_drop_data() {
GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
if (mesh_instance && spatial_editor->get_preview_material_surface() != -1) {
- editor_data->get_undo_redo().create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface()));
- editor_data->get_undo_redo().add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material());
- editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material());
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface()));
+ editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material());
+ editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material());
+ editor_data->get_undo_redo()->commit_action();
} else if (geometry_instance) {
- editor_data->get_undo_redo().create_action(TTR("Set Material Override"));
- editor_data->get_undo_redo().add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material());
- editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material());
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Set Material Override"));
+ editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material());
+ editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material());
+ editor_data->get_undo_redo()->commit_action();
}
_remove_preview_material();
@@ -4054,7 +4059,7 @@ void Node3DEditorViewport::_perform_drop_data() {
Vector<String> error_files;
- editor_data->get_undo_redo().create_action(TTR("Create Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Create Node"));
for (int i = 0; i < selected_files.size(); i++) {
String path = selected_files[i];
@@ -4072,7 +4077,7 @@ void Node3DEditorViewport::_perform_drop_data() {
}
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
if (error_files.size() > 0) {
String files_str;
@@ -4113,6 +4118,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
continue;
}
Ref<PackedScene> scn = res;
+ Ref<Mesh> mesh = res;
Ref<Material> mat = res;
Ref<Texture2D> tex = res;
if (scn.is_valid()) {
@@ -4131,6 +4137,8 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
spatial_editor->set_preview_material(mat);
break;
+ } else if (mesh.is_valid()) {
+ // Let the mesh pass.
} else if (tex.is_valid()) {
Ref<StandardMaterial3D> new_mat = memnew(StandardMaterial3D);
new_mat->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, tex);
@@ -4384,7 +4392,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4483,7 +4491,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
@@ -4526,7 +4534,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
break;
}
- static const float orthogonal_threshold = Math::cos(Math::deg2rad(87.0f));
+ static const float orthogonal_threshold = Math::cos(Math::deg_to_rad(87.0f));
bool axis_is_orthogonal = ABS(plane.normal.dot(global_axis)) < orthogonal_threshold;
double angle = 0.0f;
@@ -4546,10 +4554,10 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
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::rad_to_deg(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);
+ angle = Math::deg_to_rad(angle);
bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
@@ -4587,7 +4595,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
}
spatial_editor->update_transform_gizmo();
- surface->update();
+ surface->queue_redraw();
} break;
default: {
@@ -4600,7 +4608,7 @@ void Node3DEditorViewport::finish_transform() {
spatial_editor->update_transform_gizmo();
_edit.mode = TRANSFORM_NONE;
_edit.instant = false;
- surface->update();
+ surface->queue_redraw();
}
// Register a shortcut and also add it as an input action with the same events.
@@ -4809,7 +4817,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
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"), KeyModifierMask::CMD | Key::P));
+ preview_camera->set_shortcut(ED_SHORTCUT("spatial_editor/toggle_camera_preview", TTR("Toggle Camera Preview"), KeyModifierMask::CMD_OR_CTRL | Key::P));
vbox->add_child(preview_camera);
preview_camera->set_h_size_flags(0);
preview_camera->hide();
@@ -5002,7 +5010,7 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) {
hovering_v = mm->get_position().y > (mid_h - v_sep / 2) && mm->get_position().y < (mid_h + v_sep / 2);
if (was_hovering_h != hovering_h || was_hovering_v != hovering_v) {
- update();
+ queue_redraw();
}
}
@@ -5011,14 +5019,14 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) {
new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width);
ratio_h = new_ratio;
queue_sort();
- update();
+ queue_redraw();
}
if (dragging_v) {
real_t new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height);
ratio_v = new_ratio;
queue_sort();
- update();
+ queue_redraw();
}
}
}
@@ -5028,7 +5036,7 @@ void Node3DEditorViewportContainer::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER:
case NOTIFICATION_MOUSE_EXIT: {
mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -5717,7 +5725,7 @@ void Node3DEditor::_xform_dialog_action() {
for (int i = 0; i < 3; i++) {
translate[i] = xform_translate[i]->get_text().to_float();
- rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_float());
+ rotate[i] = Math::deg_to_rad(xform_rotate[i]->get_text().to_float());
scale[i] = xform_scale[i]->get_text().to_float();
}
@@ -5810,11 +5818,11 @@ void Node3DEditor::_update_camera_override_button(bool p_game_running) {
if (p_game_running) {
button->set_disabled(false);
- button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
+ button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
} else {
button->set_disabled(true);
button->set_pressed(false);
- button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
+ button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
}
}
@@ -6400,7 +6408,7 @@ void fragment() {
Ref<ShaderMaterial> rotate_mat = memnew(ShaderMaterial);
rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX);
rotate_mat->set_shader(rotate_shader);
- rotate_mat->set_shader_uniform("albedo", col);
+ rotate_mat->set_shader_parameter("albedo", col);
rotate_gizmo_color[i] = rotate_mat;
Array arrays = surftool->commit_to_arrays();
@@ -6408,7 +6416,7 @@ void fragment() {
rotate_gizmo[i]->surface_set_material(0, rotate_mat);
Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate();
- rotate_mat_hl->set_shader_uniform("albedo", albedo);
+ rotate_mat_hl->set_shader_parameter("albedo", albedo);
rotate_gizmo_color_hl[i] = rotate_mat_hl;
if (i == 2) { // Rotation white outline
@@ -6449,7 +6457,7 @@ void fragment() {
)");
border_mat->set_shader(border_shader);
- border_mat->set_shader_uniform("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
+ border_mat->set_shader_parameter("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
rotate_gizmo[3] = Ref<ArrayMesh>(memnew(ArrayMesh));
rotate_gizmo[3]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
@@ -6702,8 +6710,8 @@ void Node3DEditor::_init_grid() {
fade_size = CLAMP(fade_size, min_fade_size, max_fade_size);
real_t grid_fade_size = (grid_size - primary_grid_steps) * fade_size;
- grid_mat[c]->set_shader_uniform("grid_size", grid_fade_size);
- grid_mat[c]->set_shader_uniform("orthogonal", orthogonal);
+ grid_mat[c]->set_shader_parameter("grid_size", grid_fade_size);
+ grid_mat[c]->set_shader_parameter("orthogonal", orthogonal);
// Cache these so we don't have to re-access memory.
Vector<Vector3> &ref_grid = grid_points[c];
@@ -7114,6 +7122,9 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
WorldEnvironment *new_env = memnew(WorldEnvironment);
new_env->set_environment(preview_environment->get_environment()->duplicate(true));
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ new_env->set_camera_attributes(preview_environment->get_camera_attributes()->duplicate(true));
+ }
undo_redo->create_action(TTR("Add Preview Environment to Scene"));
undo_redo->add_do_method(base, "add_child", new_env, true);
@@ -7247,6 +7258,14 @@ Vector<int> Node3DEditor::get_subgizmo_selection() {
return ret;
}
+void Node3DEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
+Ref<EditorUndoRedoManager> Node3DEditor::get_undo_redo() {
+ return undo_redo;
+}
+
void Node3DEditor::add_control_to_menu_panel(Control *p_control) {
context_menu_hbox->add_child(p_control);
}
@@ -7484,10 +7503,10 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<AudioListener3DGizmoPlugin>(memnew(AudioListener3DGizmoPlugin)));
add_gizmo_plugin(Ref<MeshInstance3DGizmoPlugin>(memnew(MeshInstance3DGizmoPlugin)));
add_gizmo_plugin(Ref<OccluderInstance3DGizmoPlugin>(memnew(OccluderInstance3DGizmoPlugin)));
- add_gizmo_plugin(Ref<SoftDynamicBody3DGizmoPlugin>(memnew(SoftDynamicBody3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<SoftBody3DGizmoPlugin>(memnew(SoftBody3DGizmoPlugin)));
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<Marker3DGizmoPlugin>(memnew(Marker3DGizmoPlugin)));
add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<ShapeCast3DGizmoPlugin>(memnew(ShapeCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin)));
@@ -7504,6 +7523,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<CollisionObject3DGizmoPlugin>(memnew(CollisionObject3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionPolygon3DGizmoPlugin>(memnew(CollisionPolygon3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<NavigationLink3DGizmoPlugin>(memnew(NavigationLink3DGizmoPlugin)));
add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
add_gizmo_plugin(Ref<Joint3DGizmoPlugin>(memnew(Joint3DGizmoPlugin)));
add_gizmo_plugin(Ref<PhysicalBone3DGizmoPlugin>(memnew(PhysicalBone3DGizmoPlugin)));
@@ -7551,9 +7571,9 @@ 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_column(Vector3::AXIS_Z);
z_axis = get_editor_viewport(0)->camera->get_camera_transform().basis.xform_inv(z_axis);
- sun_direction_material->set_shader_uniform("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z));
+ sun_direction_material->set_shader_parameter("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z));
Color color = sun_color->get_pick_color() * sun_energy->get_value();
- sun_direction_material->set_shader_uniform("sun_color", Vector3(color.r, color.g, color.b));
+ sun_direction_material->set_shader_parameter("sun_color", Vector3(color.r, color.g, color.b));
}
void Node3DEditor::_preview_settings_changed() {
@@ -7565,14 +7585,14 @@ void Node3DEditor::_preview_settings_changed() {
Transform3D t;
t.basis = Basis(Vector3(sun_rotation.x, sun_rotation.y, 0));
preview_sun->set_transform(t);
- sun_direction->update();
+ sun_direction->queue_redraw();
preview_sun->set_param(Light3D::PARAM_ENERGY, sun_energy->get_value());
preview_sun->set_param(Light3D::PARAM_SHADOW_MAX_DISTANCE, sun_max_distance->get_value());
preview_sun->set_color(sun_color->get_pick_color());
}
{ //preview env
- sky_material->set_sky_energy(environ_energy->get_value());
+ sky_material->set_sky_energy_multiplier(environ_energy->get_value());
Color hz_color = environ_sky_color->get_pick_color().lerp(environ_ground_color->get_pick_color(), 0.5).lerp(Color(1, 1, 1), 0.5);
sky_material->set_sky_top_color(environ_sky_color->get_pick_color());
sky_material->set_sky_horizon_color(hz_color);
@@ -7595,11 +7615,11 @@ void Node3DEditor::_load_default_preview_settings() {
// On any not-tidally-locked planet, a sun would have an angular altitude
// of 60 degrees as the average of all points on the sphere at noon.
// The azimuth choice is arbitrary, but ideally shouldn't be on an axis.
- sun_rotation = Vector2(-Math::deg2rad(60.0), Math::deg2rad(150.0));
+ sun_rotation = Vector2(-Math::deg_to_rad(60.0), Math::deg_to_rad(150.0));
- 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();
+ sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y));
+ sun_direction->queue_redraw();
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);
@@ -7607,7 +7627,7 @@ void Node3DEditor::_load_default_preview_settings() {
environ_tonemap_button->set_pressed(true);
environ_ao_button->set_pressed(false);
environ_gi_button->set_pressed(false);
- sun_max_distance->set_value(250);
+ sun_max_distance->set_value(100);
sun_color->set_pick_color(Color(1, 1, 1));
sun_energy->set_value(1.0);
@@ -7641,8 +7661,8 @@ void Node3DEditor::_update_preview_environment() {
}
}
- sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
- sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
+ sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y));
bool disable_env = world_env_count > 0 || environ_button->is_pressed();
@@ -7675,15 +7695,15 @@ void Node3DEditor::_sun_direction_input(const Ref<InputEvent> &p_event) {
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);
- sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
- sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
+ sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y));
_preview_settings_changed();
}
}
void Node3DEditor::_sun_direction_angle_set() {
- sun_rotation.x = Math::deg2rad(-sun_angle_altitude->get_value());
- sun_rotation.y = Math::deg2rad(180.0 - sun_angle_azimuth->get_value());
+ sun_rotation.x = Math::deg_to_rad(-sun_angle_altitude->get_value());
+ sun_rotation.y = Math::deg_to_rad(180.0 - sun_angle_azimuth->get_value());
_preview_settings_changed();
}
@@ -7731,7 +7751,7 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SELECT));
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)KeyModifierMask::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_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked."));
main_menu_hbox->add_child(memnew(VSeparator));
tool_button[TOOL_MODE_MOVE] = memnew(Button);
@@ -7766,39 +7786,39 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_LIST_SELECT));
- tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show list of selectable nodes at position clicked."));
+ tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
tool_button[TOOL_LOCK_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_LOCK_SELECTED]);
tool_button[TOOL_LOCK_SELECTED]->set_flat(true);
tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED));
- tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock selected node, preventing selection and movement."));
+ tool_button[TOOL_LOCK_SELECTED]->set_tooltip_text(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)"), KeyModifierMask::CMD | Key::L));
+ tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::L));
tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
tool_button[TOOL_UNLOCK_SELECTED]->set_flat(true);
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED));
- tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock selected node, allowing selection and movement."));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip_text(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)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::L));
tool_button[TOOL_GROUP_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]);
tool_button[TOOL_GROUP_SELECTED]->set_flat(true);
tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED));
- tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Make selected node's children not selectable."));
+ tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children 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)"), KeyModifierMask::CMD | Key::G));
+ tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G));
tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true);
tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED));
- tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Make selected node's children selectable."));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children selectable."));
// 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)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -7830,7 +7850,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(memnew(VSeparator));
sun_button = memnew(Button);
- sun_button->set_tooltip(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled."));
+ sun_button->set_tooltip_text(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled."));
sun_button->set_toggle_mode(true);
sun_button->set_flat(true);
sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
@@ -7839,7 +7859,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(sun_button);
environ_button = memnew(Button);
- environ_button->set_tooltip(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled."));
+ environ_button->set_tooltip_text(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled."));
environ_button->set_toggle_mode(true);
environ_button->set_flat(true);
environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
@@ -7848,7 +7868,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(environ_button);
sun_environ_settings = memnew(Button);
- sun_environ_settings->set_tooltip(TTR("Edit Sun and Environment settings."));
+ sun_environ_settings->set_tooltip_text(TTR("Edit Sun and Environment settings."));
sun_environ_settings->set_flat(true);
sun_environ_settings->connect("pressed", callable_mp(this, &Node3DEditor::_sun_environ_settings_pressed));
@@ -7875,12 +7895,12 @@ Node3DEditor::Node3DEditor() {
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/align_transform_with_view", TTR("Align Transform with View"), KeyModifierMask::ALT + KeyModifierMask::CMD_OR_CTRL + Key::M);
+ ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KeyModifierMask::ALT + KeyModifierMask::CMD_OR_CTRL + 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);
+ ED_SHORTCUT("spatial_editor/decrease_fov", TTR("Decrease Field of View"), KeyModifierMask::CMD_OR_CTRL + Key::EQUAL); // Usually direct access key for `KEY_PLUS`.
+ ED_SHORTCUT("spatial_editor/increase_fov", TTR("Increase Field of View"), KeyModifierMask::CMD_OR_CTRL + Key::MINUS);
+ ED_SHORTCUT("spatial_editor/reset_fov", TTR("Reset Field of View to Default"), KeyModifierMask::CMD_OR_CTRL + Key::KEY_0);
PopupMenu *p;
@@ -7920,12 +7940,12 @@ Node3DEditor::Node3DEditor() {
accept = memnew(AcceptDialog);
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_radio_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KeyModifierMask::CMD_OR_CTRL + Key::KEY_1), MENU_VIEW_USE_1_VIEWPORT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KeyModifierMask::CMD_OR_CTRL + 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_OR_CTRL + 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_OR_CTRL + 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_OR_CTRL + 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_OR_CTRL + Key::KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
p->add_separator();
p->add_submenu_item(TTR("Gizmos"), "GizmosMenu");
@@ -8154,8 +8174,8 @@ void fragment() {
)");
sun_direction_material.instantiate();
sun_direction_material->set_shader(sun_direction_shader);
- sun_direction_material->set_shader_uniform("sun_direction", Vector3(0, 0, 1));
- sun_direction_material->set_shader_uniform("sun_color", Vector3(1, 1, 1));
+ sun_direction_material->set_shader_parameter("sun_direction", Vector3(0, 0, 1));
+ sun_direction_material->set_shader_parameter("sun_color", Vector3(1, 1, 1));
sun_direction->set_material(sun_direction_material);
HBoxContainer *sun_angle_hbox = memnew(HBoxContainer);
@@ -8206,7 +8226,7 @@ void fragment() {
sun_add_to_scene = memnew(Button);
sun_add_to_scene->set_text(TTR("Add Sun to Scene"));
- sun_add_to_scene->set_tooltip(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene."));
+ sun_add_to_scene->set_tooltip_text(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene."));
sun_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_sun_to_scene).bind(false));
sun_vb->add_spacer();
sun_vb->add_child(sun_add_to_scene);
@@ -8275,7 +8295,7 @@ void fragment() {
environ_add_to_scene = memnew(Button);
environ_add_to_scene->set_text(TTR("Add Environment to Scene"));
- environ_add_to_scene->set_tooltip(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene."));
+ environ_add_to_scene->set_tooltip_text(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene."));
environ_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_environment_to_scene).bind(false));
environ_vb->add_spacer();
environ_vb->add_child(environ_add_to_scene);
@@ -8292,6 +8312,10 @@ void fragment() {
preview_environment = memnew(WorldEnvironment);
environment.instantiate();
preview_environment->set_environment(environment);
+ if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
+ camera_attributes.instantiate();
+ preview_environment->set_camera_attributes(camera_attributes);
+ }
Ref<Sky> sky;
sky.instantiate();
sky_material.instantiate();
@@ -8425,7 +8449,7 @@ void Node3DEditor::remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) {
Node3DEditorPlugin::Node3DEditorPlugin() {
spatial_editor = memnew(Node3DEditor);
spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- EditorNode::get_singleton()->get_main_control()->add_child(spatial_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(spatial_editor);
spatial_editor->hide();
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 4469271a38..580cb878ce 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -53,6 +53,7 @@ class Node3DEditorViewport;
class SubViewportContainer;
class DirectionalLight3D;
class WorldEnvironment;
+class EditorUndoRedoManager;
class ViewportRotationControl : public Control {
GDCLASS(ViewportRotationControl, Control);
@@ -201,7 +202,7 @@ private:
EditorData *editor_data = nullptr;
EditorSelection *editor_selection = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CheckBox *preview_camera = nullptr;
SubViewportContainer *subviewport_container = nullptr;
@@ -432,7 +433,7 @@ protected:
static void _bind_methods();
public:
- void update_surface() { surface->update(); }
+ void update_surface() { surface->queue_redraw(); }
void update_transform_gizmo_view();
void set_can_preview(Camera3D *p_preview);
@@ -682,7 +683,7 @@ private:
HBoxContainer *context_menu_hbox = nullptr;
void _generate_selection_boxes();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
int camera_override_viewport_id;
@@ -764,6 +765,7 @@ private:
DirectionalLight3D *preview_sun = nullptr;
WorldEnvironment *preview_environment = nullptr;
Ref<Environment> environment;
+ Ref<CameraAttributesPhysical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
bool sun_environ_updating = false;
@@ -820,13 +822,13 @@ public:
void select_gizmo_highlight_axis(int p_axis);
void set_custom_camera(Node *p_camera) { custom_camera = p_camera; }
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
Dictionary get_state() const;
void set_state(const Dictionary &p_state);
Ref<Environment> get_viewport_environment() { return viewport_environment; }
- UndoRedo *get_undo_redo() { return undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
+ Ref<EditorUndoRedoManager> get_undo_redo();
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp
index 8d083d28b2..2f4ae734d1 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.cpp
+++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp
@@ -123,7 +123,7 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlugin() {
// Scene Node's properties containing strings that will be fetched for translation.
lookup_properties.insert("text");
- lookup_properties.insert("hint_tooltip");
+ lookup_properties.insert("tooltip_text");
lookup_properties.insert("placeholder_text");
lookup_properties.insert("items");
lookup_properties.insert("title");
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index fd331c4127..c8bd4c1d05 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
void Path2DEditor::_notification(int p_what) {
switch (p_what) {
@@ -149,7 +150,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point creation.
- if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_or_control_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
undo_redo->create_action(TTR("Add Point to Curve"));
@@ -536,7 +537,7 @@ Path2DEditor::Path2DEditor() {
curve_edit->set_flat(true);
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)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
+ curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + 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).bind(MODE_EDIT));
base_hb->add_child(curve_edit);
@@ -544,7 +545,7 @@ Path2DEditor::Path2DEditor() {
curve_edit_curve->set_flat(true);
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->set_tooltip_text(TTR("Select Control Points (Shift+Drag)"));
curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_EDIT_CURVE));
base_hb->add_child(curve_edit_curve);
@@ -552,7 +553,7 @@ Path2DEditor::Path2DEditor() {
curve_create->set_flat(true);
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->set_tooltip_text(TTR("Add Point (in empty space)"));
curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CREATE));
base_hb->add_child(curve_create);
@@ -560,14 +561,14 @@ Path2DEditor::Path2DEditor() {
curve_del->set_flat(true);
curve_del->set_toggle_mode(true);
curve_del->set_focus_mode(Control::FOCUS_NONE);
- curve_del->set_tooltip(TTR("Delete Point"));
+ curve_del->set_tooltip_text(TTR("Delete Point"));
curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_DELETE));
base_hb->add_child(curve_del);
curve_close = memnew(Button);
curve_close->set_flat(true);
curve_close->set_focus_mode(Control::FOCUS_NONE);
- curve_close->set_tooltip(TTR("Close Curve"));
+ curve_close->set_tooltip_text(TTR("Close Curve"));
curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(ACTION_CLOSE));
base_hb->add_child(curve_close);
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index 720f5c090f..13eca79010 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -36,11 +36,12 @@
#include "scene/gui/separator.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class Path2DEditor : public HBoxContainer {
GDCLASS(Path2DEditor, HBoxContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
Panel *panel = nullptr;
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 65b15a6001..adfaf11264 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/resources/curve.h"
@@ -172,7 +173,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (!p_secondary) {
if (p_cancel) {
@@ -385,7 +386,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
}
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (closest_seg != -1) {
//subdivide
@@ -427,21 +428,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 = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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 = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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 = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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));
@@ -520,7 +521,7 @@ void Path3DEditorPlugin::_close_curve() {
if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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());
@@ -596,7 +597,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
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)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
+ curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
curve_create = memnew(Button);
@@ -604,7 +605,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
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)"));
+ curve_create->set_tooltip_text(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);
@@ -612,14 +613,14 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_del->set_toggle_mode(true);
curve_del->hide();
curve_del->set_focus_mode(Control::FOCUS_NONE);
- curve_del->set_tooltip(TTR("Delete Point"));
+ curve_del->set_tooltip_text(TTR("Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del);
curve_close = memnew(Button);
curve_close->set_flat(true);
curve_close->hide();
curve_close->set_focus_mode(Control::FOCUS_NONE);
- curve_close->set_tooltip(TTR("Close Curve"));
+ curve_close->set_tooltip_text(TTR("Close Curve"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_close);
PopupMenu *menu;
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 4f46c99a04..58a3a07c43 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -94,8 +94,8 @@ void Polygon2DEditor::_notification(int p_what) {
[[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")));
+ uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
+ bone_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -155,8 +155,8 @@ void Polygon2DEditor::_sync_bones() {
undo_redo->add_undo_method(node, "_set_bones", prev_bones);
undo_redo->add_do_method(this, "_update_bone_list");
undo_redo->add_undo_method(this, "_update_bone_list");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -195,11 +195,11 @@ void Polygon2DEditor::_update_bone_list() {
cb->connect("pressed", callable_mp(this, &Polygon2DEditor::_bone_paint_selected).bind(i));
}
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_bone_paint_selected(int p_index) {
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
@@ -269,7 +269,7 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
}
uv_edit->set_size(uv_edit->get_size()); // Necessary readjustment of the popup window.
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_edit_popup_hide() {
@@ -293,8 +293,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create UV Map"));
undo_redo->add_do_method(node, "set_uv", points);
undo_redo->add_undo_method(node, "set_uv", uvs);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -314,8 +314,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create UV Map"));
undo_redo->add_do_method(node, "set_uv", points);
undo_redo->add_undo_method(node, "set_uv", uvs);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} break;
case UVEDIT_UV_TO_POLYGON: {
@@ -328,8 +328,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create Polygon"));
undo_redo->add_do_method(node, "set_polygon", uvs);
undo_redo->add_undo_method(node, "set_polygon", points);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} break;
case UVEDIT_UV_CLEAR: {
@@ -340,8 +340,8 @@ void Polygon2DEditor::_menu_option(int p_option) {
undo_redo->create_action(TTR("Create UV Map"));
undo_redo->add_do_method(node, "set_uv", Vector<Vector2>());
undo_redo->add_undo_method(node, "set_uv", uvs);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} break;
case UVEDIT_GRID_SETTINGS: {
@@ -391,8 +391,8 @@ void Polygon2DEditor::_update_polygon_editing_state() {
void Polygon2DEditor::_commit_action() {
// Makes that undo/redoing actions made outside of the UV editor still affect its polygon.
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport");
undo_redo->add_undo_method(CanvasItemEditor::get_singleton(), "update_viewport");
undo_redo->commit_action();
@@ -406,31 +406,31 @@ void Polygon2DEditor::_set_use_snap(bool p_use) {
void Polygon2DEditor::_set_show_grid(bool p_show) {
snap_show_grid = p_show;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "show_grid", p_show);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_off_x(real_t p_val) {
snap_offset.x = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_off_y(real_t p_val) {
snap_offset.y = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_step_x(real_t p_val) {
snap_step.x = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_set_snap_step_y(real_t p_val) {
snap_step.y = p_val;
EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_mode(int p_mode) {
@@ -495,7 +495,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
node->set_uv(points_prev);
node->set_internal_vertex_count(0);
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
} else {
Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position()));
@@ -514,8 +514,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "_set_bones", uv_create_bones_prev);
undo_redo->add_do_method(this, "_update_polygon_editing_state");
undo_redo->add_undo_method(this, "_update_polygon_editing_state");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
uv_drag = false;
uv_create = false;
@@ -566,8 +566,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices);
undo_redo->add_do_method(this, "_update_polygon_editing_state");
undo_redo->add_undo_method(this, "_update_polygon_editing_state");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -621,17 +621,17 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices);
undo_redo->add_do_method(this, "_update_polygon_editing_state");
undo_redo->add_undo_method(this, "_update_polygon_editing_state");
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
if (uv_move_current == UV_MODE_EDIT_POINT) {
- if (mb->is_shift_pressed() && mb->is_command_pressed()) {
+ if (mb->is_shift_pressed() && mb->is_command_or_control_pressed()) {
uv_move_current = UV_MODE_SCALE;
} else if (mb->is_shift_pressed()) {
uv_move_current = UV_MODE_MOVE;
- } else if (mb->is_command_pressed()) {
+ } else if (mb->is_command_or_control_pressed()) {
uv_move_current = UV_MODE_ROTATE;
}
}
@@ -679,8 +679,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->create_action(TTR("Add Custom Polygon"));
undo_redo->add_do_method(node, "set_polygons", polygons);
undo_redo->add_undo_method(node, "set_polygons", node->get_polygons());
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -720,8 +720,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
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());
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
}
@@ -748,15 +748,15 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->create_action(TTR("Transform UV Map"));
undo_redo->add_do_method(node, "set_uv", node->get_uv());
undo_redo->add_undo_method(node, "set_uv", points_prev);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
} else if (uv_edit_mode[1]->is_pressed() && uv_move_current == UV_MODE_EDIT_POINT) { // Edit polygon.
undo_redo->create_action(TTR("Transform Polygon"));
undo_redo->add_do_method(node, "set_polygon", node->get_polygon());
undo_redo->add_undo_method(node, "set_polygon", points_prev);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
}
@@ -767,8 +767,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->create_action(TTR("Paint Bone Weights"));
undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone));
undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->commit_action();
bone_painting = false;
}
@@ -780,7 +780,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
node->set_bone_weights(bone_painting_bone, prev_weights);
}
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
}
@@ -906,14 +906,14 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
node->set_bone_weights(bone_painting_bone, painted_weights);
}
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
CanvasItemEditor::get_singleton()->update_viewport();
} else if (polygon_create.size()) {
uv_create_to = mtx.affine_inverse().xform(mm->get_position());
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
} else if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) {
bone_paint_pos = mm->get_position();
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
}
@@ -954,7 +954,7 @@ void Polygon2DEditor::_uv_scroll_changed(real_t) {
uv_draw_ofs.x = uv_hscroll->get_value();
uv_draw_ofs.y = uv_vscroll->get_value();
uv_draw_zoom = uv_zoom->get_value();
- uv_edit_draw->update();
+ uv_edit_draw->queue_redraw();
}
void Polygon2DEditor::_uv_draw() {
@@ -1237,7 +1237,7 @@ Polygon2DEditor::Polygon2DEditor() {
button_uv = memnew(Button);
button_uv->set_flat(true);
add_child(button_uv);
- button_uv->set_tooltip(TTR("Open Polygon 2D UV editor."));
+ button_uv->set_tooltip_text(TTR("Open Polygon 2D UV editor."));
button_uv->connect("pressed", callable_mp(this, &Polygon2DEditor::_menu_option).bind(MODE_EDIT_UV));
uv_mode = UV_MODE_EDIT_POINT;
@@ -1293,17 +1293,17 @@ Polygon2DEditor::Polygon2DEditor() {
uv_button[i]->set_focus_mode(FOCUS_NONE);
}
- uv_button[UV_MODE_CREATE]->set_tooltip(TTR("Create Polygon"));
- uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip(TTR("Create Internal Vertex"));
- uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip(TTR("Remove Internal Vertex"));
- uv_button[UV_MODE_EDIT_POINT]->set_tooltip(TTR("Move Points") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale"));
- uv_button[UV_MODE_MOVE]->set_tooltip(TTR("Move Polygon"));
- uv_button[UV_MODE_ROTATE]->set_tooltip(TTR("Rotate Polygon"));
- uv_button[UV_MODE_SCALE]->set_tooltip(TTR("Scale Polygon"));
- uv_button[UV_MODE_ADD_POLYGON]->set_tooltip(TTR("Create a custom polygon. Enables custom polygon rendering."));
- uv_button[UV_MODE_REMOVE_POLYGON]->set_tooltip(TTR("Remove a custom polygon. If none remain, custom polygon rendering is disabled."));
- uv_button[UV_MODE_PAINT_WEIGHT]->set_tooltip(TTR("Paint weights with specified intensity."));
- uv_button[UV_MODE_CLEAR_WEIGHT]->set_tooltip(TTR("Unpaint weights with specified intensity."));
+ uv_button[UV_MODE_CREATE]->set_tooltip_text(TTR("Create Polygon"));
+ uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip_text(TTR("Create Internal Vertex"));
+ uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip_text(TTR("Remove Internal Vertex"));
+ uv_button[UV_MODE_EDIT_POINT]->set_tooltip_text(TTR("Move Points") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale"));
+ uv_button[UV_MODE_MOVE]->set_tooltip_text(TTR("Move Polygon"));
+ uv_button[UV_MODE_ROTATE]->set_tooltip_text(TTR("Rotate Polygon"));
+ uv_button[UV_MODE_SCALE]->set_tooltip_text(TTR("Scale Polygon"));
+ uv_button[UV_MODE_ADD_POLYGON]->set_tooltip_text(TTR("Create a custom polygon. Enables custom polygon rendering."));
+ uv_button[UV_MODE_REMOVE_POLYGON]->set_tooltip_text(TTR("Remove a custom polygon. If none remain, custom polygon rendering is disabled."));
+ uv_button[UV_MODE_PAINT_WEIGHT]->set_tooltip_text(TTR("Paint weights with specified intensity."));
+ uv_button[UV_MODE_CLEAR_WEIGHT]->set_tooltip_text(TTR("Unpaint weights with specified intensity."));
uv_button[UV_MODE_CREATE]->hide();
uv_button[UV_MODE_CREATE_INTERNAL]->hide();
@@ -1368,7 +1368,7 @@ Polygon2DEditor::Polygon2DEditor() {
b_snap_enable->set_focus_mode(FOCUS_NONE);
b_snap_enable->set_toggle_mode(true);
b_snap_enable->set_pressed(use_snap);
- b_snap_enable->set_tooltip(TTR("Enable Snap"));
+ b_snap_enable->set_tooltip_text(TTR("Enable Snap"));
b_snap_enable->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_use_snap));
b_snap_grid = memnew(Button);
@@ -1378,7 +1378,7 @@ Polygon2DEditor::Polygon2DEditor() {
b_snap_grid->set_focus_mode(FOCUS_NONE);
b_snap_grid->set_toggle_mode(true);
b_snap_grid->set_pressed(snap_show_grid);
- b_snap_grid->set_tooltip(TTR("Show Grid"));
+ b_snap_grid->set_tooltip_text(TTR("Show Grid"));
b_snap_grid->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_show_grid));
grid_settings = memnew(AcceptDialog);
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 83092f990f..2b3a5c3e23 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -38,6 +38,7 @@
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
diff --git a/editor/plugins/polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h
index e1e1261250..0eb02a39e2 100644
--- a/editor/plugins/polygon_3d_editor_plugin.h
+++ b/editor/plugins/polygon_3d_editor_plugin.h
@@ -37,11 +37,12 @@
#include "scene/resources/immediate_mesh.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class Polygon3DEditor : public HBoxContainer {
GDCLASS(Polygon3DEditor, HBoxContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum Mode {
MODE_CREATE,
MODE_EDIT,
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index 4e528ef066..21647d1b69 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -196,7 +196,7 @@ void ResourcePreloaderEditor::_update_library() {
String type = r->get_class();
ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(type, "Object"));
- ti->set_tooltip(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type);
+ ti->set_tooltip_text(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type);
ti->set_text(1, r->get_path());
ti->set_editable(1, false);
@@ -234,6 +234,10 @@ void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column,
}
}
+void ResourcePreloaderEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void ResourcePreloaderEditor::edit(ResourcePreloader *p_preloader) {
preloader = p_preloader;
@@ -352,7 +356,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
vbc->add_child(hbc);
load = memnew(Button);
- load->set_tooltip(TTR("Load Resource"));
+ load->set_tooltip_text(TTR("Load Resource"));
hbc->add_child(load);
paste = memnew(Button);
@@ -387,7 +391,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
}
void ResourcePreloaderEditorPlugin::edit(Object *p_object) {
- preloader_editor->set_undo_redo(&get_undo_redo());
+ preloader_editor->set_undo_redo(EditorNode::get_undo_redo());
ResourcePreloader *s = Object::cast_to<ResourcePreloader>(p_object);
if (!s) {
return;
diff --git a/editor/plugins/resource_preloader_editor_plugin.h b/editor/plugins/resource_preloader_editor_plugin.h
index 96cef3de21..ef80283dae 100644
--- a/editor/plugins/resource_preloader_editor_plugin.h
+++ b/editor/plugins/resource_preloader_editor_plugin.h
@@ -37,6 +37,7 @@
#include "scene/main/resource_preloader.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class ResourcePreloaderEditor : public PanelContainer {
GDCLASS(ResourcePreloaderEditor, PanelContainer);
@@ -66,7 +67,7 @@ class ResourcePreloaderEditor : public PanelContainer {
void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _item_edited();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
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;
@@ -78,7 +79,7 @@ protected:
static void _bind_methods();
public:
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(ResourcePreloader *p_preloader);
ResourcePreloaderEditor();
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index 681dd476e3..de30c4100d 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -198,7 +198,7 @@ void EditorPropertyRootMotion::_node_clear() {
void EditorPropertyRootMotion::update_property() {
NodePath p = get_edited_object()->get(get_edited_property());
- assign->set_tooltip(p);
+ assign->set_tooltip_text(p);
if (p == NodePath()) {
assign->set_icon(Ref<Texture2D>());
assign->set_text(TTR("Assign..."));
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index c53ac59c11..0a111aeb49 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -49,7 +49,6 @@
#include "editor/find_in_files.h"
#include "editor/node_dock.h"
#include "editor/plugins/shader_editor_plugin.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"
@@ -66,12 +65,12 @@ String EditorSyntaxHighlighter::_get_name() const {
return "Unnamed";
}
-Array EditorSyntaxHighlighter::_get_supported_languages() const {
- Array ret;
+PackedStringArray EditorSyntaxHighlighter::_get_supported_languages() const {
+ PackedStringArray ret;
if (GDVIRTUAL_CALL(_get_supported_languages, ret)) {
return ret;
}
- return Array();
+ return PackedStringArray();
}
Ref<EditorSyntaxHighlighter> EditorSyntaxHighlighter::_create() const {
@@ -883,7 +882,7 @@ void ScriptEditor::_queue_close_tabs() {
// Maybe there are unsaved changes.
if (se->is_unsaved()) {
_ask_close_current_unsaved_tab(se);
- erase_tab_confirm->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &ScriptEditor::_queue_close_tabs), CONNECT_ONESHOT);
+ erase_tab_confirm->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &ScriptEditor::_queue_close_tabs), CONNECT_ONE_SHOT);
break;
}
}
@@ -941,50 +940,6 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
disk_changed->hide();
}
-void ScriptEditor::_reload_scripts() {
- 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; //internal script, who cares
- }
-
- uint64_t last_date = edited_res->get_last_modified_time();
- uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
-
- if (last_date == date) {
- continue;
- }
-
- Ref<Script> script = edited_res;
- if (script != nullptr) {
- Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
- ERR_CONTINUE(!rel_script.is_valid());
- script->set_source_code(rel_script->get_source_code());
- script->set_last_modified_time(rel_script->get_last_modified_time());
- script->reload(true);
- }
-
- Ref<TextFile> text_file = edited_res;
- if (text_file != nullptr) {
- Error err;
- Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
- ERR_CONTINUE(!rel_text_file.is_valid());
- text_file->set_text(rel_text_file->get_text());
- text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
- }
- se->reload_text();
- }
-
- disk_changed->hide();
- _update_script_names();
-}
-
void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
@@ -1078,7 +1033,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) {
if (need_reload) {
if (!need_ask) {
- script_editor->_reload_scripts();
+ script_editor->reload_scripts();
need_reload = false;
} else {
disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.5);
@@ -1156,8 +1111,8 @@ Ref<Script> ScriptEditor::_get_current_script() {
}
}
-Array ScriptEditor::_get_open_scripts() const {
- Array ret;
+TypedArray<Script> ScriptEditor::_get_open_scripts() const {
+ TypedArray<Script> ret;
Vector<Ref<Script>> scripts = get_open_scripts();
int scrits_amount = scripts.size();
for (int idx_script = 0; idx_script < scrits_amount; idx_script++) {
@@ -1408,8 +1363,6 @@ void ScriptEditor::_menu_option(int p_option) {
es->set_editor(EditorNode::get_singleton());
es->_run();
-
- EditorNode::get_undo_redo()->clear_history();
} break;
case FILE_CLOSE: {
if (current->is_unsaved()) {
@@ -1543,7 +1496,7 @@ void ScriptEditor::_show_save_theme_as_dialog() {
file_dialog_option = THEME_SAVE_AS;
file_dialog->clear_filters();
file_dialog->add_filter("*.tet");
- file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme")));
+ file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(EditorSettings::get_singleton()->get("text_editor/theme/color_theme")));
file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("Save Theme As..."));
}
@@ -1734,7 +1687,7 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
continue;
}
- Array bpoints = se->get_breakpoints();
+ PackedInt32Array bpoints = se->get_breakpoints();
for (int j = 0; j < bpoints.size(); j++) {
p_breakpoints->push_back(base + ":" + itos((int)bpoints[j] + 1));
}
@@ -2041,7 +1994,7 @@ void ScriptEditor::_update_script_names() {
} break;
case DISPLAY_DIR_AND_NAME: {
if (!path.get_base_dir().get_file().is_empty()) {
- sd.name = path.get_base_dir().get_file().plus_file(name);
+ sd.name = path.get_base_dir().get_file().path_join(name);
} else {
sd.name = name;
}
@@ -2067,7 +2020,7 @@ void ScriptEditor::_update_script_names() {
name = name.get_file();
} break;
case DISPLAY_DIR_AND_NAME: {
- name = name.get_base_dir().get_file().plus_file(name.get_file());
+ name = name.get_base_dir().get_file().path_join(name.get_file());
} break;
default:
break;
@@ -2382,8 +2335,8 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
se->add_syntax_highlighter(highlighter);
if (script != nullptr && !highlighter_set) {
- Array languages = highlighter->_get_supported_languages();
- if (languages.find(script->get_language()->get_name()) > -1) {
+ PackedStringArray languages = highlighter->_get_supported_languages();
+ if (languages.has(script->get_language()->get_name())) {
se->set_syntax_highlighter(highlighter);
highlighter_set = true;
}
@@ -2591,6 +2544,50 @@ void ScriptEditor::apply_scripts() const {
}
}
+void ScriptEditor::reload_scripts() {
+ 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; //internal script, who cares
+ }
+
+ uint64_t last_date = edited_res->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(edited_res->get_path());
+
+ if (last_date == date) {
+ continue;
+ }
+
+ Ref<Script> script = edited_res;
+ if (script != nullptr) {
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_script.is_valid());
+ script->set_source_code(rel_script->get_source_code());
+ script->set_last_modified_time(rel_script->get_last_modified_time());
+ script->reload(true);
+ }
+
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ Error err;
+ Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
+ ERR_CONTINUE(!rel_text_file.is_valid());
+ text_file->set_text(rel_text_file->get_text());
+ text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ }
+ se->reload_text();
+ }
+
+ disk_changed->hide();
+ _update_script_names();
+}
+
void ScriptEditor::open_script_create_dialog(const String &p_base_name, const String &p_base_path) {
_menu_option(FILE_NEW);
script_create_dialog->config(p_base_name, p_base_path);
@@ -3270,7 +3267,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset());
// Save the cache.
- script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+ script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
}
void ScriptEditor::_help_class_open(const String &p_class) {
@@ -3366,15 +3363,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..."), KeyModifierMask::CMD | Key::F), HELP_SEARCH_FIND);
+ script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KeyModifierMask::CMD_OR_CTRL | 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"), KeyModifierMask::CMD | KeyModifierMask::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_OR_CTRL | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
script_search_menu->show();
} else {
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->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
script_search_menu->show();
} else {
script_search_menu->hide();
@@ -3448,8 +3445,8 @@ Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
return out_scripts;
}
-Array ScriptEditor::_get_open_script_editors() const {
- Array script_editors;
+TypedArray<ScriptEditorBase> ScriptEditor::_get_open_script_editors() const {
+ TypedArray<ScriptEditorBase> script_editors;
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) {
@@ -3651,7 +3648,7 @@ ScriptEditor::ScriptEditor() {
current_theme = "";
script_editor_cache.instantiate();
- script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+ script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
completion_cache = memnew(EditorScriptCodeCompletionCache);
restoring_layout = false;
@@ -3715,7 +3712,7 @@ ScriptEditor::ScriptEditor() {
members_overview_alphabeta_sort_button = memnew(Button);
members_overview_alphabeta_sort_button->set_flat(true);
- members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list."));
+ members_overview_alphabeta_sort_button->set_tooltip_text(TTR("Toggle alphabetical sorting of the method list."));
members_overview_alphabeta_sort_button->set_toggle_mode(true);
members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/script_list/sort_members_outline_alphabetically"));
members_overview_alphabeta_sort_button->connect("toggled", callable_mp(this, &ScriptEditor::_toggle_members_overview_alpha_sort));
@@ -3760,8 +3757,8 @@ ScriptEditor::ScriptEditor() {
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);
+ ED_SHORTCUT("script_editor/next_script", TTR("Next Script"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::PERIOD);
+ ED_SHORTCUT("script_editor/prev_script", TTR("Previous Script"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::COMMA);
set_process_input(true);
set_process_shortcut_input(true);
@@ -3771,10 +3768,10 @@ ScriptEditor::ScriptEditor() {
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..."), 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/new", TTR("New Script..."), KeyModifierMask::CMD_OR_CTRL | Key::N), FILE_NEW);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File..."), KeyModifierMask::CMD_OR_CTRL | 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"), KeyModifierMask::CMD | KeyModifierMask::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_OR_CTRL | 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);
@@ -3784,11 +3781,11 @@ ScriptEditor::ScriptEditor() {
_update_recent_scripts();
file_menu->get_popup()->add_separator();
- 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", TTR("Save"), KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL | 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"), 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 Tool Script"), KeyModifierMask::CMD | KeyModifierMask::ALT | Key::R), FILE_TOOL_RELOAD_SOFT);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Tool Script"), KeyModifierMask::CMD_OR_CTRL | 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();
@@ -3811,16 +3808,16 @@ ScriptEditor::ScriptEditor() {
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"), KeyModifierMask::CMD | Key::W), FILE_CLOSE);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KeyModifierMask::CMD_OR_CTRL | 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"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::X), FILE_RUN);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/run_file", TTR("Run"), KeyModifierMask::CMD_OR_CTRL | 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"), KeyModifierMask::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_OR_CTRL | 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));
@@ -3861,14 +3858,14 @@ ScriptEditor::ScriptEditor() {
site_search->set_text(TTR("Online Docs"));
site_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_WEBSITE));
menu_hb->add_child(site_search);
- site_search->set_tooltip(TTR("Open Godot online documentation."));
+ site_search->set_tooltip_text(TTR("Open Godot online documentation."));
help_search = memnew(Button);
help_search->set_flat(true);
help_search->set_text(TTR("Search Help"));
help_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_HELP));
menu_hb->add_child(help_search);
- help_search->set_tooltip(TTR("Search the reference documentation."));
+ help_search->set_tooltip_text(TTR("Search the reference documentation."));
menu_hb->add_child(memnew(VSeparator));
@@ -3877,14 +3874,14 @@ ScriptEditor::ScriptEditor() {
script_back->connect("pressed", callable_mp(this, &ScriptEditor::_history_back));
menu_hb->add_child(script_back);
script_back->set_disabled(true);
- script_back->set_tooltip(TTR("Go to previous edited document."));
+ script_back->set_tooltip_text(TTR("Go to previous edited document."));
script_forward = memnew(Button);
script_forward->set_flat(true);
script_forward->connect("pressed", callable_mp(this, &ScriptEditor::_history_forward));
menu_hb->add_child(script_forward);
script_forward->set_disabled(true);
- script_forward->set_tooltip(TTR("Go to next edited document."));
+ script_forward->set_tooltip_text(TTR("Go to next edited document."));
tab_container->connect("tab_changed", callable_mp(this, &ScriptEditor::_tab_changed));
@@ -3921,7 +3918,7 @@ ScriptEditor::ScriptEditor() {
vbc->add_child(disk_changed_list);
disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
- disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::_reload_scripts));
+ disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts));
disk_changed->set_ok_button_text(TTR("Reload"));
disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
@@ -4052,7 +4049,7 @@ void ScriptEditorPlugin::edited_scene_changed() {
ScriptEditorPlugin::ScriptEditorPlugin() {
script_editor = memnew(ScriptEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(script_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(script_editor);
script_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
script_editor->hide();
@@ -4073,7 +4070,7 @@ ScriptEditorPlugin::ScriptEditorPlugin() {
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"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::T);
+ ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD_OR_CTRL | 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 9f088aac49..a8e6cc6868 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -59,11 +59,11 @@ protected:
static void _bind_methods();
GDVIRTUAL0RC(String, _get_name)
- GDVIRTUAL0RC(Array, _get_supported_languages)
+ GDVIRTUAL0RC(PackedStringArray, _get_supported_languages)
public:
virtual String _get_name() const;
- virtual Array _get_supported_languages() const;
+ virtual PackedStringArray _get_supported_languages() const;
void _set_edited_resource(const Ref<Resource> &p_res) { edited_resourse = p_res; }
Ref<RefCounted> _get_edited_resource() { return edited_resourse; }
@@ -156,7 +156,7 @@ public:
virtual void ensure_focus() = 0;
virtual void tag_saved_version() = 0;
virtual void reload(bool p_soft) {}
- virtual Array get_breakpoints() = 0;
+ virtual PackedInt32Array get_breakpoints() = 0;
virtual void set_breakpoint(int p_line, bool p_enabled) = 0;
virtual void clear_breakpoints() = 0;
virtual void add_callback(const String &p_function, PackedStringArray p_args) = 0;
@@ -327,7 +327,6 @@ class ScriptEditor : public PanelContainer {
String _get_debug_tooltip(const String &p_text, Node *_se);
void _resave_scripts(const String &p_str);
- void _reload_scripts();
bool _test_script_times_on_disk(Ref<Resource> p_for_script = Ref<Resource>());
@@ -386,7 +385,7 @@ class ScriptEditor : public PanelContainer {
Array _get_cached_breakpoints_for_script(const String &p_path) const;
ScriptEditorBase *_get_current_editor() const;
- Array _get_open_script_editors() const;
+ TypedArray<ScriptEditorBase> _get_open_script_editors() const;
Ref<ConfigFile> script_editor_cache;
void _save_editor_state(ScriptEditorBase *p_editor);
@@ -452,7 +451,7 @@ class ScriptEditor : public PanelContainer {
void _file_dialog_action(String p_file);
Ref<Script> _get_current_script();
- Array _get_open_scripts() const;
+ TypedArray<Script> _get_open_scripts() const;
HashSet<String> textfile_extensions;
Ref<TextFile> _load_text_file(const String &p_path, Error *r_error) const;
@@ -478,6 +477,7 @@ public:
bool toggle_scripts_panel();
bool is_scripts_panel_toggled();
void apply_scripts() const;
+ void reload_scripts();
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 = "");
Ref<Resource> open_file(const String &p_file);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 5d5f452390..42dcfb8b1f 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -340,7 +340,9 @@ void ScriptTextEditor::set_edit_state(const Variant &p_state) {
}
if (editor_enabled) {
+#ifndef ANDROID_ENABLED
ensure_focus();
+#endif
}
}
@@ -596,7 +598,7 @@ void ScriptTextEditor::_update_bookmark_list() {
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV);
- Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
+ PackedInt32Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
if (bookmark_list.size() == 0) {
return;
}
@@ -751,7 +753,7 @@ void ScriptTextEditor::_update_breakpoint_list() {
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT);
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT);
- Array breakpoint_list = code_editor->get_text_editor()->get_breakpointed_lines();
+ PackedInt32Array breakpoint_list = code_editor->get_text_editor()->get_breakpointed_lines();
if (breakpoint_list.size() == 0) {
return;
}
@@ -942,7 +944,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
String ScriptTextEditor::_get_absolute_path(const String &rel_path) {
String base_path = script->get_path().get_base_dir();
- String path = base_path.plus_file(rel_path);
+ String path = base_path.path_join(rel_path);
return path.replace("///", "//").simplify_path();
}
@@ -1124,15 +1126,15 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case EDIT_TOGGLE_FOLD_LINE: {
tx->toggle_foldable_line(tx->get_caret_line());
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_FOLD_ALL_LINES: {
tx->fold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_UNFOLD_ALL_LINES: {
tx->unfold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_TOGGLE_COMMENT: {
_edit_option_toggle_inline_comment();
@@ -1264,7 +1266,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak);
} break;
case DEBUG_REMOVE_ALL_BREAKPOINTS: {
- Array bpoints = tx->get_breakpointed_lines();
+ PackedInt32Array bpoints = tx->get_breakpointed_lines();
for (int i = 0; i < bpoints.size(); i++) {
int line = bpoints[i];
@@ -1274,7 +1276,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
}
} break;
case DEBUG_GOTO_NEXT_BREAKPOINT: {
- Array bpoints = tx->get_breakpointed_lines();
+ PackedInt32Array bpoints = tx->get_breakpointed_lines();
if (bpoints.size() <= 0) {
return;
}
@@ -1300,7 +1302,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case DEBUG_GOTO_PREV_BREAKPOINT: {
- Array bpoints = tx->get_breakpointed_lines();
+ PackedInt32Array bpoints = tx->get_breakpointed_lines();
if (bpoints.size() <= 0) {
return;
}
@@ -1441,7 +1443,7 @@ void ScriptTextEditor::reload(bool p_soft) {
scr->get_language()->reload_tool_script(scr, soft);
}
-Array ScriptTextEditor::get_breakpoints() {
+PackedInt32Array ScriptTextEditor::get_breakpoints() {
return code_editor->get_text_editor()->get_breakpointed_lines();
}
@@ -1590,7 +1592,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
}
- String variable_name = String(node->get_name()).camelcase_to_underscore(true).validate_identifier();
+ String variable_name = String(node->get_name()).to_snake_case().validate_identifier();
if (use_type) {
text_to_drop += vformat("@onready var %s: %s = %s%s\n", variable_name, node->get_class_name(), is_unique ? "%" : "$", path);
} else {
@@ -1760,7 +1762,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) {
code_editor->get_text_editor()->begin_complex_operation();
code_editor->get_text_editor()->set_line(color_position.x, line_with_replaced_args);
code_editor->get_text_editor()->end_complex_operation();
- code_editor->get_text_editor()->update();
+ code_editor->get_text_editor()->queue_redraw();
}
void ScriptTextEditor::_prepare_edit_menu() {
@@ -2070,58 +2072,58 @@ static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
void ScriptTextEditor::register_editor() {
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);
+ ED_SHORTCUT("script_text_editor/delete_line", TTR("Delete Line"), KeyModifierMask::CMD_OR_CTRL | 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"), KeyModifierMask::CMD | Key::K);
+ ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KeyModifierMask::CMD_OR_CTRL | 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("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::SHIFT | KeyModifierMask::CTRL | Key::D);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/duplicate_selection", "macos", KeyModifierMask::SHIFT | KeyModifierMask::META | Key::C);
+ ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::E);
+ ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T);
+ ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::Y);
+ ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::I);
+ ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KeyModifierMask::CMD_OR_CTRL | Key::I);
- ED_SHORTCUT_AND_COMMAND("script_text_editor/find", TTR("Find..."), KeyModifierMask::CMD | Key::F);
+ ED_SHORTCUT_AND_COMMAND("script_text_editor/find", TTR("Find..."), KeyModifierMask::CMD_OR_CTRL | Key::F);
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_OVERRIDE("script_text_editor/find_next", "macos", KeyModifierMask::META | 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_OVERRIDE("script_text_editor/find_previous", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::G);
- 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_AND_COMMAND("script_text_editor/replace", TTR("Replace..."), KeyModifierMask::CTRL | Key::R);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/replace", "macos", KeyModifierMask::ALT | KeyModifierMask::META | Key::F);
- 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/find_in_files", TTR("Find in Files..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F);
+ ED_SHORTCUT("script_text_editor/replace_in_files", TTR("Replace in Files..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::R);
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"), 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/toggle_bookmark", TTR("Toggle Bookmark"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::B);
+ ED_SHORTCUT("script_text_editor/goto_next_bookmark", TTR("Go to Next Bookmark"), KeyModifierMask::CMD_OR_CTRL | Key::B);
+ ED_SHORTCUT("script_text_editor/goto_previous_bookmark", TTR("Go to Previous Bookmark"), KeyModifierMask::CMD_OR_CTRL | 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..."), 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_function", TTR("Go to Function..."), KeyModifierMask::ALT | KeyModifierMask::CTRL | Key::F);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/goto_function", "macos", KeyModifierMask::CTRL | KeyModifierMask::META | Key::J);
- ED_SHORTCUT("script_text_editor/goto_line", TTR("Go to Line..."), KeyModifierMask::CMD | Key::L);
+ ED_SHORTCUT("script_text_editor/goto_line", TTR("Go to Line..."), KeyModifierMask::CMD_OR_CTRL | Key::L);
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_OVERRIDE("script_text_editor/toggle_breakpoint", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::B);
- 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);
+ ED_SHORTCUT("script_text_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F9);
+ ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Go to Next Breakpoint"), KeyModifierMask::CMD_OR_CTRL | Key::PERIOD);
+ ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Go to Previous Breakpoint"), KeyModifierMask::CMD_OR_CTRL | 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 fc87c84a2c..8d2fb98721 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -229,7 +229,7 @@ public:
virtual void clear_executing_line() override;
virtual void reload(bool p_soft) override;
- virtual Array get_breakpoints() override;
+ virtual PackedInt32Array get_breakpoints() override;
virtual void set_breakpoint(int p_line, bool p_enabled) override;
virtual void clear_breakpoints() override;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index e700412188..246bc4b183 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -47,6 +47,50 @@
#include "servers/rendering/shader_preprocessor.h"
#include "servers/rendering/shader_types.h"
+/*** SHADER SYNTAX HIGHLIGHTER ****/
+
+Dictionary GDShaderSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
+ Dictionary color_map;
+
+ for (const Point2i &region : disabled_branch_regions) {
+ if (p_line >= region.x && p_line <= region.y) {
+ Dictionary highlighter_info;
+ highlighter_info["color"] = disabled_branch_color;
+
+ color_map[0] = highlighter_info;
+ return color_map;
+ }
+ }
+
+ return CodeHighlighter::_get_line_syntax_highlighting_impl(p_line);
+}
+
+void GDShaderSyntaxHighlighter::add_disabled_branch_region(const Point2i &p_region) {
+ ERR_FAIL_COND(p_region.x < 0);
+ ERR_FAIL_COND(p_region.y < 0);
+
+ for (int i = 0; i < disabled_branch_regions.size(); i++) {
+ ERR_FAIL_COND_MSG(disabled_branch_regions[i].x == p_region.x, "Branch region with a start line '" + itos(p_region.x) + "' already exists.");
+ }
+
+ Point2i disabled_branch_region;
+ disabled_branch_region.x = p_region.x;
+ disabled_branch_region.y = p_region.y;
+ disabled_branch_regions.push_back(disabled_branch_region);
+
+ clear_highlighting_cache();
+}
+
+void GDShaderSyntaxHighlighter::clear_disabled_branch_regions() {
+ disabled_branch_regions.clear();
+ clear_highlighting_cache();
+}
+
+void GDShaderSyntaxHighlighter::set_disabled_branch_color(const Color &p_color) {
+ disabled_branch_color = p_color;
+ clear_highlighting_cache();
+}
+
/*** SHADER SCRIPT EDITOR ****/
static bool saved_warnings_enabled = false;
@@ -134,6 +178,7 @@ void ShaderTextEditor::set_edited_code(const String &p_code) {
get_text_editor()->clear_undo_history();
get_text_editor()->call_deferred(SNAME("set_h_scroll"), 0);
get_text_editor()->call_deferred(SNAME("set_v_scroll"), 0);
+ get_text_editor()->tag_saved_version();
_validate_script();
_line_col_changed();
@@ -263,6 +308,7 @@ void ShaderTextEditor::_load_theme_settings() {
syntax_highlighter->clear_color_regions();
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, true);
+ syntax_highlighter->set_disabled_branch_color(comment_color);
text_editor->clear_comment_delimiters();
text_editor->add_comment_delimiter("/*", "*/", false);
@@ -309,7 +355,7 @@ void ShaderTextEditor::_check_shader_mode() {
}
static ShaderLanguage::DataType _get_global_shader_uniform_type(const StringName &p_variable) {
- RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(p_variable);
+ RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_variable);
return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);
}
@@ -345,7 +391,7 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa
if (!complete_from_path.ends_with("/")) {
complete_from_path += "/";
}
- preprocessor.preprocess(p_code, code, nullptr, nullptr, nullptr, &pp_options, _complete_include_paths);
+ preprocessor.preprocess(p_code, "", code, nullptr, nullptr, nullptr, nullptr, &pp_options, _complete_include_paths);
complete_from_path = String();
if (pp_options.size()) {
for (const ScriptLanguage::CodeCompletionOption &E : pp_options) {
@@ -391,11 +437,29 @@ void ShaderTextEditor::_validate_script() {
String code_pp;
String error_pp;
List<ShaderPreprocessor::FilePosition> err_positions;
- last_compile_result = preprocessor.preprocess(code, code_pp, &error_pp, &err_positions);
+ List<ShaderPreprocessor::Region> regions;
+ String filename;
+ if (shader.is_valid()) {
+ filename = shader->get_path();
+ } else if (shader_inc.is_valid()) {
+ filename = shader_inc->get_path();
+ }
+ last_compile_result = preprocessor.preprocess(code, filename, code_pp, &error_pp, &err_positions, &regions);
for (int i = 0; i < get_text_editor()->get_line_count(); i++) {
get_text_editor()->set_line_background_color(i, Color(0, 0, 0, 0));
}
+
+ syntax_highlighter->clear_disabled_branch_regions();
+ for (const ShaderPreprocessor::Region &region : regions) {
+ if (!region.enabled) {
+ if (filename != region.file) {
+ continue;
+ }
+ syntax_highlighter->add_disabled_branch_region(Point2i(region.from_line, region.to_line));
+ }
+ }
+
set_error("");
set_error_count(0);
@@ -843,6 +907,7 @@ void ShaderEditor::save_external_data(const String &p_str) {
if (shader_inc.is_valid() && shader_inc != edited_shader_inc) {
ResourceSaver::save(shader_inc);
}
+ shader_editor->get_text_editor()->tag_saved_version();
disk_changed->hide();
}
@@ -851,6 +916,10 @@ void ShaderEditor::validate_script() {
shader_editor->_validate_script();
}
+bool ShaderEditor::is_unsaved() const {
+ return shader_editor->get_text_editor()->get_saved_version() != shader_editor->get_text_editor()->get_version();
+}
+
void ShaderEditor::apply_shaders() {
String editor_code = shader_editor->get_text_editor()->get_text();
if (shader.is_valid()) {
@@ -925,7 +994,7 @@ void ShaderEditor::_update_bookmark_list() {
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV);
- Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines();
+ PackedInt32Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines();
if (bookmark_list.size() == 0) {
return;
}
@@ -1127,36 +1196,34 @@ ShaderEditor::ShaderEditor() {
void ShaderEditorPlugin::_update_shader_list() {
shader_list->clear();
for (uint32_t i = 0; i < edited_shaders.size(); i++) {
- String text;
- String path;
- String _class;
- String shader_name;
- if (edited_shaders[i].shader.is_valid()) {
- Ref<Shader> shader = edited_shaders[i].shader;
-
- path = shader->get_path();
- _class = shader->get_class();
- shader_name = shader->get_name();
- } else {
- Ref<ShaderInclude> shader_inc = edited_shaders[i].shader_inc;
-
- path = shader_inc->get_path();
- _class = shader_inc->get_class();
- shader_name = shader_inc->get_name();
+ Ref<Resource> shader = edited_shaders[i].shader;
+ if (shader.is_null()) {
+ shader = edited_shaders[i].shader_inc;
}
- if (path.is_resource_file()) {
- text = path.get_file();
- } else if (shader_name != "") {
- text = shader_name;
- } else {
- if (edited_shaders[i].shader.is_valid()) {
- text = _class + ":" + itos(edited_shaders[i].shader->get_instance_id());
- } else {
- text = _class + ":" + itos(edited_shaders[i].shader_inc->get_instance_id());
+ String path = shader->get_path();
+ String text = path.get_file();
+ if (text.is_empty()) {
+ // This appears for newly created built-in shaders before saving the scene.
+ text = TTR("[unsaved]");
+ } else if (shader->is_built_in()) {
+ const String &shader_name = shader->get_name();
+ if (!shader_name.is_empty()) {
+ text = vformat("%s (%s)", shader_name, text.get_slice("::", 0));
}
}
+ bool unsaved = false;
+ if (edited_shaders[i].shader_editor) {
+ unsaved = edited_shaders[i].shader_editor->is_unsaved();
+ }
+ // TODO: Handle visual shaders too.
+
+ if (unsaved) {
+ text += "(*)";
+ }
+
+ String _class = shader->get_class();
if (!shader_list->has_theme_icon(_class, SNAME("EditorIcons"))) {
_class = "TextFile";
}
@@ -1190,6 +1257,17 @@ void ShaderEditorPlugin::_update_shader_list_status() {
}
}
+void ShaderEditorPlugin::_move_shader_tab(int p_from, int p_to) {
+ if (p_from == p_to) {
+ return;
+ }
+ EditedShader es = edited_shaders[p_from];
+ edited_shaders.remove_at(p_from);
+ edited_shaders.insert(p_to, es);
+ shader_tabs->move_child(shader_tabs->get_tab_control(p_from), p_to);
+ _update_shader_list();
+}
+
void ShaderEditorPlugin::edit(Object *p_object) {
EditedShader es;
@@ -1206,7 +1284,7 @@ void ShaderEditorPlugin::edit(Object *p_object) {
es.shader_editor = memnew(ShaderEditor);
es.shader_editor->edit(si);
shader_tabs->add_child(es.shader_editor);
- es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list_status));
+ es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list));
} else {
Shader *s = Object::cast_to<Shader>(p_object);
for (uint32_t i = 0; i < edited_shaders.size(); i++) {
@@ -1226,7 +1304,7 @@ void ShaderEditorPlugin::edit(Object *p_object) {
es.shader_editor = memnew(ShaderEditor);
shader_tabs->add_child(es.shader_editor);
es.shader_editor->edit(s);
- es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list_status));
+ es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list));
}
}
@@ -1272,6 +1350,7 @@ void ShaderEditorPlugin::save_external_data() {
edited_shaders[i].shader_editor->save_external_data();
}
}
+ _update_shader_list();
}
void ShaderEditorPlugin::apply_changes() {
@@ -1289,6 +1368,12 @@ void ShaderEditorPlugin::_shader_selected(int p_index) {
shader_tabs->set_current_tab(p_index);
}
+void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
+ if (p_mouse_button_index == MouseButton::MIDDLE) {
+ _close_shader(p_item);
+ }
+}
+
void ShaderEditorPlugin::_close_shader(int p_index) {
int index = shader_tabs->get_current_tab();
ERR_FAIL_INDEX(index, shader_tabs->get_tab_count());
@@ -1313,12 +1398,12 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
switch (p_index) {
case FILE_NEW: {
String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir();
- shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 0);
+ shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 0);
shader_create_dialog->popup_centered();
} break;
case FILE_NEW_INCLUDE: {
String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir();
- shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 2);
+ shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 2);
shader_create_dialog->popup_centered();
} break;
case FILE_OPEN: {
@@ -1377,6 +1462,109 @@ void ShaderEditorPlugin::_shader_include_created(Ref<ShaderInclude> p_shader_inc
EditorNode::get_singleton()->push_item(p_shader_inc.ptr());
}
+Variant ShaderEditorPlugin::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (shader_list->get_item_count() == 0) {
+ return Variant();
+ }
+
+ int idx = shader_list->get_item_at_position(p_point);
+ if (idx < 0) {
+ return Variant();
+ }
+
+ HBoxContainer *drag_preview = memnew(HBoxContainer);
+ String preview_name = shader_list->get_item_text(idx);
+ Ref<Texture2D> preview_icon = shader_list->get_item_icon(idx);
+
+ 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));
+ drag_preview->add_child(label);
+ main_split->set_drag_preview(drag_preview);
+
+ Dictionary drag_data;
+ drag_data["type"] = "shader_list_element";
+ drag_data["shader_list_element"] = idx;
+
+ return drag_data;
+}
+
+bool ShaderEditorPlugin::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ Dictionary d = p_data;
+ if (!d.has("type")) {
+ return false;
+ }
+
+ if (String(d["type"]) == "shader_list_element") {
+ return true;
+ }
+
+ if (String(d["type"]) == "files") {
+ Vector<String> files = d["files"];
+
+ if (files.size() == 0) {
+ return false;
+ }
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ if (ResourceLoader::exists(file, "Shader")) {
+ Ref<Shader> shader = ResourceLoader::load(file);
+ if (shader.is_valid()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ return false;
+}
+
+void ShaderEditorPlugin::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ if (!can_drop_data_fw(p_point, p_data, p_from)) {
+ return;
+ }
+
+ Dictionary d = p_data;
+ if (!d.has("type")) {
+ return;
+ }
+
+ if (String(d["type"]) == "shader_list_element") {
+ int idx = d["shader_list_element"];
+ int new_idx = shader_list->get_item_at_position(p_point);
+ _move_shader_tab(idx, new_idx);
+ return;
+ }
+
+ if (String(d["type"]) == "files") {
+ Vector<String> files = d["files"];
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ if (!ResourceLoader::exists(file, "Shader")) {
+ continue;
+ }
+
+ Ref<Resource> res = ResourceLoader::load(file);
+ if (res.is_valid()) {
+ edit(res.ptr());
+ }
+ }
+ }
+}
+
+void ShaderEditorPlugin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ShaderEditorPlugin::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::drop_data_fw);
+}
+
ShaderEditorPlugin::ShaderEditorPlugin() {
main_split = memnew(HSplitContainer);
@@ -1408,6 +1596,8 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
shader_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vb->add_child(shader_list);
shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected));
+ shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked));
+ shader_list->set_drag_forwarding(this);
main_split->add_child(vb);
vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE);
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 907de6ea87..afd38ef71a 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -48,6 +48,21 @@ class VisualShaderEditor;
class HSplitContainer;
class ShaderCreateDialog;
+class GDShaderSyntaxHighlighter : public CodeHighlighter {
+ GDCLASS(GDShaderSyntaxHighlighter, CodeHighlighter)
+
+private:
+ Vector<Point2i> disabled_branch_regions;
+ Color disabled_branch_color;
+
+public:
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override;
+
+ void add_disabled_branch_region(const Point2i &p_region);
+ void clear_disabled_branch_regions();
+ void set_disabled_branch_color(const Color &p_color);
+};
+
class ShaderTextEditor : public CodeTextEditor {
GDCLASS(ShaderTextEditor, CodeTextEditor);
@@ -57,7 +72,7 @@ class ShaderTextEditor : public CodeTextEditor {
_ALWAYS_INLINE_ bool operator()(const ShaderWarning &p_a, const ShaderWarning &p_b) const { return (p_a.get_line() < p_b.get_line()); }
};
- Ref<CodeHighlighter> syntax_highlighter;
+ Ref<GDShaderSyntaxHighlighter> syntax_highlighter;
RichTextLabel *warnings_panel = nullptr;
Ref<Shader> shader;
Ref<ShaderInclude> shader_inc;
@@ -185,6 +200,7 @@ public:
void goto_line_selection(int p_line, int p_begin, int p_end);
void save_external_data(const String &p_str = "");
void validate_script();
+ bool is_unsaved() const;
virtual Size2 get_minimum_size() const override { return Size2(0, 200); }
@@ -226,6 +242,7 @@ class ShaderEditorPlugin : public EditorPlugin {
void _update_shader_list();
void _shader_selected(int p_index);
+ void _shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index);
void _menu_item_pressed(int p_index);
void _resource_saved(Object *obj);
void _close_shader(int p_index);
@@ -233,10 +250,16 @@ class ShaderEditorPlugin : public EditorPlugin {
void _shader_created(Ref<Shader> p_shader);
void _shader_include_created(Ref<ShaderInclude> p_shader_inc);
void _update_shader_list_status();
+ void _move_shader_tab(int p_from, int p_to);
+
+ 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);
+
+protected:
+ static void _bind_methods();
public:
- virtual String get_name() const override { return "Shader"; }
- 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;
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index 5a1505c232..dbad81d743 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/gui/box_container.h"
#include "thirdparty/misc/clipper.hpp"
@@ -59,7 +60,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
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);
@@ -75,7 +76,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
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);
@@ -130,7 +131,7 @@ void Skeleton2DEditorPlugin::make_visible(bool p_visible) {
Skeleton2DEditorPlugin::Skeleton2DEditorPlugin() {
sprite_editor = memnew(Skeleton2DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(sprite_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(sprite_editor);
make_visible(false);
//sprite_editor->options->hide();
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index c453ed26aa..3c75ac6ca6 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -31,10 +31,10 @@
#include "skeleton_3d_editor_plugin.h"
#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/editor_undo_redo_manager.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/collision_shape_3d.h"
@@ -182,27 +182,27 @@ void BoneTransformEditor::_update_properties() {
if (split[2] == "enabled") {
enabled_checkbox->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
enabled_checkbox->update_property();
- enabled_checkbox->update();
+ enabled_checkbox->queue_redraw();
}
if (split[2] == "position") {
position_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
position_property->update_property();
- position_property->update();
+ position_property->queue_redraw();
}
if (split[2] == "rotation") {
rotation_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
rotation_property->update_property();
- rotation_property->update();
+ rotation_property->queue_redraw();
}
if (split[2] == "scale") {
scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
scale_property->update_property();
- scale_property->update();
+ scale_property->queue_redraw();
}
if (split[2] == "rest") {
rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
rest_matrix->update_property();
- rest_matrix->update();
+ rest_matrix->queue_redraw();
}
}
}
@@ -221,7 +221,7 @@ void Skeleton3DEditor::set_keyable(const bool p_keyable) {
};
void Skeleton3DEditor::set_bone_options_enabled(const bool p_bone_options_enabled) {
- skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INIT_SELECTED_POSES, !p_bone_options_enabled);
+ skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_RESET_SELECTED_POSES, !p_bone_options_enabled);
skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled);
};
@@ -231,12 +231,12 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
}
switch (p_skeleton_option) {
- case SKELETON_OPTION_INIT_ALL_POSES: {
- init_pose(true);
+ case SKELETON_OPTION_RESET_ALL_POSES: {
+ reset_pose(true);
break;
}
- case SKELETON_OPTION_INIT_SELECTED_POSES: {
- init_pose(false);
+ case SKELETON_OPTION_RESET_SELECTED_POSES: {
+ reset_pose(false);
break;
}
case SKELETON_OPTION_ALL_POSES_TO_RESTS: {
@@ -258,7 +258,7 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
}
}
-void Skeleton3DEditor::init_pose(const bool p_all_bones) {
+void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
if (!skeleton) {
return;
}
@@ -267,31 +267,25 @@ void Skeleton3DEditor::init_pose(const bool p_all_bones) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
- Transform3D rest = skeleton->get_bone_rest(i);
- ur->add_do_method(skeleton, "set_bone_pose_position", i, rest.origin);
- ur->add_do_method(skeleton, "set_bone_pose_rotation", i, rest.basis.get_rotation_quaternion());
- ur->add_do_method(skeleton, "set_bone_pose_scale", i, rest.basis.get_scale());
ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i));
ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i));
ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i));
}
+ ur->add_do_method(skeleton, "reset_bone_poses");
} else {
// Todo: Do method with multiple bone selection.
if (selected_bone == -1) {
ur->commit_action();
return;
}
- Transform3D rest = skeleton->get_bone_rest(selected_bone);
- ur->add_do_method(skeleton, "set_bone_pose_position", selected_bone, rest.origin);
- ur->add_do_method(skeleton, "set_bone_pose_rotation", selected_bone, rest.basis.get_rotation_quaternion());
- ur->add_do_method(skeleton, "set_bone_pose_scale", selected_bone, rest.basis.get_scale());
ur->add_undo_method(skeleton, "set_bone_pose_position", selected_bone, skeleton->get_bone_pose_position(selected_bone));
ur->add_undo_method(skeleton, "set_bone_pose_rotation", selected_bone, skeleton->get_bone_pose_rotation(selected_bone));
ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone));
+ ur->add_do_method(skeleton, "reset_bone_pose", selected_bone);
}
ur->commit_action();
}
@@ -340,7 +334,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
@@ -360,7 +354,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
}
void Skeleton3DEditor::create_physical_skeleton() {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ERR_FAIL_COND(!get_tree());
Node *owner = get_tree()->get_edited_scene_root();
@@ -432,12 +426,14 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
bone_shape->set_name("CollisionShape3D");
Transform3D capsule_transform;
- capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0));
+ capsule_transform.basis.rows[0] = Vector3(1, 0, 0);
+ capsule_transform.basis.rows[1] = Vector3(0, 0, 1);
+ capsule_transform.basis.rows[2] = 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())) {
+ if (up.cross(child_rest.origin).is_zero_approx()) {
up = Vector3(0, 0, 1);
}
@@ -593,7 +589,7 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se
Node *node = get_node_or_null(p_skeleton_path);
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
ERR_FAIL_NULL(skeleton);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Parentage"));
// If the target is a child of ourselves, we move only *us* and not our children.
if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
@@ -696,8 +692,6 @@ void Skeleton3DEditor::update_editors() {
void Skeleton3DEditor::create_editors() {
set_h_size_flags(SIZE_EXPAND_FILL);
- add_theme_constant_override("separation", 0);
-
set_focus_mode(FOCUS_ALL);
Node3DEditor *ne = Node3DEditor::get_singleton();
@@ -717,12 +711,11 @@ void Skeleton3DEditor::create_editors() {
ne->add_control_to_menu_panel(skeleton_options);
skeleton_options->set_text(TTR("Skeleton3D"));
- skeleton_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Skeleton3D"), SNAME("EditorIcons")));
// Skeleton options.
PopupMenu *p = skeleton_options->get_popup();
- p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_all_poses", TTR("Init all Poses")), SKELETON_OPTION_INIT_ALL_POSES);
- p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_selected_poses", TTR("Init selected Poses")), SKELETON_OPTION_INIT_SELECTED_POSES);
+ p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_all_poses", TTR("Reset all bone Poses")), SKELETON_OPTION_RESET_ALL_POSES);
+ p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_selected_poses", TTR("Reset selected Poses")), SKELETON_OPTION_RESET_SELECTED_POSES);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply all poses to rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply selected poses to rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS);
p->add_item(TTR("Create physical skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON);
@@ -739,7 +732,7 @@ void Skeleton3DEditor::create_editors() {
edit_mode_button->set_flat(true);
edit_mode_button->set_toggle_mode(true);
edit_mode_button->set_focus_mode(FOCUS_NONE);
- edit_mode_button->set_tooltip(TTR("Edit Mode\nShow buttons on joints."));
+ edit_mode_button->set_tooltip_text(TTR("Edit Mode\nShow buttons on joints."));
edit_mode_button->connect("toggled", callable_mp(this, &Skeleton3DEditor::edit_mode_toggled));
edit_mode = false;
@@ -760,7 +753,7 @@ void Skeleton3DEditor::create_editors() {
key_loc_button->set_toggle_mode(true);
key_loc_button->set_pressed(false);
key_loc_button->set_focus_mode(FOCUS_NONE);
- key_loc_button->set_tooltip(TTR("Translation mask for inserting keys."));
+ key_loc_button->set_tooltip_text(TTR("Translation mask for inserting keys."));
animation_hb->add_child(key_loc_button);
key_rot_button = memnew(Button);
@@ -768,7 +761,7 @@ void Skeleton3DEditor::create_editors() {
key_rot_button->set_toggle_mode(true);
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
- key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys."));
+ key_rot_button->set_tooltip_text(TTR("Rotation mask for inserting keys."));
animation_hb->add_child(key_rot_button);
key_scale_button = memnew(Button);
@@ -776,14 +769,14 @@ void Skeleton3DEditor::create_editors() {
key_scale_button->set_toggle_mode(true);
key_scale_button->set_pressed(false);
key_scale_button->set_focus_mode(FOCUS_NONE);
- key_scale_button->set_tooltip(TTR("Scale mask for inserting keys."));
+ key_scale_button->set_tooltip_text(TTR("Scale mask for inserting keys."));
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys).bind(false));
- key_insert_button->set_tooltip(TTR("Insert key of bone poses already exist track."));
+ key_insert_button->set_tooltip_text(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));
animation_hb->add_child(key_insert_button);
@@ -791,8 +784,8 @@ void Skeleton3DEditor::create_editors() {
key_insert_all_button->set_flat(true);
key_insert_all_button->set_focus_mode(FOCUS_NONE);
key_insert_all_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys).bind(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)"), KeyModifierMask::CMD + Key::INSERT));
+ key_insert_all_button->set_tooltip_text(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)"), KeyModifierMask::CMD_OR_CTRL + Key::INSERT));
animation_hb->add_child(key_insert_all_button);
// Bone tree.
@@ -829,20 +822,10 @@ void Skeleton3DEditor::create_editors() {
void Skeleton3DEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), 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_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons")));
- get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONESHOT);
- break;
- }
case NOTIFICATION_ENTER_TREE: {
- create_editors();
update_joint_tree();
update_editors();
+
joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed));
joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select));
#ifdef TOOLS_ENABLED
@@ -851,8 +834,38 @@ void Skeleton3DEditor::_notification(int p_what) {
skeleton->connect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
skeleton->connect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
#endif
- break;
- }
+
+ get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONE_SHOT);
+ } break;
+ case NOTIFICATION_READY: {
+ // Will trigger NOTIFICATION_THEME_CHANGED, but won't cause any loops if called here.
+ add_theme_constant_override("separation", 0);
+ } break;
+ case NOTIFICATION_THEME_CHANGED: {
+ skeleton_options->set_icon(get_theme_icon(SNAME("Skeleton3D"), SNAME("EditorIcons")));
+ edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), 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_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons")));
+
+ update_joint_tree();
+ } break;
+ case NOTIFICATION_PREDELETE: {
+ if (skeleton) {
+ select_bone(-1); // Requires that the joint_tree has not been deleted.
+#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));
+ skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
+ skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
+ skeleton->set_transform_gizmo_visible(true);
+#endif
+ handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance);
+ }
+ edit_mode_toggled(false);
+ } break;
}
}
@@ -921,13 +934,15 @@ void fragment() {
)");
handle_material->set_shader(handle_shader);
Ref<Texture2D> handle = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("EditorBoneHandle"), SNAME("EditorIcons"));
- handle_material->set_shader_uniform("point_size", handle->get_width());
- handle_material->set_shader_uniform("texture_albedo", handle);
+ handle_material->set_shader_parameter("point_size", handle->get_width());
+ handle_material->set_shader_parameter("texture_albedo", handle);
handles_mesh_instance = memnew(MeshInstance3D);
handles_mesh_instance->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
handles_mesh.instantiate();
handles_mesh_instance->set_mesh(handles_mesh);
+
+ create_editors();
}
void Skeleton3DEditor::update_bone_original() {
@@ -1065,18 +1080,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));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
- skeleton->disconnect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties));
- skeleton->set_transform_gizmo_visible(true);
-#endif
- handles_mesh_instance->get_parent()->remove_child(handles_mesh_instance);
- }
- edit_mode_toggled(false);
+ singleton = nullptr;
handles_mesh_instance->queue_delete();
@@ -1127,7 +1131,7 @@ Skeleton3DEditorPlugin::Skeleton3DEditorPlugin() {
EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
- if (se->is_edit_mode()) {
+ if (se && se->is_edit_mode()) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (ne->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) {
@@ -1315,7 +1319,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Transform"));
if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
for (int i = 0; i < p_ids.size(); i++) {
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 975b54fa77..9747ed8374 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef SKELETON_3D_EDITOR_PLUGIN_H
#define SKELETON_3D_EDITOR_PLUGIN_H
+#include "editor/editor_file_dialog.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
#include "node_3d_editor_plugin.h"
@@ -40,6 +41,7 @@
#include "scene/resources/immediate_mesh.h"
class EditorInspectorPluginSkeleton;
+class EditorUndoRedoManager;
class Joint;
class PhysicalBone3D;
class Skeleton3DEditorPlugin;
@@ -63,7 +65,7 @@ class BoneTransformEditor : public VBoxContainer {
Skeleton3D *skeleton = nullptr;
// String property;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool toggle_enabled = false;
bool updating = false;
@@ -96,8 +98,8 @@ class Skeleton3DEditor : public VBoxContainer {
friend class Skeleton3DEditorPlugin;
enum SkeletonOption {
- SKELETON_OPTION_INIT_ALL_POSES,
- SKELETON_OPTION_INIT_SELECTED_POSES,
+ SKELETON_OPTION_RESET_ALL_POSES,
+ SKELETON_OPTION_RESET_SELECTED_POSES,
SKELETON_OPTION_ALL_POSES_TO_RESTS,
SKELETON_OPTION_SELECTED_POSES_TO_RESTS,
SKELETON_OPTION_CREATE_PHYSICAL_SKELETON,
@@ -148,7 +150,7 @@ class Skeleton3DEditor : public VBoxContainer {
void create_editors();
- void init_pose(const bool p_all_bones);
+ void reset_pose(const bool p_all_bones);
void pose_to_rest(const bool p_all_bones);
void insert_keys(const bool p_all_bones);
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 7d350fd46f..b78b70cd5c 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -34,6 +34,7 @@
#include "core/math/geometry_2d.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/light_occluder_2d.h"
@@ -127,7 +128,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
case MENU_OPTION_CONVERT_TO_POLYGON_2D: {
@@ -136,7 +137,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
case MENU_OPTION_CREATE_COLLISION_POLY_2D: {
debug_uv_dialog->set_ok_button_text(TTR("Create CollisionPolygon2D"));
@@ -144,7 +145,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: {
@@ -153,7 +154,7 @@ void Sprite2DEditor::_menu_option(int p_option) {
_update_mesh_data();
debug_uv_dialog->popup_centered();
- debug_uv->update();
+ debug_uv->queue_redraw();
} break;
}
@@ -301,7 +302,7 @@ void Sprite2DEditor::_update_mesh_data() {
}
}
- debug_uv->update();
+ debug_uv->queue_redraw();
}
void Sprite2DEditor::_create_node() {
@@ -342,7 +343,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() {
MeshInstance2D *mesh_instance = memnew(MeshInstance2D);
mesh_instance->set_mesh(mesh);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
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);
@@ -400,7 +401,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() {
polygon_2d_instance->set_polygon(polygon);
polygon_2d_instance->set_polygons(polys);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Convert to Polygon2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, polygon_2d_instance, true, false);
ur->add_do_reference(polygon_2d_instance);
@@ -422,7 +423,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() {
CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
collision_polygon_2d_instance->set_polygon(outline);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Create CollisionPolygon2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance);
ur->add_do_reference(collision_polygon_2d_instance);
@@ -455,7 +456,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() {
LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
light_occluder_2d_instance->set_occluder_polygon(polygon);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Create LightOccluder2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance);
ur->add_do_reference(light_occluder_2d_instance);
@@ -603,7 +604,7 @@ void Sprite2DEditorPlugin::make_visible(bool p_visible) {
Sprite2DEditorPlugin::Sprite2DEditorPlugin() {
sprite_editor = memnew(Sprite2DEditor);
- EditorNode::get_singleton()->get_main_control()->add_child(sprite_editor);
+ EditorNode::get_singleton()->get_main_screen_control()->add_child(sprite_editor);
make_visible(false);
//sprite_editor->options->hide();
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index a39d24a167..ae21aad337 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "scene/3d/sprite_3d.h"
#include "scene/gui/center_container.h"
@@ -181,7 +182,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
if (last_frame_selected != idx || idx != -1) {
last_frame_selected = idx;
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
}
@@ -207,7 +208,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
}
last_frame_selected = idx;
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
}
}
@@ -306,7 +307,7 @@ void SpriteFramesEditor::_sheet_select_clear_all_frames() {
frames_selected.clear();
}
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) {
@@ -362,7 +363,7 @@ void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_para
frames_selected.clear();
last_frame_selected = -1;
- split_sheet_preview->update();
+ split_sheet_preview->queue_redraw();
}
void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
@@ -427,7 +428,7 @@ 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")));
- split_sheet_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ split_sheet_scroll->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_READY: {
@@ -1010,6 +1011,10 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
}
}
+void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
if (!frames->has_animation(edited_anim)) {
return false;
@@ -1156,13 +1161,13 @@ SpriteFramesEditor::SpriteFramesEditor() {
new_anim = memnew(Button);
new_anim->set_flat(true);
- new_anim->set_tooltip(TTR("New Animation"));
+ new_anim->set_tooltip_text(TTR("New Animation"));
hbc_animlist->add_child(new_anim);
new_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_add));
remove_anim = memnew(Button);
remove_anim->set_flat(true);
- remove_anim->set_tooltip(TTR("Remove Animation"));
+ remove_anim->set_tooltip_text(TTR("Remove Animation"));
hbc_animlist->add_child(remove_anim);
remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
@@ -1210,53 +1215,53 @@ SpriteFramesEditor::SpriteFramesEditor() {
load = memnew(Button);
load->set_flat(true);
- load->set_tooltip(TTR("Add a Texture from File"));
+ load->set_tooltip_text(TTR("Add a Texture from File"));
hbc->add_child(load);
load_sheet = memnew(Button);
load_sheet->set_flat(true);
- load_sheet->set_tooltip(TTR("Add Frames from a Sprite Sheet"));
+ load_sheet->set_tooltip_text(TTR("Add Frames from a Sprite Sheet"));
hbc->add_child(load_sheet);
hbc->add_child(memnew(VSeparator));
copy = memnew(Button);
copy->set_flat(true);
- copy->set_tooltip(TTR("Copy"));
+ copy->set_tooltip_text(TTR("Copy"));
hbc->add_child(copy);
paste = memnew(Button);
paste->set_flat(true);
- paste->set_tooltip(TTR("Paste"));
+ paste->set_tooltip_text(TTR("Paste"));
hbc->add_child(paste);
hbc->add_child(memnew(VSeparator));
empty = memnew(Button);
empty->set_flat(true);
- empty->set_tooltip(TTR("Insert Empty (Before)"));
+ empty->set_tooltip_text(TTR("Insert Empty (Before)"));
hbc->add_child(empty);
empty2 = memnew(Button);
empty2->set_flat(true);
- empty2->set_tooltip(TTR("Insert Empty (After)"));
+ empty2->set_tooltip_text(TTR("Insert Empty (After)"));
hbc->add_child(empty2);
hbc->add_child(memnew(VSeparator));
move_up = memnew(Button);
move_up->set_flat(true);
- move_up->set_tooltip(TTR("Move (Before)"));
+ move_up->set_tooltip_text(TTR("Move (Before)"));
hbc->add_child(move_up);
move_down = memnew(Button);
move_down->set_flat(true);
- move_down->set_tooltip(TTR("Move (After)"));
+ move_down->set_tooltip_text(TTR("Move (After)"));
hbc->add_child(move_down);
_delete = memnew(Button);
_delete->set_flat(true);
- _delete->set_tooltip(TTR("Delete"));
+ _delete->set_tooltip_text(TTR("Delete"));
hbc->add_child(_delete);
hbc->add_spacer();
@@ -1264,19 +1269,19 @@ SpriteFramesEditor::SpriteFramesEditor() {
zoom_out = memnew(Button);
zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_out));
zoom_out->set_flat(true);
- zoom_out->set_tooltip(TTR("Zoom Out"));
+ zoom_out->set_tooltip_text(TTR("Zoom Out"));
hbc->add_child(zoom_out);
zoom_reset = memnew(Button);
zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_reset));
zoom_reset->set_flat(true);
- zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ zoom_reset->set_tooltip_text(TTR("Zoom Reset"));
hbc->add_child(zoom_reset);
zoom_in = memnew(Button);
zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_in));
zoom_in->set_flat(true);
- zoom_in->set_tooltip(TTR("Zoom In"));
+ zoom_in->set_tooltip_text(TTR("Zoom In"));
hbc->add_child(zoom_in);
file = memnew(EditorFileDialog);
@@ -1429,21 +1434,21 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_zoom_out = memnew(Button);
split_sheet_zoom_out->set_flat(true);
split_sheet_zoom_out->set_focus_mode(FOCUS_NONE);
- split_sheet_zoom_out->set_tooltip(TTR("Zoom Out"));
+ split_sheet_zoom_out->set_tooltip_text(TTR("Zoom Out"));
split_sheet_zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_out));
split_sheet_zoom_hb->add_child(split_sheet_zoom_out);
split_sheet_zoom_reset = memnew(Button);
split_sheet_zoom_reset->set_flat(true);
split_sheet_zoom_reset->set_focus_mode(FOCUS_NONE);
- split_sheet_zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ split_sheet_zoom_reset->set_tooltip_text(TTR("Zoom Reset"));
split_sheet_zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_reset));
split_sheet_zoom_hb->add_child(split_sheet_zoom_reset);
split_sheet_zoom_in = memnew(Button);
split_sheet_zoom_in->set_flat(true);
split_sheet_zoom_in->set_focus_mode(FOCUS_NONE);
- split_sheet_zoom_in->set_tooltip(TTR("Zoom In"));
+ split_sheet_zoom_in->set_tooltip_text(TTR("Zoom In"));
split_sheet_zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_in));
split_sheet_zoom_hb->add_child(split_sheet_zoom_in);
@@ -1471,7 +1476,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
}
void SpriteFramesEditorPlugin::edit(Object *p_object) {
- frames_editor->set_undo_redo(&get_undo_redo());
+ frames_editor->set_undo_redo(get_undo_redo());
SpriteFrames *s;
AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object);
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 6352259b73..f2530b732f 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -45,6 +45,7 @@
#include "scene/gui/tree.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class SpriteFramesEditor : public HSplitContainer {
GDCLASS(SpriteFramesEditor, HSplitContainer);
@@ -151,7 +152,7 @@ class SpriteFramesEditor : public HSplitContainer {
bool updating;
bool updating_split_settings = false; // Skip SpinBox/Range callback when setting value by code.
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
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;
@@ -176,7 +177,7 @@ protected:
static void _bind_methods();
public:
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(SpriteFrames *p_frames);
SpriteFramesEditor();
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index d4baff34e2..fffcce6d9a 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -36,7 +36,7 @@ bool StyleBoxPreview::grid_preview_enabled = true;
void StyleBoxPreview::_grid_preview_toggled(bool p_active) {
grid_preview_enabled = p_active;
- preview->update();
+ preview->queue_redraw();
}
bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) {
@@ -66,7 +66,7 @@ void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
}
void StyleBoxPreview::_sb_changed() {
- preview->update();
+ preview->queue_redraw();
}
void StyleBoxPreview::_notification(int p_what) {
diff --git a/editor/plugins/sub_viewport_preview_editor_plugin.cpp b/editor/plugins/sub_viewport_preview_editor_plugin.cpp
index c8bb0cd56f..074a9708b7 100644
--- a/editor/plugins/sub_viewport_preview_editor_plugin.cpp
+++ b/editor/plugins/sub_viewport_preview_editor_plugin.cpp
@@ -39,7 +39,7 @@ void EditorInspectorPluginSubViewportPreview::parse_begin(Object *p_object) {
TexturePreview *sub_viewport_preview = memnew(TexturePreview(sub_viewport->get_texture(), false));
// Otherwise `sub_viewport_preview`'s `texture_display` doesn't update properly when `sub_viewport`'s size changes.
- sub_viewport->connect("size_changed", callable_mp((CanvasItem *)sub_viewport_preview->get_texture_display(), &CanvasItem::update));
+ sub_viewport->connect("size_changed", callable_mp((CanvasItem *)sub_viewport_preview->get_texture_display(), &CanvasItem::queue_redraw));
add_custom_control(sub_viewport_preview);
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 196d87da36..76332b2d10 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -128,8 +128,8 @@ Control *TextEditor::get_base_editor() const {
return code_editor->get_text_editor();
}
-Array TextEditor::get_breakpoints() {
- return Array();
+PackedInt32Array TextEditor::get_breakpoints() {
+ return PackedInt32Array();
}
void TextEditor::reload_text() {
@@ -165,7 +165,7 @@ void TextEditor::_update_bookmark_list() {
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV);
- Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
+ PackedInt32Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
if (bookmark_list.size() == 0) {
return;
}
@@ -339,15 +339,15 @@ void TextEditor::_edit_option(int p_op) {
} break;
case EDIT_TOGGLE_FOLD_LINE: {
tx->toggle_foldable_line(tx->get_caret_line());
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_FOLD_ALL_LINES: {
tx->fold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_UNFOLD_ALL_LINES: {
tx->unfold_all_lines();
- tx->update();
+ tx->queue_redraw();
} break;
case EDIT_TRIM_TRAILING_WHITESAPCE: {
trim_trailing_whitespace();
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 4f0121da52..15f7c45653 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -118,7 +118,7 @@ public:
virtual Variant get_edit_state() override;
virtual void set_edit_state(const Variant &p_state) override;
virtual Vector<String> get_functions() override;
- virtual Array get_breakpoints() override;
+ virtual PackedInt32Array get_breakpoints() override;
virtual void set_breakpoint(int p_line, bool p_enabled) override{};
virtual void clear_breakpoints() override{};
virtual void goto_line(int p_line, bool p_with_error = false) override;
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index 64cafa17f3..3ea62184c6 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -53,12 +53,12 @@ void Texture3DEditor::_texture_changed() {
if (!is_visible()) {
return;
}
- update();
+ queue_redraw();
}
void Texture3DEditor::_update_material() {
- material->set_shader_uniform("layer", (layer->get_value() + 0.5) / texture->get_depth());
- material->set_shader_uniform("tex", texture->get_rid());
+ material->set_shader_parameter("layer", (layer->get_value() + 0.5) / texture->get_depth());
+ material->set_shader_parameter("tex", texture->get_rid());
String format = Image::get_format_name(texture->get_format());
@@ -124,7 +124,7 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) {
}
texture->connect("changed", callable_mp(this, &Texture3DEditor::_texture_changed));
- update();
+ queue_redraw();
texture_rect->set_material(material);
setting = true;
layer->set_max(texture->get_depth() - 1);
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index f6b02d5f80..be382759f5 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -137,7 +137,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
// It's okay that these colors are static since the grid color is static too.
metadata_label->add_theme_color_override("font_color", Color::named("white"));
- metadata_label->add_theme_color_override("font_color_shadow", Color::named("black"));
+ metadata_label->add_theme_color_override("font_shadow_color", Color::named("black"));
metadata_label->add_theme_font_size_override("font_size", 14 * EDSCALE);
metadata_label->add_theme_color_override("font_outline_color", Color::named("black"));
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 2c6f70463d..dd8633360e 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -64,13 +64,13 @@ void TextureLayeredEditor::_texture_changed() {
if (!is_visible()) {
return;
}
- update();
+ queue_redraw();
}
void TextureLayeredEditor::_update_material() {
- materials[0]->set_shader_uniform("layer", layer->get_value());
- materials[2]->set_shader_uniform("layer", layer->get_value());
- materials[texture->get_layered_type()]->set_shader_uniform("tex", texture->get_rid());
+ materials[0]->set_shader_parameter("layer", layer->get_value());
+ materials[2]->set_shader_parameter("layer", layer->get_value());
+ materials[texture->get_layered_type()]->set_shader_parameter("tex", texture->get_rid());
Vector3 v(1, 1, 1);
v.normalize();
@@ -79,10 +79,10 @@ void TextureLayeredEditor::_update_material() {
b.rotate(Vector3(1, 0, 0), x_rot);
b.rotate(Vector3(0, 1, 0), y_rot);
- materials[1]->set_shader_uniform("normal", v);
- materials[1]->set_shader_uniform("rot", b);
- materials[2]->set_shader_uniform("normal", v);
- materials[2]->set_shader_uniform("rot", b);
+ materials[1]->set_shader_parameter("normal", v);
+ materials[1]->set_shader_parameter("rot", b);
+ materials[2]->set_shader_parameter("normal", v);
+ materials[2]->set_shader_parameter("rot", b);
String format = Image::get_format_name(texture->get_format());
@@ -190,7 +190,7 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) {
}
texture->connect("changed", callable_mp(this, &TextureLayeredEditor::_texture_changed));
- update();
+ queue_redraw();
texture_rect->set_material(materials[texture->get_layered_type()]);
setting = true;
if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 0bd8a8a484..8e04391a94 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/check_box.h"
#include "scene/gui/separator.h"
#include "scene/gui/view_panner.h"
@@ -380,8 +381,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
undo_redo->add_do_method(this, "_update_rect");
undo_redo->add_undo_method(this, "_update_rect");
- undo_redo->add_do_method(edit_draw, "update");
- undo_redo->add_undo_method(edit_draw, "update");
+ undo_redo->add_do_method(edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(edit_draw, "queue_redraw");
undo_redo->commit_action();
break;
}
@@ -454,8 +455,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
undo_redo->add_do_method(this, "_update_rect");
undo_redo->add_undo_method(this, "_update_rect");
- undo_redo->add_do_method(edit_draw, "update");
- undo_redo->add_undo_method(edit_draw, "update");
+ undo_redo->add_do_method(edit_draw, "queue_redraw");
+ undo_redo->add_undo_method(edit_draw, "queue_redraw");
undo_redo->commit_action();
drag = false;
creating = false;
@@ -476,7 +477,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else {
apply_rect(rect_prev);
rect = rect_prev;
- edit_draw->update();
+ edit_draw->queue_redraw();
drag_index = -1;
}
}
@@ -545,7 +546,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
rect = Rect2(drag_from, Size2());
rect.expand_to(new_pos);
apply_rect(rect);
- edit_draw->update();
+ edit_draw->queue_redraw();
return;
}
@@ -600,7 +601,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} break;
}
}
- edit_draw->update();
+ edit_draw->queue_redraw();
}
}
@@ -641,7 +642,7 @@ void TextureRegionEditor::_scroll_changed(float) {
draw_ofs.x = hscroll->get_value();
draw_ofs.y = vscroll->get_value();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_mode(int p_mode) {
@@ -657,37 +658,37 @@ void TextureRegionEditor::_set_snap_mode(int p_mode) {
_update_autoslice();
}
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_off_x(float p_val) {
snap_offset.x = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_off_y(float p_val) {
snap_offset.y = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_step_x(float p_val) {
snap_step.x = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_step_y(float p_val) {
snap_step.y = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_sep_x(float p_val) {
snap_separation.x = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_set_snap_sep_y(float p_val) {
snap_separation.y = p_val;
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
@@ -701,7 +702,7 @@ void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
ofs = ofs / prev_zoom - ofs / draw_zoom;
draw_ofs = (draw_ofs + ofs).round();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
void TextureRegionEditor::_zoom_in() {
@@ -822,7 +823,7 @@ void TextureRegionEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ edit_draw->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
case NOTIFICATION_READY: {
zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
@@ -932,7 +933,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
obj_styleBox = Ref<StyleBoxTexture>(nullptr);
atlas_tex = Ref<AtlasTexture>(nullptr);
}
- edit_draw->update();
+ edit_draw->queue_redraw();
popup_centered_ratio(0.5);
request_center = true;
}
@@ -962,7 +963,7 @@ void TextureRegionEditor::_edit_region() {
_zoom_reset();
hscroll->hide();
vscroll->hide();
- edit_draw->update();
+ edit_draw->queue_redraw();
return;
}
@@ -978,7 +979,7 @@ void TextureRegionEditor::_edit_region() {
}
_update_rect();
- edit_draw->update();
+ edit_draw->queue_redraw();
}
Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
@@ -1109,19 +1110,19 @@ TextureRegionEditor::TextureRegionEditor() {
zoom_out = memnew(Button);
zoom_out->set_flat(true);
- zoom_out->set_tooltip(TTR("Zoom Out"));
+ zoom_out->set_tooltip_text(TTR("Zoom Out"));
zoom_out->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_out));
zoom_hb->add_child(zoom_out);
zoom_reset = memnew(Button);
zoom_reset->set_flat(true);
- zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ zoom_reset->set_tooltip_text(TTR("Zoom Reset"));
zoom_reset->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_reset));
zoom_hb->add_child(zoom_reset);
zoom_in = memnew(Button);
zoom_in->set_flat(true);
- zoom_in->set_tooltip(TTR("Zoom In"));
+ zoom_in->set_tooltip_text(TTR("Zoom In"));
zoom_in->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_in));
zoom_hb->add_child(zoom_in);
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index a18c87f153..e3bbaf49fc 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -40,6 +40,7 @@
#include "scene/resources/texture.h"
class ViewPanner;
+class EditorUndoRedoManager;
class TextureRegionEditor : public AcceptDialog {
GDCLASS(TextureRegionEditor, AcceptDialog);
@@ -68,7 +69,7 @@ class TextureRegionEditor : public AcceptDialog {
VScrollBar *vscroll = nullptr;
HScrollBar *hscroll = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Vector2 draw_ofs;
float draw_zoom = 0.0;
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index bbc22c8622..f6acd8ceda 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -35,8 +35,10 @@
#include "editor/editor_node.h"
#include "editor/editor_resource_picker.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/progress_dialog.h"
#include "scene/gui/color_picker.h"
+#include "scene/theme/theme_db.h"
void ThemeItemImportTree::_update_items_tree() {
import_items_tree->clear();
@@ -796,7 +798,7 @@ void ThemeItemImportTree::_import_selected() {
ProgressDialog::get_singleton()->end_task("import_theme_items");
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Import Theme Items"));
ur->add_do_method(*edited_theme, "clear");
@@ -1102,15 +1104,15 @@ ThemeItemImportTree::ThemeItemImportTree() {
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);
+ select_all_items_button->set_tooltip_text(select_all_items_tooltip);
button_set->add_child(select_all_items_button);
select_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_data_type_pressed).bind(i));
select_full_items_button->set_flat(true);
- select_full_items_button->set_tooltip(select_full_items_tooltip);
+ select_full_items_button->set_tooltip_text(select_full_items_tooltip);
button_set->add_child(select_full_items_button);
select_full_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_data_type_pressed).bind(i));
deselect_all_items_button->set_flat(true);
- deselect_all_items_button->set_tooltip(deselect_all_items_tooltip);
+ deselect_all_items_button->set_tooltip_text(deselect_all_items_tooltip);
button_set->add_child(deselect_all_items_button);
deselect_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed).bind(i));
@@ -1141,12 +1143,12 @@ ThemeItemImportTree::ThemeItemImportTree() {
import_collapse_types_button = memnew(Button);
import_collapse_types_button->set_flat(true);
- import_collapse_types_button->set_tooltip(TTR("Collapse types."));
+ import_collapse_types_button->set_tooltip_text(TTR("Collapse types."));
import_buttons->add_child(import_collapse_types_button);
import_collapse_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(true));
import_expand_types_button = memnew(Button);
import_expand_types_button->set_flat(true);
- import_expand_types_button->set_tooltip(TTR("Expand types."));
+ import_expand_types_button->set_tooltip_text(TTR("Expand types."));
import_buttons->add_child(import_expand_types_button);
import_expand_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(false));
@@ -1155,19 +1157,19 @@ ThemeItemImportTree::ThemeItemImportTree() {
import_select_all_button = memnew(Button);
import_select_all_button->set_flat(true);
import_select_all_button->set_text(TTR("Select All"));
- import_select_all_button->set_tooltip(TTR("Select all Theme items."));
+ import_select_all_button->set_tooltip_text(TTR("Select all Theme items."));
import_buttons->add_child(import_select_all_button);
import_select_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_items_pressed));
import_select_full_button = memnew(Button);
import_select_full_button->set_flat(true);
import_select_full_button->set_text(TTR("Select With Data"));
- import_select_full_button->set_tooltip(TTR("Select all Theme items with item data."));
+ import_select_full_button->set_tooltip_text(TTR("Select all Theme items with item data."));
import_buttons->add_child(import_select_full_button);
import_select_full_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_items_pressed));
import_deselect_all_button = memnew(Button);
import_deselect_all_button->set_flat(true);
import_deselect_all_button->set_text(TTR("Deselect All"));
- import_deselect_all_button->set_tooltip(TTR("Deselect all Theme items."));
+ import_deselect_all_button->set_tooltip_text(TTR("Deselect all Theme items."));
import_buttons->add_child(import_deselect_all_button);
import_deselect_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_items_pressed));
@@ -1201,7 +1203,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() {
_update_edit_types();
import_default_theme_items->set_edited_theme(edited_theme);
- import_default_theme_items->set_base_theme(Theme::get_default());
+ import_default_theme_items->set_base_theme(ThemeDB::get_singleton()->get_default_theme());
import_default_theme_items->reset_item_tree();
import_editor_theme_items->set_edited_theme(edited_theme);
@@ -1213,7 +1215,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() {
}
void ThemeItemEditorDialog::_update_edit_types() {
- Ref<Theme> base_theme = Theme::get_default();
+ Ref<Theme> base_theme = ThemeDB::get_singleton()->get_default_theme();
List<StringName> theme_types;
edited_theme->get_type_list(&theme_types);
@@ -1494,7 +1496,7 @@ 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);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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));
@@ -1513,7 +1515,7 @@ 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();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Theme Type"));
ur->add_do_method(*edited_theme, "add_type", new_type);
@@ -1525,7 +1527,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
}
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();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Create Theme Item"));
switch (p_data_type) {
@@ -1570,7 +1572,7 @@ 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();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Theme Type"));
new_snapshot->remove_type(p_theme_type);
@@ -1593,7 +1595,7 @@ void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type,
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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);
@@ -1622,14 +1624,14 @@ void ThemeItemEditorDialog::_remove_class_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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;
names.clear();
- Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_theme_item_list(data_type, edited_item_type, &names);
for (const StringName &E : names) {
if (new_snapshot->has_theme_item_nocheck(data_type, E, edited_item_type)) {
new_snapshot->clear_theme_item(data_type, E, edited_item_type);
@@ -1658,7 +1660,7 @@ void ThemeItemEditorDialog::_remove_custom_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Custom Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1667,7 +1669,7 @@ void ThemeItemEditorDialog::_remove_custom_items() {
names.clear();
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)) {
+ if (!ThemeDB::get_singleton()->get_default_theme()->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))) {
@@ -1694,7 +1696,7 @@ void ThemeItemEditorDialog::_remove_all_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove All Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1798,7 +1800,7 @@ 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) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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);
@@ -1953,42 +1955,42 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito
edit_items_toolbar->add_child(edit_items_toolbar_add_label);
edit_items_add_color = memnew(Button);
- edit_items_add_color->set_tooltip(TTR("Add Color Item"));
+ edit_items_add_color->set_tooltip_text(TTR("Add Color Item"));
edit_items_add_color->set_flat(true);
edit_items_add_color->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_color);
edit_items_add_color->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_COLOR));
edit_items_add_constant = memnew(Button);
- edit_items_add_constant->set_tooltip(TTR("Add Constant Item"));
+ edit_items_add_constant->set_tooltip_text(TTR("Add Constant Item"));
edit_items_add_constant->set_flat(true);
edit_items_add_constant->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_constant);
edit_items_add_constant->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_CONSTANT));
edit_items_add_font = memnew(Button);
- edit_items_add_font->set_tooltip(TTR("Add Font Item"));
+ edit_items_add_font->set_tooltip_text(TTR("Add Font Item"));
edit_items_add_font->set_flat(true);
edit_items_add_font->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_font);
edit_items_add_font->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT));
edit_items_add_font_size = memnew(Button);
- edit_items_add_font_size->set_tooltip(TTR("Add Font Size Item"));
+ edit_items_add_font_size->set_tooltip_text(TTR("Add Font Size Item"));
edit_items_add_font_size->set_flat(true);
edit_items_add_font_size->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_font_size);
edit_items_add_font_size->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT_SIZE));
edit_items_add_icon = memnew(Button);
- edit_items_add_icon->set_tooltip(TTR("Add Icon Item"));
+ edit_items_add_icon->set_tooltip_text(TTR("Add Icon Item"));
edit_items_add_icon->set_flat(true);
edit_items_add_icon->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_icon);
edit_items_add_icon->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_ICON));
edit_items_add_stylebox = memnew(Button);
- edit_items_add_stylebox->set_tooltip(TTR("Add StyleBox Item"));
+ edit_items_add_stylebox->set_tooltip_text(TTR("Add StyleBox Item"));
edit_items_add_stylebox->set_flat(true);
edit_items_add_stylebox->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_stylebox);
@@ -2001,21 +2003,21 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito
edit_items_toolbar->add_child(edit_items_toolbar_remove_label);
edit_items_remove_class = memnew(Button);
- edit_items_remove_class->set_tooltip(TTR("Remove Class Items"));
+ edit_items_remove_class->set_tooltip_text(TTR("Remove Class Items"));
edit_items_remove_class->set_flat(true);
edit_items_remove_class->set_disabled(true);
edit_items_toolbar->add_child(edit_items_remove_class);
edit_items_remove_class->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_class_items));
edit_items_remove_custom = memnew(Button);
- edit_items_remove_custom->set_tooltip(TTR("Remove Custom Items"));
+ edit_items_remove_custom->set_tooltip_text(TTR("Remove Custom Items"));
edit_items_remove_custom->set_flat(true);
edit_items_remove_custom->set_disabled(true);
edit_items_toolbar->add_child(edit_items_remove_custom);
edit_items_remove_custom->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items));
edit_items_remove_all = memnew(Button);
- edit_items_remove_all->set_tooltip(TTR("Remove All Items"));
+ edit_items_remove_all->set_tooltip_text(TTR("Remove All Items"));
edit_items_remove_all->set_flat(true);
edit_items_remove_all->set_disabled(true);
edit_items_toolbar->add_child(edit_items_remove_all);
@@ -2128,7 +2130,7 @@ void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {
add_type_options->clear();
List<StringName> names;
- Theme::get_default()->get_type_list(&names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_list(&names);
if (include_own_types) {
edited_theme->get_type_list(&names);
}
@@ -2369,7 +2371,7 @@ HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, v
default_type = edited_theme->get_type_variation_base(p_type_name);
}
- (Theme::get_default().operator->()->*get_list_func)(default_type, &names);
+ (ThemeDB::get_singleton()->get_default_theme().operator->()->*get_list_func)(default_type, &names);
names.sort_custom<StringName::AlphCompare>();
for (const StringName &E : names) {
items[E] = false;
@@ -2411,7 +2413,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
item_name->set_h_size_flags(SIZE_EXPAND_FILL);
item_name->set_clip_text(true);
item_name->set_text(p_item_name);
- item_name->set_tooltip(p_item_name);
+ item_name->set_tooltip_text(p_item_name);
item_name_container->add_child(item_name);
if (p_editable) {
@@ -2424,21 +2426,21 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
Button *item_rename_button = memnew(Button);
item_rename_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- item_rename_button->set_tooltip(TTR("Rename Item"));
+ item_rename_button->set_tooltip_text(TTR("Rename Item"));
item_rename_button->set_flat(true);
item_name_container->add_child(item_rename_button);
item_rename_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_cbk).bind(p_data_type, p_item_name, item_name_container));
Button *item_remove_button = memnew(Button);
item_remove_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- item_remove_button->set_tooltip(TTR("Remove Item"));
+ item_remove_button->set_tooltip_text(TTR("Remove Item"));
item_remove_button->set_flat(true);
item_name_container->add_child(item_remove_button);
item_remove_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_remove_cbk).bind(p_data_type, p_item_name));
Button *item_rename_confirm_button = memnew(Button);
item_rename_confirm_button->set_icon(get_theme_icon(SNAME("ImportCheck"), SNAME("EditorIcons")));
- item_rename_confirm_button->set_tooltip(TTR("Confirm Item Rename"));
+ item_rename_confirm_button->set_tooltip_text(TTR("Confirm Item Rename"));
item_rename_confirm_button->set_flat(true);
item_name_container->add_child(item_rename_confirm_button);
item_rename_confirm_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_confirmed).bind(p_data_type, p_item_name, item_name_container));
@@ -2446,7 +2448,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
Button *item_rename_cancel_button = memnew(Button);
item_rename_cancel_button->set_icon(get_theme_icon(SNAME("ImportFail"), SNAME("EditorIcons")));
- item_rename_cancel_button->set_tooltip(TTR("Cancel Item Rename"));
+ item_rename_cancel_button->set_tooltip_text(TTR("Cancel Item Rename"));
item_rename_cancel_button->set_flat(true);
item_name_container->add_child(item_rename_cancel_button);
item_rename_cancel_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_canceled).bind(p_data_type, p_item_name, item_name_container));
@@ -2456,7 +2458,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
Button *item_override_button = memnew(Button);
item_override_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
- item_override_button->set_tooltip(TTR("Override Item"));
+ item_override_button->set_tooltip_text(TTR("Override Item"));
item_override_button->set_flat(true);
item_name_container->add_child(item_override_button);
item_override_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_override_cbk).bind(p_data_type, p_item_name));
@@ -2495,7 +2497,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed).bind(E.key));
item_editor->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(item_editor->get_picker()));
} else {
- item_editor->set_pick_color(Theme::get_default()->get_color(E.key, edited_type));
+ item_editor->set_pick_color(ThemeDB::get_singleton()->get_default_theme()->get_color(E.key, edited_type));
item_editor->set_disabled(true);
}
@@ -2528,7 +2530,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->set_value(edited_theme->get_constant(E.key, edited_type));
item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed).bind(E.key));
} else {
- item_editor->set_value(Theme::get_default()->get_constant(E.key, edited_type));
+ item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_constant(E.key, edited_type));
item_editor->set_editable(false);
}
@@ -2562,8 +2564,8 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed).bind(E.key));
} else {
- if (Theme::get_default()->has_font(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_font(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_font(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_font(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2599,7 +2601,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->set_value(edited_theme->get_font_size(E.key, edited_type));
item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed).bind(E.key));
} else {
- item_editor->set_value(Theme::get_default()->get_font_size(E.key, edited_type));
+ item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_font_size(E.key, edited_type));
item_editor->set_editable(false);
}
@@ -2633,8 +2635,8 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed).bind(E.key));
} else {
- if (Theme::get_default()->has_icon(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_icon(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_icon(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2666,7 +2668,7 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_toggle_mode(true);
pin_leader_button->set_pressed(true);
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."));
+ pin_leader_button->set_tooltip_text(TTR("Unpin this StyleBox as a main style."));
item_control->add_child(pin_leader_button);
pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_unpin_leader_button_pressed));
@@ -2709,12 +2711,12 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_flat(true);
pin_leader_button->set_toggle_mode(true);
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."));
+ pin_leader_button->set_tooltip_text(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::_on_pin_leader_button_pressed).bind(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));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_stylebox(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2769,62 +2771,62 @@ void ThemeTypeEditor::_add_default_type_items() {
{
names.clear();
- Theme::get_default()->get_icon_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_icon_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_icon(E, edited_type)) {
- new_snapshot->set_icon(E, edited_type, Theme::get_default()->get_icon(E, edited_type));
+ new_snapshot->set_icon(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_icon(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_stylebox_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_stylebox(E, edited_type)) {
- new_snapshot->set_stylebox(E, edited_type, Theme::get_default()->get_stylebox(E, edited_type));
+ new_snapshot->set_stylebox(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_font_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_font(E, edited_type)) {
- new_snapshot->set_font(E, edited_type, Theme::get_default()->get_font(E, edited_type));
+ new_snapshot->set_font(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_font_size_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(default_type, &names);
for (const StringName &E : names) {
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));
+ new_snapshot->set_font_size(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_color_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_color(E, edited_type)) {
- new_snapshot->set_color(E, edited_type, Theme::get_default()->get_color(E, edited_type));
+ new_snapshot->set_color(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_constant_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_constant(E, edited_type)) {
- new_snapshot->set_constant(E, edited_type, Theme::get_default()->get_constant(E, edited_type));
+ new_snapshot->set_constant(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(E, edited_type));
}
}
}
updating = false;
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Override All Default Theme Items"));
ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
@@ -2844,7 +2846,7 @@ 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();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Theme Item"));
switch (p_data_type) {
@@ -2889,16 +2891,16 @@ 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();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Override Theme Item"));
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR: {
- 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_do_method(*edited_theme, "set_color", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->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: {
- 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_do_method(*edited_theme, "set_constant", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->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: {
@@ -2906,7 +2908,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT_SIZE: {
- 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_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->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: {
@@ -2928,7 +2930,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
}
void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Theme Item"));
switch (p_data_type) {
@@ -3002,7 +3004,7 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Rename Theme Item"));
switch (p_data_type) {
@@ -3058,7 +3060,7 @@ 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) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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));
@@ -3066,7 +3068,7 @@ void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
}
void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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));
@@ -3074,7 +3076,7 @@ void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name)
}
void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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));
@@ -3086,7 +3088,7 @@ void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit)
}
void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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>());
@@ -3103,7 +3105,7 @@ void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name)
}
void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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>());
@@ -3120,7 +3122,7 @@ void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_n
}
void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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>());
@@ -3163,7 +3165,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_
stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Pin Stylebox"));
ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox);
@@ -3196,7 +3198,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_
}
void ThemeTypeEditor::_on_unpin_leader_button_pressed() {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::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);
@@ -3265,7 +3267,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
}
void ThemeTypeEditor::_type_variation_changed(const String p_value) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Theme Type Variation"));
if (p_value.is_empty()) {
@@ -3386,7 +3388,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
theme_type_list->connect("item_selected", callable_mp(this, &ThemeTypeEditor::_list_type_selected));
add_type_button = memnew(Button);
- add_type_button->set_tooltip(TTR("Add a type from a list of available types or create a new one."));
+ add_type_button->set_tooltip_text(TTR("Add a type from a list of available types or create a new one."));
type_list_hb->add_child(add_type_button);
add_type_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_button_cbk));
@@ -3396,7 +3398,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
show_default_items_button = memnew(CheckButton);
show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
show_default_items_button->set_text(TTR("Show Default"));
- show_default_items_button->set_tooltip(TTR("Show default type items alongside items that have been overridden."));
+ show_default_items_button->set_tooltip_text(TTR("Show default type items alongside items that have been overridden."));
show_default_items_button->set_pressed(true);
type_controls->add_child(show_default_items_button);
show_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_update_type_items));
@@ -3404,7 +3406,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
Button *add_default_items_button = memnew(Button);
add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
add_default_items_button->set_text(TTR("Override All"));
- add_default_items_button->set_tooltip(TTR("Override all default type items."));
+ add_default_items_button->set_tooltip_text(TTR("Override all default type items."));
type_controls->add_child(add_default_items_button);
add_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_default_type_items));
@@ -3451,7 +3453,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
type_variation_edit->connect("focus_exited", callable_mp(this, &ThemeTypeEditor::_update_type_items));
type_variation_button = memnew(Button);
type_variation_hb->add_child(type_variation_button);
- type_variation_button->set_tooltip(TTR("Select the variation base type from a list of available types."));
+ type_variation_button->set_tooltip_text(TTR("Select the variation base type from a list of available types."));
type_variation_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_variation_cbk));
type_variation_locked = memnew(Label);
@@ -3632,7 +3634,7 @@ ThemeEditor::ThemeEditor() {
Button *theme_edit_button = memnew(Button);
theme_edit_button->set_text(TTR("Manage Items..."));
- theme_edit_button->set_tooltip(TTR("Add, remove, organize and import Theme items."));
+ theme_edit_button->set_tooltip_text(TTR("Add, remove, organize and import Theme items."));
theme_edit_button->set_flat(true);
theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));
top_menu->add_child(theme_edit_button);
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index b5c6c6d651..8cc96201e7 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -40,6 +40,7 @@
#include "scene/gui/color_picker.h"
#include "scene/gui/progress_bar.h"
#include "scene/resources/packed_scene.h"
+#include "scene/theme/theme_db.h"
constexpr double REFRESH_TIMER = 1.5;
@@ -55,7 +56,7 @@ void ThemeEditorPreview::add_preview_overlay(Control *p_overlay) {
void ThemeEditorPreview::_propagate_redraw(Control *p_at) {
p_at->notification(NOTIFICATION_THEME_CHANGED);
p_at->update_minimum_size();
- p_at->update();
+ p_at->queue_redraw();
for (int i = 0; i < p_at->get_child_count(); i++) {
Control *a = Object::cast_to<Control>(p_at->get_child(i));
if (a) {
@@ -173,7 +174,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
if (mm.is_valid()) {
Vector2 mp = preview_content->get_local_mouse_position();
hovered_control = _find_hovered_control(preview_content, mp);
- picker_overlay->update();
+ picker_overlay->queue_redraw();
}
// Forward input to the scroll container underneath to allow scrolling.
@@ -182,7 +183,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
void ThemeEditorPreview::_reset_picker_overlay() {
hovered_control = nullptr;
- picker_overlay->update();
+ picker_overlay->queue_redraw();
}
void ThemeEditorPreview::_notification(int p_what) {
@@ -227,7 +228,7 @@ ThemeEditorPreview::ThemeEditorPreview() {
preview_toolbar->add_child(picker_button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_tooltip(TTR("Toggle the control picker, allowing to visually select control types for edit."));
+ picker_button->set_tooltip_text(TTR("Toggle the control picker, allowing to visually select control types for edit."));
picker_button->connect("pressed", callable_mp(this, &ThemeEditorPreview::_picker_button_cbk));
MarginContainer *preview_body = memnew(MarginContainer);
@@ -240,7 +241,7 @@ ThemeEditorPreview::ThemeEditorPreview() {
MarginContainer *preview_root = memnew(MarginContainer);
preview_container->add_child(preview_root);
- preview_root->set_theme(Theme::get_default());
+ preview_root->set_theme(ThemeDB::get_singleton()->get_default_theme());
preview_root->set_clip_contents(true);
preview_root->set_custom_minimum_size(Size2(450, 0) * EDSCALE);
preview_root->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -517,7 +518,7 @@ SceneThemeEditorPreview::SceneThemeEditorPreview() {
reload_scene_button = memnew(Button);
reload_scene_button->set_flat(true);
- reload_scene_button->set_tooltip(TTR("Reload the scene to reflect its most actual state."));
+ reload_scene_button->set_tooltip_text(TTR("Reload the scene to reflect its most actual state."));
preview_toolbar->add_child(reload_scene_button);
reload_scene_button->connect("pressed", callable_mp(this, &SceneThemeEditorPreview::_reload_scene));
}
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index 3fe6778f48..de4f3f7989 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/control.h"
#include "scene/gui/split_container.h"
diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h
index c54e259594..c7e4635d16 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.h
+++ b/editor/plugins/tiles/atlas_merging_dialog.h
@@ -38,6 +38,7 @@
#include "scene/resources/tile_set.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class AtlasMergingDialog : public ConfirmationDialog {
GDCLASS(AtlasMergingDialog, ConfirmationDialog);
@@ -49,7 +50,7 @@ private:
LocalVector<HashMap<Vector2i, Vector2i>> merged_mapping;
Ref<TileSet> tile_set;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
// Settings.
int next_line_after_column = 30;
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index f119ada810..d9291503cb 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -127,8 +127,8 @@ void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
}
// Update the backgrounds.
- background_left->update();
- background_right->update();
+ background_left->set_size(base_tiles_root_control->get_custom_minimum_size());
+ background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size());
// Zoom on the position.
if (p_zoom_on_mouse_pos) {
@@ -139,7 +139,7 @@ void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
// Center of panel.
panning = panning * zoom / previous_zoom;
}
- button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
+ button_center_view->set_disabled(panning.is_zero_approx());
previous_zoom = zoom;
@@ -160,7 +160,7 @@ void TileAtlasView::_center_view() {
}
void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
- base_tiles_root_control->set_tooltip("");
+ base_tiles_root_control->set_tooltip_text("");
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
@@ -169,7 +169,7 @@ void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
coords = tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- base_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords));
+ base_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords));
}
}
}
@@ -319,7 +319,7 @@ void TileAtlasView::_draw_base_tiles_shape_grid() {
}
void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
- alternative_tiles_root_control->set_tooltip("");
+ alternative_tiles_root_control->set_tooltip_text("");
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
@@ -328,7 +328,7 @@ void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEve
Vector2i coords = Vector2i(coords3.x, coords3.y);
int alternative_id = coords3.z;
if (coords != TileSetSource::INVALID_ATLAS_COORDS && alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
- alternative_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id));
+ alternative_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id));
}
}
}
@@ -374,13 +374,11 @@ void TileAtlasView::_draw_alternatives() {
void TileAtlasView::_draw_background_left() {
Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
- background_left->set_size(base_tiles_root_control->get_custom_minimum_size());
background_left->draw_texture_rect(texture, Rect2(Vector2(), background_left->get_size()), true);
}
void TileAtlasView::_draw_background_right() {
Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
- background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size());
background_right->draw_texture_rect(texture, Rect2(Vector2(), background_right->get_size()), true);
}
@@ -405,30 +403,13 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
// Update everything.
_update_zoom_and_panning();
- // Change children control size.
- Size2i base_tiles_control_size = _compute_base_tiles_control_size();
- for (int i = 0; i < base_tiles_drawing_root->get_child_count(); i++) {
- Control *control = Object::cast_to<Control>(base_tiles_drawing_root->get_child(i));
- if (control) {
- control->set_size(base_tiles_control_size);
- }
- }
-
- Size2i alternative_control_size = _compute_alternative_tiles_control_size();
- for (int i = 0; i < alternative_tiles_drawing_root->get_child_count(); i++) {
- Control *control = Object::cast_to<Control>(alternative_tiles_drawing_root->get_child(i));
- if (control) {
- control->set_size(alternative_control_size);
- }
- }
-
// Update.
- base_tiles_draw->update();
- base_tiles_texture_grid->update();
- base_tiles_shape_grid->update();
- alternatives_draw->update();
- background_left->update();
- background_right->update();
+ base_tiles_draw->queue_redraw();
+ base_tiles_texture_grid->queue_redraw();
+ base_tiles_shape_grid->queue_redraw();
+ alternatives_draw->queue_redraw();
+ background_left->queue_redraw();
+ background_right->queue_redraw();
}
float TileAtlasView::get_zoom() const {
@@ -512,13 +493,13 @@ Rect2i TileAtlasView::get_alternative_tile_rect(const Vector2i p_coords, int p_a
return alternative_tiles_rect_cache[p_coords][p_alternative_tile];
}
-void TileAtlasView::update() {
- base_tiles_draw->update();
- base_tiles_texture_grid->update();
- base_tiles_shape_grid->update();
- alternatives_draw->update();
- background_left->update();
- background_right->update();
+void TileAtlasView::queue_redraw() {
+ base_tiles_draw->queue_redraw();
+ base_tiles_texture_grid->queue_redraw();
+ base_tiles_shape_grid->queue_redraw();
+ alternatives_draw->queue_redraw();
+ background_left->queue_redraw();
+ background_right->queue_redraw();
}
void TileAtlasView::_notification(int p_what) {
@@ -561,7 +542,7 @@ TileAtlasView::TileAtlasView() {
button_center_view->connect("pressed", callable_mp(this, &TileAtlasView::_center_view));
button_center_view->set_flat(true);
button_center_view->set_disabled(true);
- button_center_view->set_tooltip(TTR("Center View"));
+ button_center_view->set_tooltip_text(TTR("Center View"));
add_child(button_center_view);
panner.instantiate();
@@ -613,7 +594,7 @@ TileAtlasView::TileAtlasView() {
background_left = memnew(Control);
background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
- background_left->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+ background_left->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT);
background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left));
base_tiles_root_control->add_child(background_left);
@@ -651,23 +632,26 @@ TileAtlasView::TileAtlasView() {
alternative_tiles_root_control = memnew(Control);
alternative_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ alternative_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
alternative_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_alternative_tiles_root_control_gui_input));
right_vbox->add_child(alternative_tiles_root_control);
background_right = memnew(Control);
background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ background_right->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT);
background_right->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
background_right->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_right));
-
alternative_tiles_root_control->add_child(background_right);
alternative_tiles_drawing_root = memnew(Control);
alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternative_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
alternative_tiles_root_control->add_child(alternative_tiles_drawing_root);
alternatives_draw = memnew(Control);
alternatives_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternatives_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives));
alternative_tiles_drawing_root->add_child(alternatives_draw);
}
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 196a642283..c710eac107 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -136,6 +136,7 @@ public:
} else {
base_tiles_root_control->add_child(p_control);
}
+ p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
};
@@ -149,11 +150,12 @@ public:
} else {
alternative_tiles_root_control->add_child(p_control);
}
+ p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
};
- // Update everything.
- void update();
+ // Redraw everything.
+ void queue_redraw();
TileAtlasView();
};
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index a00e1ed9e8..4d54001b94 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -38,6 +38,11 @@
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
+
+#ifdef DEBUG_ENABLED
+#include "servers/navigation_server_3d.h"
+#endif // DEBUG_ENABLED
void TileDataEditor::_tile_set_changed_plan_update() {
_tile_set_changed_update_needed = true;
@@ -239,16 +244,23 @@ void GenericTilePolygonEditor::_base_control_draw() {
void GenericTilePolygonEditor::_center_view() {
panning = Vector2();
- base_control->update();
+ base_control->queue_redraw();
button_center_view->set_disabled(true);
}
void GenericTilePolygonEditor::_zoom_changed() {
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
- UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo);
+ Ref<EditorUndoRedoManager> undo_redo;
+ if (use_undo_redo) {
+ undo_redo = editor_undo_redo;
+ } else {
+ // This nice hack allows for discarding undo actions without making code too complex.
+ undo_redo.instantiate();
+ }
+
switch (p_item_pressed) {
case RESET_TO_DEFAULT_TILE: {
undo_redo->create_action(TTR("Reset Polygons"));
@@ -258,26 +270,26 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
polygon.write[i] = polygon[i] * tile_set->get_tile_size();
}
undo_redo->add_do_method(this, "add_polygon", polygon);
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
undo_redo->add_undo_method(this, "clear_polygons");
for (unsigned int i = 0; i < polygons.size(); i++) {
undo_redo->add_undo_method(this, "add_polygon", polygons[i]);
}
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
undo_redo->commit_action(true);
} break;
case CLEAR_TILE: {
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(base_control, "queue_redraw");
undo_redo->add_do_method(this, "emit_signal", "polygons_changed");
undo_redo->add_undo_method(this, "clear_polygons");
for (unsigned int i = 0; i < polygons.size(); i++) {
undo_redo->add_undo_method(this, "add_polygon", polygons[i]);
}
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "emit_signal", "polygons_changed");
undo_redo->commit_action(true);
} break;
@@ -310,21 +322,18 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
}
undo_redo->add_do_method(this, "set_polygon", i, new_polygon);
}
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
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(base_control, "queue_redraw");
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) {
@@ -409,7 +418,14 @@ 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);
+ Ref<EditorUndoRedoManager> undo_redo;
+ if (use_undo_redo) {
+ undo_redo = editor_undo_redo;
+ } else {
+ // This nice hack allows for discarding undo actions without making code too complex.
+ undo_redo.instantiate();
+ }
+
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
hovered_polygon_index = -1;
@@ -436,7 +452,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
} else if (drag_type == DRAG_TYPE_PAN) {
panning += mm->get_position() - drag_last_pos;
drag_last_pos = mm->get_position();
- button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
+ button_center_view->set_disabled(panning.is_zero_approx());
} else {
// Update hovered point.
_grab_polygon_point(mm->get_position(), xform, hovered_polygon_index, hovered_point_index);
@@ -479,9 +495,9 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
undo_redo->add_do_method(this, "clear_polygons");
}
undo_redo->add_do_method(this, "add_polygon", in_creation_polygon);
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "remove_polygon", added);
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
} else {
@@ -527,8 +543,8 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]);
undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon);
}
- undo_redo->add_do_method(base_control, "update");
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
}
@@ -537,9 +553,9 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
if (drag_type == DRAG_TYPE_DRAG_POINT) {
undo_redo->create_action(TTR("Edit Polygons"));
undo_redo->add_do_method(this, "set_polygon", drag_polygon_index, polygons[drag_polygon_index]);
- undo_redo->add_do_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
undo_redo->add_undo_method(this, "set_polygon", drag_polygon_index, drag_old_polygon);
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
} else if (drag_type == DRAG_TYPE_CREATE_POINT) {
@@ -574,8 +590,8 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]);
undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon);
}
- undo_redo->add_do_method(base_control, "update");
- undo_redo->add_undo_method(base_control, "update");
+ undo_redo->add_do_method(base_control, "queue_redraw");
+ undo_redo->add_undo_method(base_control, "queue_redraw");
undo_redo->commit_action(false);
emit_signal(SNAME("polygons_changed"));
} else {
@@ -599,11 +615,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
}
}
- base_control->update();
-
- if (!use_undo_redo) {
- memdelete(undo_redo);
- }
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
@@ -651,7 +663,7 @@ void GenericTilePolygonEditor::set_background(Ref<Texture2D> p_texture, Rect2 p_
background_v_flip = p_flip_v;
background_transpose = p_transpose;
background_modulate = p_modulate;
- base_control->update();
+ base_control->queue_redraw();
}
int GenericTilePolygonEditor::get_polygon_count() {
@@ -664,13 +676,13 @@ int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index)
if (p_index < 0) {
polygons.push_back(p_polygon);
- base_control->update();
+ base_control->queue_redraw();
button_edit->set_pressed(true);
return polygons.size() - 1;
} else {
polygons.insert(p_index, p_polygon);
button_edit->set_pressed(true);
- base_control->update();
+ base_control->queue_redraw();
return p_index;
}
}
@@ -682,12 +694,12 @@ void GenericTilePolygonEditor::remove_polygon(int p_index) {
if (polygons.size() == 0) {
button_create->set_pressed(true);
}
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::clear_polygons() {
polygons.clear();
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p_polygon) {
@@ -695,7 +707,7 @@ void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p
ERR_FAIL_COND(p_polygon.size() < 3);
polygons[p_polygon_index] = p_polygon;
button_edit->set_pressed(true);
- base_control->update();
+ base_control->queue_redraw();
}
Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) {
@@ -705,7 +717,7 @@ Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) {
void GenericTilePolygonEditor::set_polygons_color(Color p_color) {
polygon_color = p_color;
- base_control->update();
+ base_control->queue_redraw();
}
void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon_mode) {
@@ -756,21 +768,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"));
+ button_create->set_tooltip_text(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"));
+ button_edit->set_tooltip_text(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"));
+ button_delete->set_tooltip_text(TTR("Delete points tool"));
toolbar->add_child(button_delete);
button_advanced_menu = memnew(MenuButton);
@@ -793,7 +805,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"));
+ button_pixel_snap->set_tooltip_text(TTR("Snap to half-pixel"));
toolbar->add_child(button_pixel_snap);
Control *root = memnew(Control);
@@ -1153,7 +1165,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->set_tooltip_text(p_property);
property_editor->update_property();
add_child(property_editor);
}
@@ -1363,7 +1375,7 @@ void TileDataCollisionEditor::_polygons_changed() {
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->set_tooltip_text(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;
@@ -1375,7 +1387,7 @@ void TileDataCollisionEditor::_polygons_changed() {
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->set_tooltip_text(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;
@@ -1536,7 +1548,7 @@ TileDataCollisionEditor::TileDataCollisionEditor() {
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->set_tooltip_text(linear_velocity_editor->get_edited_property());
linear_velocity_editor->update_property();
add_child(linear_velocity_editor);
property_editors["linear_velocity"] = linear_velocity_editor;
@@ -1546,7 +1558,7 @@ TileDataCollisionEditor::TileDataCollisionEditor() {
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->set_tooltip_text(angular_velocity_editor->get_edited_property());
angular_velocity_editor->update_property();
add_child(angular_velocity_editor);
property_editors["angular_velocity"] = angular_velocity_editor;
@@ -2594,7 +2606,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());
+ terrain_set_property_editor->set_tooltip_text(terrain_set_property_editor->get_edited_property());
add_child(terrain_set_property_editor);
terrain_property_editor = memnew(EditorPropertyEnum);
@@ -2666,7 +2678,9 @@ void TileDataNavigationEditor::_tile_set_changed() {
void TileDataNavigationEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- polygon_editor->set_polygons_color(get_tree()->get_debug_navigation_color());
+#ifdef DEBUG_ENABLED
+ polygon_editor->set_polygons_color(NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color());
+#endif // DEBUG_ENABLED
} break;
}
}
@@ -2693,7 +2707,10 @@ void TileDataNavigationEditor::draw_over_tile(CanvasItem *p_canvas_item, Transfo
return;
}
- Color color = p_canvas_item->get_tree()->get_debug_navigation_color();
+ Color color = Color(0.5, 1.0, 1.0, 1.0);
+#ifdef DEBUG_ENABLED
+ color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
+#endif // DEBUG_ENABLED
if (p_selected) {
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index f9b8948d0a..c1560138b2 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -39,6 +39,8 @@
#include "scene/gui/control.h"
#include "scene/gui/label.h"
+class EditorUndoRedoManager;
+
class TileDataEditor : public VBoxContainer {
GDCLASS(TileDataEditor, VBoxContainer);
@@ -93,7 +95,7 @@ private:
bool multiple_polygon_mode = false;
bool use_undo_redo = true;
- UndoRedo *editor_undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> editor_undo_redo;
// UI
int hovered_polygon_index = -1;
@@ -214,7 +216,7 @@ private:
protected:
DummyObject *dummy_object = memnew(DummyObject);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
StringName type;
String property;
@@ -279,7 +281,7 @@ private:
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void _tile_set_changed() override;
@@ -314,7 +316,7 @@ class TileDataCollisionEditor : public TileDataDefaultEditor {
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void _tile_set_changed() override;
@@ -366,7 +368,7 @@ protected:
void _notification(int p_what);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
public:
virtual Control *get_toolbar() override { return toolbar; };
@@ -399,7 +401,7 @@ private:
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
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 1bf24a7393..01bef9b52b 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/camera_2d.h"
@@ -350,7 +351,7 @@ void TileMapEditorTilesPlugin::_update_atlas_view() {
tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id);
TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
- tile_atlas_control->update();
+ tile_atlas_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_update_scenes_collection_view() {
@@ -576,7 +577,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
_fix_invalid_tiles_in_tile_map_selection();
} break;
case DRAG_TYPE_BUCKET: {
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
@@ -623,7 +624,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
} 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()) {
+ if (tile_map_selection.has(tile_map->local_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) {
// Move the selection
_update_selection_pattern_from_tilemap_selection(); // Make sure the pattern is up to date before moving.
drag_type = DRAG_TYPE_MOVE;
@@ -672,7 +673,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
drag_type = DRAG_TYPE_BUCKET;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
@@ -751,14 +752,14 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
if (drag_type == DRAG_TYPE_PICK) {
// Draw the area being picked.
- Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
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) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_origin(tile_map->map_to_local(coords));
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);
}
@@ -766,7 +767,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
}
} else if (drag_type == DRAG_TYPE_SELECT) {
// Draw the area being selected.
- Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
RBSet<Vector2i> to_draw;
for (int x = rect.position.x; x < rect.get_end().x; x++) {
@@ -788,8 +789,8 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
for (const Vector2i &E : tile_map_selection) {
top_left = top_left.min(E);
}
- Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
- offset = tile_map->world_to_map(drag_last_mouse_pos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_local(top_left);
+ offset = tile_map->local_to_map(drag_last_mouse_pos - offset) - tile_map->local_to_map(drag_start_mouse_pos - offset);
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
for (int i = 0; i < selection_used_cells.size(); i++) {
@@ -802,7 +803,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Vector2 mouse_offset = (Vector2(tile_map_clipboard->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
TypedArray<Vector2i> clipboard_used_cells = tile_map_clipboard->get_used_cells();
for (int i = 0; i < clipboard_used_cells.size(); i++) {
- Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
+ Vector2i coords = tile_map->map_pattern(tile_map->local_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))) {
@@ -823,11 +824,11 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
}
} else if (drag_type == DRAG_TYPE_RECT) {
// Preview for a rect pattern.
- preview = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos), drag_erasing);
+ preview = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos), drag_erasing);
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a fill pattern.
- preview = _draw_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed(), erase_button->is_pressed());
+ preview = _draw_bucket_fill(tile_map->local_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed(), erase_button->is_pressed());
}
// Expand the grid if needed
@@ -860,7 +861,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
@@ -873,7 +874,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the preview.
for (const KeyValue<Vector2i, TileMapCell> &E : preview) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(E.key));
+ tile_xform.set_origin(tile_map->map_to_local(E.key));
tile_xform.set_scale(tile_set->get_tile_size());
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);
@@ -898,9 +899,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
bool transpose = tile_data->get_transpose();
if (transpose) {
- dest_rect.position = (tile_map->map_to_world(E.key) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
+ dest_rect.position = (tile_map->map_to_local(E.key) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
} else {
- dest_rect.position = (tile_map->map_to_world(E.key) - dest_rect.size / 2 - tile_offset);
+ dest_rect.position = (tile_map->map_to_local(E.key) - dest_rect.size / 2 - tile_offset);
}
dest_rect = xform.xform(dest_rect);
@@ -1011,7 +1012,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_st
// Paint the tiles on the tile map.
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));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(p_from_mouse_pos), tile_map->local_to_map(p_to_mouse_pos));
for (int i = 0; i < line.size(); i++) {
output.insert(line[i], _pick_random_tile(pattern));
}
@@ -1019,9 +1020,9 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_st
// Paint the pattern.
// If we paint several tiles, we virtually move the mouse as if it was in the center of the "brush"
Vector2 mouse_offset = (Vector2(pattern->get_size()) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
- Vector2i last_hovered_cell = tile_map->world_to_map(p_from_mouse_pos - mouse_offset);
- Vector2i new_hovered_cell = tile_map->world_to_map(p_to_mouse_pos - mouse_offset);
- Vector2i drag_start_cell = tile_map->world_to_map(p_start_drag_mouse_pos - mouse_offset);
+ Vector2i last_hovered_cell = tile_map->local_to_map(p_from_mouse_pos - mouse_offset);
+ Vector2i new_hovered_cell = tile_map->local_to_map(p_to_mouse_pos - mouse_offset);
+ Vector2i drag_start_cell = tile_map->local_to_map(p_start_drag_mouse_pos - mouse_offset);
TypedArray<Vector2i> used_cells = pattern->get_used_cells();
Vector2i offset = Vector2i(Math::posmod(drag_start_cell.x, pattern->get_size().x), Math::posmod(drag_start_cell.y, pattern->get_size().y)); // Note: no posmodv for Vector2i for now. Meh.s
@@ -1171,7 +1172,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto
TypedArray<Vector2i> to_check;
if (source_cell.source_id == TileSet::INVALID_SOURCE) {
Rect2i rect = tile_map->get_used_rect();
- if (rect.has_no_area()) {
+ if (!rect.has_area()) {
rect = Rect2i(p_coords, Vector2i(1, 1));
}
for (int x = boundaries.position.x; x < boundaries.get_end().x; x++) {
@@ -1240,7 +1241,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
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();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_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);
@@ -1286,8 +1287,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
}
// Get the offset from the mouse.
- Vector2i offset = drag_start_mouse_pos - tile_map->map_to_world(top_left);
- offset = tile_map->world_to_map(mpos - offset) - tile_map->world_to_map(drag_start_mouse_pos - offset);
+ Vector2i offset = drag_start_mouse_pos - tile_map->map_to_local(top_left);
+ offset = tile_map->local_to_map(mpos - offset) - tile_map->local_to_map(drag_start_mouse_pos - offset);
TypedArray<Vector2i> selection_used_cells = selection_pattern->get_used_cells();
@@ -1333,7 +1334,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
}
} break;
case DRAG_TYPE_PICK: {
- 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();
+ Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
int picked_source = -1;
@@ -1358,11 +1359,11 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
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);
+ TilesEditorPlugin::get_singleton()->set_sources_lists_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);
@@ -1393,7 +1394,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_RECT: {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
@@ -1417,7 +1418,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->create_action(TTR("Paste tiles"));
TypedArray<Vector2i> used_cells = tile_map_clipboard->get_used_cells();
for (int i = 0; i < used_cells.size(); i++) {
- Vector2i coords = tile_map->map_pattern(tile_map->world_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard);
+ Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard);
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i]));
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, coords, tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
}
@@ -1650,8 +1651,8 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern(
}
}
_update_source_display();
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
@@ -1735,7 +1736,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_mouse_exited() {
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
tile_set_dragging_selection = false;
- tile_atlas_control->update();
+ tile_atlas_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) {
@@ -1779,8 +1780,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
Ref<InputEventMouseButton> mb = p_event;
@@ -1840,7 +1841,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
}
tile_set_dragging_selection = false;
}
- tile_atlas_control->update();
+ tile_atlas_control->queue_redraw();
}
}
@@ -1894,7 +1895,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_mouse_exited() {
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
tile_set_dragging_selection = false;
- alternative_tiles_control->update();
+ alternative_tiles_control->queue_redraw();
}
void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) {
@@ -1937,8 +1938,8 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
Ref<InputEventMouseButton> mb = p_event;
@@ -1958,8 +1959,8 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In
}
_update_selection_pattern_from_tileset_tiles_selection();
}
- tile_atlas_control->update();
- alternative_tiles_control->update();
+ tile_atlas_control->queue_redraw();
+ alternative_tiles_control->queue_redraw();
}
}
@@ -2019,9 +2020,9 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
->connect("mouse_exited", callable_mp(this, &TileMapEditorTilesPlugin::_mouse_exited_viewport));
// --- Shortcuts ---
- 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/cut", TTR("Cut"), KeyModifierMask::CMD_OR_CTRL | Key::X);
+ ED_SHORTCUT("tiles_editor/copy", TTR("Copy"), KeyModifierMask::CMD_OR_CTRL | Key::C);
+ ED_SHORTCUT("tiles_editor/paste", TTR("Paste"), KeyModifierMask::CMD_OR_CTRL | Key::V);
ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), Key::ESCAPE);
ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE);
@@ -2049,7 +2050,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
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_tooltip(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle."));
+ paint_tool_button->set_tooltip_text(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);
@@ -2090,7 +2091,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
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_tooltip(TTR("Alternatively hold Ctrl with other tools to pick tile."));
+ picker_button->set_tooltip_text(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);
@@ -2099,7 +2100,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
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_tooltip(TTR("Alternatively use RMB to erase tiles."));
+ erase_button->set_tooltip_text(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);
@@ -2118,13 +2119,13 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
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->set_tooltip_text(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);
- scatter_label->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_label->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
scatter_label->set_text(TTR("Scattering:"));
tools_settings->add_child(scatter_label);
@@ -2132,7 +2133,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
scatter_spinbox->set_min(0.0);
scatter_spinbox->set_max(1000);
scatter_spinbox->set_step(0.001);
- scatter_spinbox->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_spinbox->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
scatter_spinbox->get_line_edit()->add_theme_constant_override("minimum_character_width", 4);
scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapEditorTilesPlugin::_on_scattering_spinbox_changed));
tools_settings->add_child(scatter_spinbox);
@@ -2177,7 +2178,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
source_sort_button = memnew(MenuButton);
source_sort_button->set_flat(true);
- source_sort_button->set_tooltip(TTR("Sort sources"));
+ source_sort_button->set_tooltip_text(TTR("Sort sources"));
PopupMenu *p = source_sort_button->get_popup();
p->connect("id_pressed", callable_mp(this, &TileMapEditorTilesPlugin::_set_source_sort));
@@ -2557,7 +2558,7 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i
TypedArray<Vector2i> to_check;
if (source_cell.source_id == TileSet::INVALID_SOURCE) {
Rect2i rect = tile_map->get_used_rect();
- if (rect.has_no_area()) {
+ if (!rect.has_area()) {
rect = Rect2i(p_coords, Vector2i(1, 1));
}
for (int x = boundaries.position.x; x < boundaries.get_end().x; x++) {
@@ -2639,7 +2640,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
switch (drag_type) {
case DRAG_TYPE_PICK: {
- Vector2i coords = tile_map->world_to_map(mpos);
+ Vector2i coords = tile_map->local_to_map(mpos);
TileMapCell cell = tile_map->get_cell(tile_map_layer, coords);
TileData *tile_data = nullptr;
@@ -2713,7 +2714,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
undo_redo->commit_action(false);
} break;
case DRAG_TYPE_LINE: {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
undo_redo->create_action(TTR("Paint terrain"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
@@ -2725,7 +2726,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_RECT: {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
undo_redo->create_action(TTR("Paint terrain"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
@@ -2835,7 +2836,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
switch (drag_type) {
case DRAG_TYPE_PAINT: {
if (selected_terrain_set >= 0) {
- HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ HashMap<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos), drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_modified.has(E.key)) {
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
@@ -2879,7 +2880,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_start_mouse_pos = mpos;
drag_modified.clear();
- Vector2i cell = tile_map->world_to_map(mpos);
+ Vector2i cell = tile_map->local_to_map(mpos);
HashMap<Vector2i, TileMapCell> to_draw = _draw_line(cell, cell, drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
@@ -2906,7 +2907,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_type = DRAG_TYPE_BUCKET;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_last_mouse_pos), tile_map->local_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
@@ -2970,10 +2971,10 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
if (drag_type == DRAG_TYPE_PICK) {
// Draw the area being picked.
- Vector2i coords = tile_map->world_to_map(drag_last_mouse_pos);
+ Vector2i coords = tile_map->local_to_map(drag_last_mouse_pos);
if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_origin(tile_map->map_to_local(coords));
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);
}
@@ -2981,15 +2982,15 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single tile.
- preview.insert(tile_map->world_to_map(drag_last_mouse_pos));
+ preview.insert(tile_map->local_to_map(drag_last_mouse_pos));
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == line_tool_button || drag_type == DRAG_TYPE_LINE) {
if (drag_type == DRAG_TYPE_NONE) {
// Preview for a single tile.
- preview.insert(tile_map->world_to_map(drag_last_mouse_pos));
+ preview.insert(tile_map->local_to_map(drag_last_mouse_pos));
} else if (drag_type == DRAG_TYPE_LINE) {
// Preview for a line.
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos));
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(drag_last_mouse_pos));
for (int i = 0; i < line.size(); i++) {
preview.insert(line[i]);
}
@@ -2998,8 +2999,8 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
} else if (drag_type == DRAG_TYPE_RECT) {
// Preview for a rect.
Rect2i rect;
- rect.set_position(tile_map->world_to_map(drag_start_mouse_pos));
- rect.set_end(tile_map->world_to_map(drag_last_mouse_pos));
+ rect.set_position(tile_map->local_to_map(drag_start_mouse_pos));
+ rect.set_end(tile_map->local_to_map(drag_last_mouse_pos));
rect = rect.abs();
HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
@@ -3011,7 +3012,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a fill.
- preview = _get_cells_for_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed());
+ preview = _get_cells_for_bucket_fill(tile_map->local_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed());
}
// Expand the grid if needed
@@ -3044,7 +3045,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
@@ -3057,7 +3058,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
// Draw the preview.
for (const Vector2i &E : preview) {
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(E));
+ tile_xform.set_origin(tile_map->map_to_local(E));
tile_xform.set_scale(tile_set->get_tile_size());
if (drag_erasing || erase_button->is_pressed()) {
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(0.0, 0.0, 0.0, 0.5), true);
@@ -3617,7 +3618,7 @@ void TileMapEditor::_tab_changed(int p_tab_id) {
}
// Graphical update.
- tabs_data[tabs_bar->get_current_tab()].panel->update();
+ tabs_data[tabs_bar->get_current_tab()].panel->queue_redraw();
CanvasItemEditor::get_singleton()->update_viewport();
}
@@ -3697,8 +3698,8 @@ void TileMapEditor::_update_layers_selection() {
}
void TileMapEditor::_move_tile_map_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);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
TileMap *tile_map = Object::cast_to<TileMap>(p_edited);
if (!tile_map) {
@@ -3837,7 +3838,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
// Draw the scaled tile.
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_origin(tile_map->map_to_local(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture);
}
@@ -3847,7 +3848,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
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]);
- Rect2 rect = Rect2(xform.xform(tile_map->map_to_world(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
+ Rect2 rect = Rect2(xform.xform(tile_map->map_to_local(coords)) - (icon_size * xform.get_scale() / 2), icon_size * xform.get_scale());
p_overlay->draw_texture_rect(missing_tile_texture, rect);
}
}
@@ -3860,10 +3861,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
// Determine the drawn area.
Size2 screen_size = p_overlay->get_size();
Rect2i screen_rect;
- screen_rect.position = tile_map->world_to_map(xform_inv.xform(Vector2()));
- screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
- screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
- screen_rect.expand_to(tile_map->world_to_map(xform_inv.xform(screen_size)));
+ screen_rect.position = tile_map->local_to_map(xform_inv.xform(Vector2()));
+ screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(Vector2(0, screen_size.height))));
+ screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(Vector2(screen_size.width, 0))));
+ screen_rect.expand_to(tile_map->local_to_map(xform_inv.xform(screen_size)));
screen_rect = screen_rect.grow(1);
Rect2i tilemap_used_rect = tile_map->get_used_rect();
@@ -3896,7 +3897,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Transform2D tile_xform;
- tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_origin(tile_map->map_to_local(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
@@ -3909,7 +3910,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
/*Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
- p_overlay->draw_string(font, xform.xform(tile_map->map_to_world(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y)));
+ p_overlay->draw_string(font, xform.xform(tile_map->map_to_local(Vector2(x, y))) + Vector2i(-tile_shape_size.x / 2, 0), vformat("%s", Vector2(x, y)));
}
}*/
@@ -4002,7 +4003,7 @@ TileMapEditor::TileMapEditor() {
layers_selection_button = memnew(OptionButton);
layers_selection_button->set_custom_minimum_size(Size2(200, 0));
layers_selection_button->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
- layers_selection_button->set_tooltip(TTR("TileMap Layers"));
+ layers_selection_button->set_tooltip_text(TTR("TileMap Layers"));
layers_selection_button->connect("item_selected", callable_mp(this, &TileMapEditor::_layers_selection_item_selected));
tile_map_toolbar->add_child(layers_selection_button);
@@ -4011,7 +4012,7 @@ TileMapEditor::TileMapEditor() {
toggle_highlight_selected_layer_button->set_toggle_mode(true);
toggle_highlight_selected_layer_button->set_pressed(true);
toggle_highlight_selected_layer_button->connect("pressed", callable_mp(this, &TileMapEditor::_update_layers_selection));
- toggle_highlight_selected_layer_button->set_tooltip(TTR("Highlight Selected TileMap Layer"));
+ toggle_highlight_selected_layer_button->set_tooltip_text(TTR("Highlight Selected TileMap Layer"));
tile_map_toolbar->add_child(toggle_highlight_selected_layer_button);
tile_map_toolbar->add_child(memnew(VSeparator));
@@ -4020,7 +4021,7 @@ TileMapEditor::TileMapEditor() {
toggle_grid_button = memnew(Button);
toggle_grid_button->set_flat(true);
toggle_grid_button->set_toggle_mode(true);
- toggle_grid_button->set_tooltip(TTR("Toggle grid visibility."));
+ toggle_grid_button->set_tooltip_text(TTR("Toggle grid visibility."));
toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditor::_on_grid_toggled));
tile_map_toolbar->add_child(toggle_grid_button);
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index 605fbe4823..9a47d8bbc4 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -47,7 +47,7 @@
#include "scene/gui/tab_bar.h"
#include "scene/gui/tree.h"
-class UndoRedo;
+class EditorUndoRedoManager;
class TileMapEditorPlugin : public Object {
public:
@@ -70,7 +70,7 @@ class TileMapEditorTilesPlugin : public TileMapEditorPlugin {
GDCLASS(TileMapEditorTilesPlugin, TileMapEditorPlugin);
private:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
ObjectID tile_map_id;
int tile_map_layer = -1;
virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
@@ -223,7 +223,7 @@ class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin {
GDCLASS(TileMapEditorTerrainsPlugin, TileMapEditorPlugin);
private:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
ObjectID tile_map_id;
int tile_map_layer = -1;
virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
@@ -317,7 +317,7 @@ class TileMapEditor : public VBoxContainer {
GDCLASS(TileMapEditor, VBoxContainer);
private:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool tileset_changed_needs_update = false;
ObjectID tile_map_id;
int tile_map_layer = -1;
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index 12e1615484..9e4c29fa79 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list, MouseButton p_mouse_button_index) {
if (p_mouse_button_index != MouseButton::RIGHT) {
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h
index 44de708898..511e442a10 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.h
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h
@@ -43,7 +43,7 @@ private:
int commited_actions_count = 0;
Ref<TileSet> tile_set;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
TileMapCell from;
TileMapCell to;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 6950f57a00..2aea020902 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -527,7 +527,7 @@ void TileSetAtlasSourceEditor::_update_tile_id_label() {
if (selection.size() == 1) {
TileSelection selected = selection.front()->get();
tool_tile_id_label->set_text(vformat("%d, %s, %d", tile_set_atlas_source_id, selected.tile, selected.alternative));
- tool_tile_id_label->set_tooltip(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative));
+ tool_tile_id_label->set_tooltip_text(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative));
tool_tile_id_label->show();
} else {
tool_tile_id_label->hide();
@@ -624,8 +624,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor);
tile_data_texture_offset_editor->hide();
tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset");
- tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["texture_offset"] = tile_data_texture_offset_editor;
}
@@ -634,8 +634,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_modulate_editor = memnew(TileDataDefaultEditor());
tile_data_modulate_editor->hide();
tile_data_modulate_editor->setup_property_editor(Variant::COLOR, "modulate", "", Color(1.0, 1.0, 1.0, 1.0));
- tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["modulate"] = tile_data_modulate_editor;
}
@@ -644,8 +644,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_z_index_editor = memnew(TileDataDefaultEditor());
tile_data_z_index_editor->hide();
tile_data_z_index_editor->setup_property_editor(Variant::INT, "z_index");
- tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["z_index"] = tile_data_z_index_editor;
}
@@ -654,8 +654,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor);
tile_data_y_sort_editor->hide();
tile_data_y_sort_editor->setup_property_editor(Variant::INT, "y_sort_origin");
- tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["y_sort_origin"] = tile_data_y_sort_editor;
}
@@ -665,8 +665,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor());
tile_data_occlusion_shape_editor->hide();
tile_data_occlusion_shape_editor->set_occlusion_layer(i);
- tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("occlusion_layer_%d", i)] = tile_data_occlusion_shape_editor;
}
}
@@ -680,8 +680,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
if (!tile_data_editors.has("terrain_set")) {
TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor);
tile_data_terrains_editor->hide();
- tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["terrain_set"] = tile_data_terrains_editor;
}
@@ -691,8 +691,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_probability_editor = memnew(TileDataDefaultEditor());
tile_data_probability_editor->hide();
tile_data_probability_editor->setup_property_editor(Variant::FLOAT, "probability", "", 1.0);
- tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors["probability"] = tile_data_probability_editor;
}
@@ -704,8 +704,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataCollisionEditor *tile_data_collision_editor = memnew(TileDataCollisionEditor());
tile_data_collision_editor->hide();
tile_data_collision_editor->set_physics_layer(i);
- tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("physics_layer_%d", i)] = tile_data_collision_editor;
}
}
@@ -722,8 +722,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataNavigationEditor *tile_data_navigation_editor = memnew(TileDataNavigationEditor());
tile_data_navigation_editor->hide();
tile_data_navigation_editor->set_navigation_layer(i);
- tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("navigation_layer_%d", i)] = tile_data_navigation_editor;
}
}
@@ -744,8 +744,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
TileDataDefaultEditor *tile_data_custom_data_editor = memnew(TileDataDefaultEditor());
tile_data_custom_data_editor->hide();
tile_data_custom_data_editor->setup_property_editor(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), tile_set->get_custom_data_layer_name(i));
- tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update));
- tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update));
+ tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
tile_data_editors[vformat("custom_data_%d", i)] = tile_data_custom_data_editor;
}
}
@@ -872,10 +872,10 @@ void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() {
void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() {
tile_data_editors_popup->call_deferred(SNAME("hide"));
_update_current_tile_data_editor();
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
}
void TileSetAtlasSourceEditor::_update_atlas_view() {
@@ -923,11 +923,11 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
tile_atlas_view->set_padding(Side::SIDE_RIGHT, texture_region_base_size_min);
// Redraw everything.
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
// Synchronize atlas view.
TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
@@ -961,14 +961,14 @@ void TileSetAtlasSourceEditor::_update_toolbar() {
void TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited() {
hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
}
void TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed() {
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
}
void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) {
@@ -983,11 +983,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Update only what's needed.
tile_set_changed_needs_update = false;
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
} else {
// Handle the event.
@@ -1132,11 +1132,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
}
// Redraw for the hovered tile.
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
}
@@ -1283,11 +1283,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Left click released.
_end_dragging();
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
} else if (mb->get_button_index() == MouseButton::RIGHT) {
// Right click pressed.
@@ -1298,11 +1298,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Right click released.
_end_dragging();
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
}
}
@@ -1872,23 +1872,23 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
if (current_tile_data_editor) {
current_tile_data_editor->forward_painting_alternatives_gui_input(tile_atlas_view, tile_set_atlas_source, p_event);
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
- tile_atlas_view->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
+ tile_atlas_view->queue_redraw();
return;
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
- if (Vector2(drag_start_mouse_pos).distance_to(tile_atlas_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
+ if (Vector2(drag_start_mouse_pos).distance_to(alternative_tiles_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
drag_type = DRAG_TYPE_NONE;
}
}
@@ -1896,8 +1896,6 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- drag_type = DRAG_TYPE_NONE;
-
Vector2 mouse_local_pos = alternative_tiles_control->get_local_mouse_position();
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
@@ -1919,40 +1917,44 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
if (mb->is_pressed()) {
drag_type = DRAG_TYPE_MAY_POPUP_MENU;
drag_start_mouse_pos = alternative_tiles_control->get_local_mouse_position();
- } else if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
- // Right click released and wasn't dragged too far
- Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
+ } else {
+ if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
+ // Right click released and wasn't dragged too far
+ Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
- selection.clear();
- TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
- selection.insert(selected);
- }
+ selection.clear();
+ TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ selection.insert(selected);
+ }
- _update_tile_inspector();
- _update_tile_id_label();
+ _update_tile_inspector();
+ _update_tile_id_label();
- if (selection.size() == 1) {
- selected = selection.front()->get();
- menu_option_coords = selected.tile;
- menu_option_alternative = selected.alternative;
- alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ if (selection.size() == 1) {
+ selected = selection.front()->get();
+ menu_option_coords = selected.tile;
+ menu_option_alternative = selected.alternative;
+ alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ }
}
+
+ drag_type = DRAG_TYPE_NONE;
}
}
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
}
}
void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() {
hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
- tile_atlas_control->update();
- tile_atlas_control_unscaled->update();
- alternative_tiles_control->update();
- alternative_tiles_control_unscaled->update();
+ tile_atlas_control->queue_redraw();
+ tile_atlas_control_unscaled->queue_redraw();
+ alternative_tiles_control->queue_redraw();
+ alternative_tiles_control_unscaled->queue_redraw();
}
void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
@@ -2058,14 +2060,16 @@ void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what)
}
void TileSetAtlasSourceEditor::_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);
- ERR_FAIL_COND(!undo_redo);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo.is_valid());
#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
- undo_redo->start_force_keep_in_merge_ends();
AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited);
if (tile_data_proxy) {
+ UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(tile_data_proxy).undo_redo;
+ internal_undo_redo->start_force_keep_in_merge_ends();
+
Vector<String> components = String(p_property).split("/", true, 2);
if (components.size() == 2 && components[1] == "polygons_count") {
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
@@ -2088,6 +2092,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
}
}
}
+ internal_undo_redo->end_force_keep_in_merge_ends();
}
TileSetAtlasSourceProxyObject *atlas_source_proxy = Object::cast_to<TileSetAtlasSourceProxyObject>(p_edited);
@@ -2095,6 +2100,9 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited();
ERR_FAIL_COND(!atlas_source);
+ UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(atlas_source).undo_redo;
+ internal_undo_redo->start_force_keep_in_merge_ends();
+
PackedVector2Array arr;
if (p_property == "texture") {
arr = atlas_source->get_tiles_to_be_removed_on_change(p_new_value, atlas_source->get_margins(), atlas_source->get_separation(), atlas_source->get_texture_region_size());
@@ -2121,8 +2129,8 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
}
}
}
+ internal_undo_redo->end_force_keep_in_merge_ends();
}
- undo_redo->end_force_keep_in_merge_ends();
#undef ADD_UNDO
}
@@ -2438,7 +2446,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tool_setup_atlas_source_button->set_toggle_mode(true);
tool_setup_atlas_source_button->set_pressed(true);
tool_setup_atlas_source_button->set_button_group(tools_button_group);
- tool_setup_atlas_source_button->set_tooltip(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing)."));
+ tool_setup_atlas_source_button->set_tooltip_text(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing)."));
toolbox->add_child(tool_setup_atlas_source_button);
tool_select_button = memnew(Button);
@@ -2446,14 +2454,14 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tool_select_button->set_toggle_mode(true);
tool_select_button->set_pressed(false);
tool_select_button->set_button_group(tools_button_group);
- tool_select_button->set_tooltip(TTR("Select tiles."));
+ tool_select_button->set_tooltip_text(TTR("Select tiles."));
toolbox->add_child(tool_select_button);
tool_paint_button = memnew(Button);
tool_paint_button->set_flat(true);
tool_paint_button->set_toggle_mode(true);
tool_paint_button->set_button_group(tools_button_group);
- tool_paint_button->set_tooltip(TTR("Paint properties."));
+ tool_paint_button->set_tooltip_text(TTR("Paint properties."));
toolbox->add_child(tool_paint_button);
// Tool settings.
@@ -2518,7 +2526,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control);
tile_atlas_control_unscaled = memnew(Control);
- tile_atlas_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
tile_atlas_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw));
tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control_unscaled, false);
tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
@@ -2535,7 +2542,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control);
alternative_tiles_control_unscaled = memnew(Control);
- alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw));
tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false);
alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index 738fe1044d..badb702e29 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -114,7 +114,7 @@ private:
TileSetAtlasSource *tile_set_atlas_source = nullptr;
int tile_set_atlas_source_id = TileSet::INVALID_SOURCE;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool tile_set_changed_needs_update = false;
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 81804710b4..dca17475e0 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
@@ -405,8 +406,8 @@ void TileSetEditor::_tab_changed(int p_tab_changed) {
}
void TileSetEditor::_move_tile_set_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);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
if (!tile_set) {
@@ -586,8 +587,8 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
void TileSetEditor::_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);
- ERR_FAIL_COND(!undo_redo);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
@@ -694,7 +695,7 @@ TileSetEditor::TileSetEditor() {
source_sort_button = memnew(MenuButton);
source_sort_button->set_flat(true);
- source_sort_button->set_tooltip(TTR("Sort sources"));
+ source_sort_button->set_tooltip_text(TTR("Sort sources"));
PopupMenu *p = source_sort_button->get_popup();
p->connect("id_pressed", callable_mp(this, &TileSetEditor::_set_source_sort));
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index c45240043e..3b9b80dac4 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -39,6 +39,8 @@
#include "tile_set_atlas_source_editor.h"
#include "tile_set_scenes_collection_source_editor.h"
+class EditorUndoRedoManager;
+
class TileSetEditor : public VBoxContainer {
GDCLASS(TileSetEditor, VBoxContainer);
@@ -58,7 +60,7 @@ private:
TileSetAtlasSourceEditor *tile_set_atlas_source_editor = nullptr;
TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
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;
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 77a583e522..0284b45c0f 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
@@ -97,7 +97,7 @@ private:
TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
int tile_set_source_id = -1;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool tile_set_scenes_collection_source_changed_needs_update = false;
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index b5134f6893..17115519e2 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -91,10 +91,10 @@ void TilesEditorPlugin::_thread() {
TypedArray<Vector2i> used_cells = tile_map->get_used_cells(0);
Rect2 encompassing_rect = Rect2();
- encompassing_rect.set_position(tile_map->map_to_world(used_cells[0]));
+ encompassing_rect.set_position(tile_map->map_to_local(used_cells[0]));
for (int i = 0; i < used_cells.size(); i++) {
Vector2i cell = used_cells[i];
- Vector2 world_pos = tile_map->map_to_world(cell);
+ Vector2 world_pos = tile_map->map_to_local(cell);
encompassing_rect.expand_to(world_pos);
// Texture.
@@ -116,7 +116,7 @@ void TilesEditorPlugin::_thread() {
// Add the viewport at the last moment to avoid rendering too early.
EditorNode::get_singleton()->add_child(viewport);
- RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Object::CONNECT_ONESHOT);
+ RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Object::CONNECT_ONE_SHOT);
pattern_preview_done.wait();
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index cf55465417..761140b2d5 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -30,25 +30,59 @@
#include "version_control_editor_plugin.h"
-#include "core/object/script_language.h"
+#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
+#include "core/os/time.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/filesystem_dock.h"
#include "scene/gui/separator.h"
+#define CHECK_PLUGIN_INITIALIZED() \
+ ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton(), "No VCS plugin is initialized. Select a Version Control Plugin from Project menu.");
+
VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr;
void VersionControlEditorPlugin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
+ ClassDB::bind_method(D_METHOD("_initialize_vcs"), &VersionControlEditorPlugin::_initialize_vcs);
+ ClassDB::bind_method(D_METHOD("_set_credentials"), &VersionControlEditorPlugin::_set_credentials);
+ ClassDB::bind_method(D_METHOD("_update_set_up_warning"), &VersionControlEditorPlugin::_update_set_up_warning);
+ ClassDB::bind_method(D_METHOD("_commit"), &VersionControlEditorPlugin::_commit);
+ ClassDB::bind_method(D_METHOD("_refresh_stage_area"), &VersionControlEditorPlugin::_refresh_stage_area);
+ ClassDB::bind_method(D_METHOD("_move_all"), &VersionControlEditorPlugin::_move_all);
+ ClassDB::bind_method(D_METHOD("_load_diff"), &VersionControlEditorPlugin::_load_diff);
+ ClassDB::bind_method(D_METHOD("_display_diff"), &VersionControlEditorPlugin::_display_diff);
+ ClassDB::bind_method(D_METHOD("_item_activated"), &VersionControlEditorPlugin::_item_activated);
+ ClassDB::bind_method(D_METHOD("_update_branch_create_button"), &VersionControlEditorPlugin::_update_branch_create_button);
+ ClassDB::bind_method(D_METHOD("_update_remote_create_button"), &VersionControlEditorPlugin::_update_remote_create_button);
+ ClassDB::bind_method(D_METHOD("_update_commit_button"), &VersionControlEditorPlugin::_update_commit_button);
+ ClassDB::bind_method(D_METHOD("_refresh_branch_list"), &VersionControlEditorPlugin::_refresh_branch_list);
+ ClassDB::bind_method(D_METHOD("_set_commit_list_size"), &VersionControlEditorPlugin::_set_commit_list_size);
+ ClassDB::bind_method(D_METHOD("_refresh_commit_list"), &VersionControlEditorPlugin::_refresh_commit_list);
+ ClassDB::bind_method(D_METHOD("_refresh_remote_list"), &VersionControlEditorPlugin::_refresh_remote_list);
+ ClassDB::bind_method(D_METHOD("_ssh_public_key_selected"), &VersionControlEditorPlugin::_ssh_public_key_selected);
+ ClassDB::bind_method(D_METHOD("_ssh_private_key_selected"), &VersionControlEditorPlugin::_ssh_private_key_selected);
+ ClassDB::bind_method(D_METHOD("_commit_message_gui_input"), &VersionControlEditorPlugin::_commit_message_gui_input);
+ ClassDB::bind_method(D_METHOD("_cell_button_pressed"), &VersionControlEditorPlugin::_cell_button_pressed);
+ ClassDB::bind_method(D_METHOD("_discard_all"), &VersionControlEditorPlugin::_discard_all);
+ ClassDB::bind_method(D_METHOD("_create_branch"), &VersionControlEditorPlugin::_create_branch);
+ ClassDB::bind_method(D_METHOD("_create_remote"), &VersionControlEditorPlugin::_create_remote);
+ ClassDB::bind_method(D_METHOD("_remove_branch"), &VersionControlEditorPlugin::_remove_branch);
+ ClassDB::bind_method(D_METHOD("_remove_remote"), &VersionControlEditorPlugin::_remove_remote);
+ ClassDB::bind_method(D_METHOD("_branch_item_selected"), &VersionControlEditorPlugin::_branch_item_selected);
+ ClassDB::bind_method(D_METHOD("_remote_selected"), &VersionControlEditorPlugin::_remote_selected);
+ ClassDB::bind_method(D_METHOD("_fetch"), &VersionControlEditorPlugin::_fetch);
+ ClassDB::bind_method(D_METHOD("_pull"), &VersionControlEditorPlugin::_pull);
+ ClassDB::bind_method(D_METHOD("_push"), &VersionControlEditorPlugin::_push);
+ ClassDB::bind_method(D_METHOD("_extra_option_selected"), &VersionControlEditorPlugin::_extra_option_selected);
+ ClassDB::bind_method(D_METHOD("_update_extra_options"), &VersionControlEditorPlugin::_update_extra_options);
+ ClassDB::bind_method(D_METHOD("_popup_branch_remove_confirm"), &VersionControlEditorPlugin::_popup_branch_remove_confirm);
+ ClassDB::bind_method(D_METHOD("_popup_remote_remove_confirm"), &VersionControlEditorPlugin::_popup_remote_remove_confirm);
+ ClassDB::bind_method(D_METHOD("_popup_file_dialog"), &VersionControlEditorPlugin::_popup_file_dialog);
- // Used to track the status of files in the staging area
- BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
+ ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
}
void VersionControlEditorPlugin::_create_vcs_metadata_files() {
@@ -56,21 +90,25 @@ void VersionControlEditorPlugin::_create_vcs_metadata_files() {
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);
-}
+void VersionControlEditorPlugin::_notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ String installed_plugin = GLOBAL_DEF("editor/version_control/plugin_name", "");
+ String project_path = GLOBAL_DEF("editor/version_control/project_path", OS::get_singleton()->get_resource_dir());
+ project_path_input->set_text(project_path);
+ bool has_autoload_enable = GLOBAL_DEF("editor/version_control/autoload_on_startup", false);
-void VersionControlEditorPlugin::_populate_available_vcs_names() {
- static bool called = false;
-
- if (!called) {
- List<StringName> available_addons = get_available_vcs_names();
- for (int i = 0; i < available_addons.size(); i++) {
- set_up_choice->add_item(available_addons[i]);
+ if (installed_plugin != "" && has_autoload_enable) {
+ if (_load_plugin(installed_plugin, project_path)) {
+ _set_credentials();
+ }
}
+ }
+}
- called = true;
+void VersionControlEditorPlugin::_populate_available_vcs_names() {
+ set_up_choice->clear();
+ for (int i = 0; i < available_plugins.size(); i++) {
+ set_up_choice->add_item(available_plugins[i]);
}
}
@@ -83,9 +121,8 @@ void VersionControlEditorPlugin::popup_vcs_metadata_dialog() {
}
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();
- if (available_addons.size() >= 1) {
+ fetch_available_vcs_plugin_names();
+ if (!available_plugins.is_empty()) {
Size2 popup_size = Size2(400, 100);
Size2 window_size = p_gui_base->get_viewport_rect().size;
popup_size.x = MIN(window_size.x * 0.5, popup_size.x);
@@ -95,213 +132,782 @@ void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_ba
set_up_dialog->popup_centered_clamped(popup_size * EDSCALE);
} else {
- EditorNode::get_singleton()->show_warning(TTR("No VCS addons are available."), TTR("Error"));
+ // TODO: Give info to user on how to fix this error.
+ EditorNode::get_singleton()->show_warning(TTR("No VCS plugins are available in the project. Install a VCS plugin to use VCS integration features."), TTR("Error"));
}
}
void VersionControlEditorPlugin::_initialize_vcs() {
- register_editor();
-
- ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active");
+ ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active.");
const int id = set_up_choice->get_selected_id();
- String selected_addon = set_up_choice->get_item_text(id);
+ String selected_plugin = set_up_choice->get_item_text(id);
- String path = ScriptServer::get_global_class_path(selected_addon);
- Ref<Script> script = ResourceLoader::load(path);
+ if (_load_plugin(selected_plugin, project_path_input->get_text())) {
+ ProjectSettings::get_singleton()->set("editor/version_control/autoload_on_startup", true);
+ ProjectSettings::get_singleton()->set("editor/version_control/plugin_name", selected_plugin);
+ ProjectSettings::get_singleton()->set("editor/version_control/project_path", project_path_input->get_text());
+ ProjectSettings::get_singleton()->save();
+ }
+}
- ERR_FAIL_COND_MSG(!script.is_valid(), "VCS Addon path is invalid");
+void VersionControlEditorPlugin::_set_vcs_ui_state(bool p_enabled) {
+ select_project_path_button->set_disabled(p_enabled);
+ set_up_dialog->get_ok_button()->set_disabled(!p_enabled);
+ project_path_input->set_editable(!p_enabled);
+ set_up_choice->set_disabled(p_enabled);
+ toggle_vcs_choice->set_pressed_no_signal(p_enabled);
+}
- EditorVCSInterface *vcs_interface = memnew(EditorVCSInterface);
- ScriptInstance *addon_script_instance = script->instance_create(vcs_interface);
+void VersionControlEditorPlugin::_set_credentials() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String username = set_up_username->get_text();
+ String password = set_up_password->get_text();
+ String ssh_public_key = set_up_ssh_public_key_path->get_text();
+ String ssh_private_key = set_up_ssh_private_key_path->get_text();
+ String ssh_passphrase = set_up_ssh_passphrase->get_text();
+
+ EditorVCSInterface::get_singleton()->set_credentials(
+ username,
+ password,
+ ssh_public_key,
+ ssh_private_key,
+ ssh_passphrase);
+
+ EditorSettings::get_singleton()->set_setting("version_control/username", username);
+ EditorSettings::get_singleton()->set_setting("version_control/ssh_public_key_path", ssh_public_key);
+ EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key);
+}
- ERR_FAIL_COND_MSG(!addon_script_instance, "Failed to create addon script instance.");
+bool VersionControlEditorPlugin::_load_plugin(String p_name, String p_project_path) {
+ Object *extension_instance = ClassDB::instantiate(p_name);
+ ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction.");
- // The addon is attached as a script to the VCS interface as a proxy end-point
- vcs_interface->set_script_and_instance(script, addon_script_instance);
+ EditorVCSInterface *vcs_plugin = Object::cast_to<EditorVCSInterface>(extension_instance);
+ ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat("Could not cast VCS extension instance to %s.", EditorVCSInterface::get_class_static()));
- EditorVCSInterface::set_singleton(vcs_interface);
- EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
+ String res_dir = project_path_input->get_text();
- String res_dir = OS::get_singleton()->get_resource_dir();
+ ERR_FAIL_COND_V_MSG(!vcs_plugin->initialize(res_dir), false, "Could not initialize " + p_name);
- ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton()->initialize(res_dir), "VCS was not initialized");
+ EditorVCSInterface::set_singleton(vcs_plugin);
+
+ register_editor();
+ EditorFileSystem::get_singleton()->connect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
_refresh_stage_area();
+ _refresh_commit_list();
+ _refresh_branch_list();
+ _refresh_remote_list();
+
+ return true;
}
-void VersionControlEditorPlugin::_send_commit_msg() {
- if (EditorVCSInterface::get_singleton()) {
- if (staged_files_count == 0) {
- commit_status->set_text(TTR("No files added to stage"));
- return;
+void VersionControlEditorPlugin::_update_set_up_warning(String p_new_text) {
+ bool empty_settings = set_up_username->get_text().strip_edges().is_empty() &&
+ set_up_password->get_text().is_empty() &&
+ set_up_ssh_public_key_path->get_text().strip_edges().is_empty() &&
+ set_up_ssh_private_key_path->get_text().strip_edges().is_empty() &&
+ set_up_ssh_passphrase->get_text().is_empty();
+
+ if (empty_settings) {
+ set_up_warning_text->add_theme_color_override(SNAME("font_color"), EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ set_up_warning_text->set_text(TTR("Remote settings are empty. VCS features that use the network may not work."));
+ } else {
+ set_up_warning_text->set_text("");
+ }
+}
+
+void VersionControlEditorPlugin::_refresh_branch_list() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ List<String> branch_list = EditorVCSInterface::get_singleton()->get_branch_list();
+ branch_select->clear();
+
+ branch_select->set_disabled(branch_list.is_empty());
+
+ String current_branch = EditorVCSInterface::get_singleton()->get_current_branch_name();
+
+ for (int i = 0; i < branch_list.size(); i++) {
+ branch_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("VcsBranches"), SNAME("EditorIcons")), branch_list[i], i);
+
+ if (branch_list[i] == current_branch) {
+ branch_select->select(i);
}
+ }
+}
- EditorVCSInterface::get_singleton()->commit(commit_message->get_text());
+String VersionControlEditorPlugin::_get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const {
+ return vformat(
+ "%s %s",
+ Time::get_singleton()->get_datetime_string_from_unix_time(p_unix_timestamp + p_offset_minutes * 60, true),
+ Time::get_singleton()->get_offset_string_from_offset_minutes(p_offset_minutes));
+}
- commit_message->set_text("");
- version_control_dock_button->set_pressed(false);
- } else {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu");
+void VersionControlEditorPlugin::_set_commit_list_size(int p_index) {
+ _refresh_commit_list();
+}
+
+void VersionControlEditorPlugin::_refresh_commit_list() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ commit_list->get_root()->clear_children();
+
+ List<EditorVCSInterface::Commit> commit_info_list = EditorVCSInterface::get_singleton()->get_previous_commits(commit_list_size_button->get_selected_metadata());
+
+ for (List<EditorVCSInterface::Commit>::Element *e = commit_info_list.front(); e; e = e->next()) {
+ EditorVCSInterface::Commit commit = e->get();
+ TreeItem *item = commit_list->create_item();
+
+ // Only display the first line of a commit message
+ int line_ending = commit.msg.find_char('\n');
+ String commit_display_msg = commit.msg.substr(0, line_ending);
+ String commit_date_string = _get_date_string_from(commit.unix_timestamp, commit.offset_minutes);
+
+ Dictionary meta_data;
+ meta_data[SNAME("commit_id")] = commit.id;
+ meta_data[SNAME("commit_title")] = commit_display_msg;
+ meta_data[SNAME("commit_subtitle")] = commit.msg.substr(line_ending).strip_edges();
+ meta_data[SNAME("commit_unix_timestamp")] = commit.unix_timestamp;
+ meta_data[SNAME("commit_author")] = commit.author;
+ meta_data[SNAME("commit_date_string")] = commit_date_string;
+
+ item->set_text(0, commit_display_msg);
+ item->set_text(1, commit.author.strip_edges());
+ item->set_metadata(0, meta_data);
+ }
+}
+
+void VersionControlEditorPlugin::_refresh_remote_list() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ List<String> remotes = EditorVCSInterface::get_singleton()->get_remotes();
+
+ String current_remote = remote_select->get_selected_metadata();
+ remote_select->clear();
+
+ remote_select->set_disabled(remotes.is_empty());
+
+ for (int i = 0; i < remotes.size(); i++) {
+ remote_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")), remotes[i], i);
+ remote_select->set_item_metadata(i, remotes[i]);
+
+ if (remotes[i] == current_remote) {
+ remote_select->select(i);
+ }
}
+}
+
+void VersionControlEditorPlugin::_commit() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String msg = commit_message->get_text().strip_edges();
+
+ ERR_FAIL_COND_MSG(msg.is_empty(), "No commit message was provided.");
+
+ EditorVCSInterface::get_singleton()->commit(msg);
+
+ version_control_dock_button->set_pressed(false);
+
+ commit_message->release_focus();
+ commit_button->release_focus();
+ commit_message->set_text("");
+
+ _refresh_stage_area();
+ _refresh_commit_list();
+ _refresh_branch_list();
+ _clear_diff();
+}
+
+void VersionControlEditorPlugin::_branch_item_selected(int p_index) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String branch_name = branch_select->get_item_text(p_index);
+ EditorVCSInterface::get_singleton()->checkout_branch(branch_name);
+
+ EditorFileSystem::get_singleton()->scan_changes();
+ ScriptEditor::get_singleton()->reload_scripts();
- _update_commit_status();
+ _refresh_branch_list();
+ _refresh_commit_list();
_refresh_stage_area();
- _clear_file_diff();
+ _clear_diff();
+
+ _update_opened_tabs();
+}
+
+void VersionControlEditorPlugin::_remote_selected(int p_index) {
+ _refresh_remote_list();
+}
+
+void VersionControlEditorPlugin::_ssh_public_key_selected(String p_path) {
+ set_up_ssh_public_key_path->set_text(p_path);
+}
+
+void VersionControlEditorPlugin::_ssh_private_key_selected(String p_path) {
+ set_up_ssh_private_key_path->set_text(p_path);
+}
+
+void VersionControlEditorPlugin::_popup_file_dialog(Variant p_file_dialog_variant) {
+ FileDialog *file_dialog = Object::cast_to<FileDialog>(p_file_dialog_variant);
+ ERR_FAIL_NULL(file_dialog);
+
+ file_dialog->popup_centered_ratio();
+}
+
+void VersionControlEditorPlugin::_create_branch() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String new_branch_name = branch_create_name_input->get_text().strip_edges();
+
+ EditorVCSInterface::get_singleton()->create_branch(new_branch_name);
+ EditorVCSInterface::get_singleton()->checkout_branch(new_branch_name);
+
+ branch_create_name_input->clear();
+ _refresh_branch_list();
+}
+
+void VersionControlEditorPlugin::_create_remote() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ String new_remote_name = remote_create_name_input->get_text().strip_edges();
+ String new_remote_url = remote_create_url_input->get_text().strip_edges();
+
+ EditorVCSInterface::get_singleton()->create_remote(new_remote_name, new_remote_url);
+
+ remote_create_name_input->clear();
+ remote_create_url_input->clear();
+ _refresh_remote_list();
+}
+
+void VersionControlEditorPlugin::_update_branch_create_button(String p_new_text) {
+ branch_create_ok->set_disabled(p_new_text.strip_edges().is_empty());
+}
+
+void VersionControlEditorPlugin::_update_remote_create_button(String p_new_text) {
+ remote_create_ok->set_disabled(p_new_text.strip_edges().is_empty());
+}
+
+int VersionControlEditorPlugin::_get_item_count(Tree *p_tree) {
+ if (!p_tree->get_root()) {
+ return 0;
+ }
+ return p_tree->get_root()->get_children().size();
}
void VersionControlEditorPlugin::_refresh_stage_area() {
- if (EditorVCSInterface::get_singleton()) {
- staged_files_count = 0;
- clear_stage_area();
-
- Dictionary modified_file_paths = EditorVCSInterface::get_singleton()->get_modified_files_data();
- String file_path;
- for (int i = 0; i < modified_file_paths.size(); i++) {
- file_path = modified_file_paths.get_key_at_index(i);
- TreeItem *found = stage_files->search_item_text(file_path, nullptr, true);
- if (!found) {
- ChangeType change_index = (ChangeType)(int)modified_file_paths.get_value_at_index(i);
- String change_text = file_path + " (" + change_type_to_strings[change_index] + ")";
- Color &change_color = change_type_to_color[change_index];
- TreeItem *new_item = stage_files->create_item(stage_files->get_root());
- new_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
- new_item->set_text(0, change_text);
- new_item->set_metadata(0, file_path);
- new_item->set_custom_color(0, change_color);
- new_item->set_checked(0, true);
- new_item->set_editable(0, true);
- } else {
- if (found->get_metadata(0) == diff_file_name->get_text()) {
- _refresh_file_diff();
- }
- }
- commit_status->set_text(TTR("New changes detected"));
+ CHECK_PLUGIN_INITIALIZED();
+
+ staged_files->get_root()->clear_children();
+ unstaged_files->get_root()->clear_children();
+
+ List<EditorVCSInterface::StatusFile> status_files = EditorVCSInterface::get_singleton()->get_modified_files_data();
+ for (List<EditorVCSInterface::StatusFile>::Element *E = status_files.front(); E; E = E->next()) {
+ EditorVCSInterface::StatusFile sf = E->get();
+ if (sf.area == EditorVCSInterface::TREE_AREA_STAGED) {
+ _add_new_item(staged_files, sf.file_path, sf.change_type);
+ } else if (sf.area == EditorVCSInterface::TREE_AREA_UNSTAGED) {
+ _add_new_item(unstaged_files, sf.file_path, sf.change_type);
}
+ }
+
+ staged_files->queue_redraw();
+ unstaged_files->queue_redraw();
+
+ int total_changes = status_files.size();
+ String commit_tab_title = TTR("Commit") + (total_changes > 0 ? " (" + itos(total_changes) + ")" : "");
+ version_commit_dock->set_name(commit_tab_title);
+}
+
+void VersionControlEditorPlugin::_discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ if (p_change == EditorVCSInterface::CHANGE_TYPE_NEW) {
+ Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ dir->remove(p_file_path);
} else {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu.");
+ CHECK_PLUGIN_INITIALIZED();
+ EditorVCSInterface::get_singleton()->discard_file(p_file_path);
}
+ // FIXIT: The project.godot file shows weird behaviour
+ EditorFileSystem::get_singleton()->update_file(p_file_path);
}
-void VersionControlEditorPlugin::_stage_selected() {
- if (!EditorVCSInterface::get_singleton()) {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu");
- return;
+void VersionControlEditorPlugin::_discard_all() {
+ TreeItem *file_entry = unstaged_files->get_root()->get_first_child();
+ while (file_entry) {
+ String file_path = file_entry->get_meta(SNAME("file_path"));
+ EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)file_entry->get_meta(SNAME("change_type"));
+ _discard_file(file_path, change);
+
+ file_entry = file_entry->get_next();
}
+ _refresh_stage_area();
+}
- staged_files_count = 0;
- TreeItem *root = stage_files->get_root();
- if (root) {
- TreeItem *file_entry = root->get_first_child();
- while (file_entry) {
- if (file_entry->is_checked(0)) {
- EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")));
- staged_files_count++;
- } else {
- EditorVCSInterface::get_singleton()->unstage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
- }
+void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change) {
+ String change_text = p_file_path + " (" + change_type_to_strings[p_change] + ")";
- file_entry = file_entry->get_next();
- }
+ TreeItem *new_item = p_tree->create_item();
+ new_item->set_text(0, change_text);
+ new_item->set_icon(0, change_type_to_icon[p_change]);
+ new_item->set_meta(SNAME("file_path"), p_file_path);
+ new_item->set_meta(SNAME("change_type"), p_change);
+ new_item->set_custom_color(0, change_type_to_color[p_change]);
+
+ new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("File"), SNAME("EditorIcons")), BUTTON_TYPE_OPEN, false, TTR("Open in editor"));
+ if (p_tree == unstaged_files) {
+ new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")), BUTTON_TYPE_DISCARD, false, TTR("Discard changes"));
}
+}
- _update_stage_status();
+void VersionControlEditorPlugin::_fetch() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->fetch(remote_select->get_selected_metadata());
+ _refresh_branch_list();
}
-void VersionControlEditorPlugin::_stage_all() {
- if (!EditorVCSInterface::get_singleton()) {
- WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu");
- return;
- }
+void VersionControlEditorPlugin::_pull() {
+ CHECK_PLUGIN_INITIALIZED();
- staged_files_count = 0;
- TreeItem *root = stage_files->get_root();
- if (root) {
- TreeItem *file_entry = root->get_first_child();
- while (file_entry) {
- EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0));
- file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")));
- file_entry->set_checked(0, true);
- staged_files_count++;
+ EditorVCSInterface::get_singleton()->pull(remote_select->get_selected_metadata());
+ _refresh_stage_area();
+ _refresh_branch_list();
+ _refresh_commit_list();
+ _clear_diff();
+ _update_opened_tabs();
+}
+
+void VersionControlEditorPlugin::_push() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), false);
+}
+
+void VersionControlEditorPlugin::_force_push() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), true);
+}
- file_entry = file_entry->get_next();
+void VersionControlEditorPlugin::_update_opened_tabs() {
+ Vector<EditorData::EditedScene> open_scenes = EditorNode::get_singleton()->get_editor_data().get_edited_scenes();
+ for (int i = 0; i < open_scenes.size(); i++) {
+ if (open_scenes[i].root == NULL) {
+ continue;
}
+ EditorNode::get_singleton()->reload_scene(open_scenes[i].path);
}
+}
+
+void VersionControlEditorPlugin::_move_all(Object *p_tree) {
+ Tree *tree = Object::cast_to<Tree>(p_tree);
- _update_stage_status();
+ TreeItem *file_entry = tree->get_root()->get_first_child();
+ while (file_entry) {
+ _move_item(tree, file_entry);
+
+ file_entry = file_entry->get_next();
+ }
+ _refresh_stage_area();
}
-void VersionControlEditorPlugin::_view_file_diff() {
+void VersionControlEditorPlugin::_load_diff(Object *p_tree) {
+ CHECK_PLUGIN_INITIALIZED();
+
version_control_dock_button->set_pressed(true);
- String file_path = stage_files->get_selected()->get_metadata(0);
+ Tree *tree = Object::cast_to<Tree>(p_tree);
+ if (tree == staged_files) {
+ show_commit_diff_header = false;
+ String file_path = tree->get_selected()->get_meta(SNAME("file_path"));
+ diff_title->set_text(TTR("Staged Changes"));
+ diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_STAGED);
+ } else if (tree == unstaged_files) {
+ show_commit_diff_header = false;
+ String file_path = tree->get_selected()->get_meta(SNAME("file_path"));
+ diff_title->set_text(TTR("Unstaged Changes"));
+ diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_UNSTAGED);
+ } else if (tree == commit_list) {
+ show_commit_diff_header = true;
+ Dictionary meta_data = tree->get_selected()->get_metadata(0);
+ String commit_id = meta_data[SNAME("commit_id")];
+ String commit_title = meta_data[SNAME("commit_title")];
+ diff_title->set_text(commit_title);
+ diff_content = EditorVCSInterface::get_singleton()->get_diff(commit_id, EditorVCSInterface::TREE_AREA_COMMIT);
+ }
+ _display_diff(0);
+}
+
+void VersionControlEditorPlugin::_clear_diff() {
+ diff->clear();
+ diff_content.clear();
+ diff_title->set_text("");
+}
- _display_file_diff(file_path);
+void VersionControlEditorPlugin::_item_activated(Object *p_tree) {
+ Tree *tree = Object::cast_to<Tree>(p_tree);
+
+ _move_item(tree, tree->get_selected());
+ _refresh_stage_area();
}
-void VersionControlEditorPlugin::_display_file_diff(String p_file_path) {
- Array diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path);
+void VersionControlEditorPlugin::_move_item(Tree *p_tree, TreeItem *p_item) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ if (p_tree == staged_files) {
+ EditorVCSInterface::get_singleton()->unstage_file(p_item->get_meta(SNAME("file_path")));
+ } else {
+ EditorVCSInterface::get_singleton()->stage_file(p_item->get_meta(SNAME("file_path")));
+ }
+}
- diff_file_name->set_text(p_file_path);
+void VersionControlEditorPlugin::_cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ String file_path = item->get_meta(SNAME("file_path"));
+ EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)item->get_meta(SNAME("change_type"));
+
+ if (p_id == BUTTON_TYPE_OPEN && change != EditorVCSInterface::CHANGE_TYPE_DELETED) {
+ Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (!dir->file_exists(file_path)) {
+ return;
+ }
+
+ file_path = "res://" + file_path;
+ if (ResourceLoader::get_resource_type(file_path) == "PackedScene") {
+ EditorNode::get_singleton()->open_request(file_path);
+ } else if (file_path.ends_with(".gd")) {
+ EditorNode::get_singleton()->load_resource(file_path);
+ ScriptEditor::get_singleton()->reload_scripts();
+ } else {
+ FileSystemDock::get_singleton()->navigate_to_path(file_path);
+ }
+
+ } else if (p_id == BUTTON_TYPE_DISCARD) {
+ _discard_file(file_path, change);
+ _refresh_stage_area();
+ }
+}
+
+void VersionControlEditorPlugin::_display_diff(int p_idx) {
+ DiffViewType diff_view = (DiffViewType)diff_view_type_select->get_selected();
diff->clear();
- diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("source"), SNAME("EditorFonts")));
+
+ if (show_commit_diff_header) {
+ Dictionary meta_data = commit_list->get_selected()->get_metadata(0);
+ String commit_id = meta_data[SNAME("commit_id")];
+ String commit_subtitle = meta_data[SNAME("commit_subtitle")];
+ String commit_date = meta_data[SNAME("commit_date")];
+ String commit_author = meta_data[SNAME("commit_author")];
+ String commit_date_string = meta_data[SNAME("commit_date_string")];
+
+ diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts")));
+ diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor")));
+ diff->add_text(TTR("Commit:") + " " + commit_id);
+ diff->add_newline();
+ diff->add_text(TTR("Author:") + " " + commit_author);
+ diff->add_newline();
+ diff->add_text(TTR("Date:") + " " + commit_date_string);
+ diff->add_newline();
+ if (!commit_subtitle.is_empty()) {
+ diff->add_text(TTR("Subtitle:") + " " + commit_subtitle);
+ diff->add_newline();
+ }
+ diff->add_newline();
+ diff->pop();
+ diff->pop();
+ }
+
for (int i = 0; i < diff_content.size(); i++) {
- Dictionary line_result = diff_content[i];
+ EditorVCSInterface::DiffFile diff_file = diff_content[i];
+
+ diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts")));
+ diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor")));
+ diff->add_text(TTR("File:") + " " + diff_file.new_file);
+ diff->pop();
+ diff->pop();
+
+ diff->add_newline();
+ diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts")));
+ for (int j = 0; j < diff_file.diff_hunks.size(); j++) {
+ EditorVCSInterface::DiffHunk hunk = diff_file.diff_hunks[j];
+
+ String old_start = String::num_int64(hunk.old_start);
+ String new_start = String::num_int64(hunk.new_start);
+ String old_lines = String::num_int64(hunk.old_lines);
+ String new_lines = String::num_int64(hunk.new_lines);
+
+ diff->append_text("[center]@@ " + old_start + "," + old_lines + " " + new_start + "," + new_lines + " @@[/center]");
+ diff->add_newline();
+
+ switch (diff_view) {
+ case DIFF_VIEW_TYPE_SPLIT:
+ _display_diff_split_view(hunk.diff_lines);
+ break;
+ case DIFF_VIEW_TYPE_UNIFIED:
+ _display_diff_unified_view(hunk.diff_lines);
+ break;
+ }
+ diff->add_newline();
+ diff->add_newline();
+ }
+ diff->pop();
+
+ diff->add_newline();
+ }
+}
+
+void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content) {
+ List<EditorVCSInterface::DiffLine> parsed_diff;
+
+ for (int i = 0; i < p_diff_content.size(); i++) {
+ EditorVCSInterface::DiffLine diff_line = p_diff_content[i];
+ String line = diff_line.content.strip_edges(false, true);
+
+ if (diff_line.new_line_no >= 0 && diff_line.old_line_no >= 0) {
+ diff_line.new_text = line;
+ diff_line.old_text = line;
+ parsed_diff.push_back(diff_line);
+ } else if (diff_line.new_line_no == -1) {
+ diff_line.new_text = "";
+ diff_line.old_text = line;
+ parsed_diff.push_back(diff_line);
+ } else if (diff_line.old_line_no == -1) {
+ int j = parsed_diff.size() - 1;
+ while (j >= 0 && parsed_diff[j].new_line_no == -1) {
+ j--;
+ }
+
+ if (j == parsed_diff.size() - 1) {
+ // no lines are modified
+ diff_line.new_text = line;
+ diff_line.old_text = "";
+ parsed_diff.push_back(diff_line);
+ } else {
+ // lines are modified
+ EditorVCSInterface::DiffLine modified_line = parsed_diff[j + 1];
+ modified_line.new_text = line;
+ modified_line.new_line_no = diff_line.new_line_no;
+ parsed_diff[j + 1] = modified_line;
+ }
+ }
+ }
+
+ diff->push_table(6);
+ /*
+ [cell]Old Line No[/cell]
+ [cell]prefix[/cell]
+ [cell]Old Code[/cell]
+
+ [cell]New Line No[/cell]
+ [cell]prefix[/cell]
+ [cell]New Line[/cell]
+ */
+
+ diff->set_table_column_expand(2, true);
+ diff->set_table_column_expand(5, true);
+
+ for (int i = 0; i < parsed_diff.size(); i++) {
+ EditorVCSInterface::DiffLine diff_line = parsed_diff[i];
+
+ bool has_change = diff_line.status != " ";
+ static const Color red = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ static const Color green = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
+ static const Color white = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label")) * Color(1, 1, 1, 0.6);
+
+ if (diff_line.old_line_no >= 0) {
+ diff->push_cell();
+ diff->push_indent(1);
+ diff->push_color(has_change ? red : white);
+ diff->add_text(String::num_int64(diff_line.old_line_no));
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? red : white);
+ diff->add_text(has_change ? "-|" : " |");
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? red : white);
+ diff->add_text(diff_line.old_text);
+ diff->pop();
+ diff->pop();
- if (line_result["status"] == "+") {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")));
- } else if (line_result["status"] == "-") {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")));
} else {
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label")));
+ diff->push_cell();
+ diff->pop();
+
+ diff->push_cell();
+ diff->pop();
+
+ diff->push_cell();
+ diff->pop();
}
- diff->add_text((String)line_result["content"]);
+ if (diff_line.new_line_no >= 0) {
+ diff->push_cell();
+ diff->push_indent(1);
+ diff->push_color(has_change ? green : white);
+ diff->add_text(String::num_int64(diff_line.new_line_no));
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? green : white);
+ diff->add_text(has_change ? "+|" : " |");
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(has_change ? green : white);
+ diff->add_text(diff_line.new_text);
+ diff->pop();
+ diff->pop();
+ } else {
+ diff->push_cell();
+ diff->pop();
- diff->pop();
+ diff->push_cell();
+ diff->pop();
+
+ diff->push_cell();
+ diff->pop();
+ }
}
diff->pop();
}
-void VersionControlEditorPlugin::_refresh_file_diff() {
- String open_file = diff_file_name->get_text();
- if (!open_file.is_empty()) {
- _display_file_diff(diff_file_name->get_text());
+void VersionControlEditorPlugin::_display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content) {
+ diff->push_table(4);
+ diff->set_table_column_expand(3, true);
+
+ /*
+ [cell]Old Line No[/cell]
+ [cell]New Line No[/cell]
+ [cell]status[/cell]
+ [cell]code[/cell]
+ */
+ for (int i = 0; i < p_diff_content.size(); i++) {
+ EditorVCSInterface::DiffLine diff_line = p_diff_content[i];
+ String line = diff_line.content.strip_edges(false, true);
+
+ Color color;
+ if (diff_line.status == "+") {
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
+ } else if (diff_line.status == "-") {
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ } else {
+ color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label"));
+ color *= Color(1, 1, 1, 0.6);
+ }
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->push_indent(1);
+ diff->add_text(diff_line.old_line_no >= 0 ? String::num_int64(diff_line.old_line_no) : "");
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->push_indent(1);
+ diff->add_text(diff_line.new_line_no >= 0 ? String::num_int64(diff_line.new_line_no) : "");
+ diff->pop();
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->add_text(diff_line.status != "" ? diff_line.status + "|" : " |");
+ diff->pop();
+ diff->pop();
+
+ diff->push_cell();
+ diff->push_color(color);
+ diff->add_text(line);
+ diff->pop();
+ diff->pop();
}
+
+ diff->pop();
}
-void VersionControlEditorPlugin::_clear_file_diff() {
- diff->clear();
- diff_file_name->set_text("");
- version_control_dock_button->set_pressed(false);
+void VersionControlEditorPlugin::_update_commit_button() {
+ commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty());
}
-void VersionControlEditorPlugin::_update_stage_status() {
- String status;
- if (staged_files_count == 1) {
- status = TTR("Stage contains 1 file");
- } else {
- status = vformat(TTR("Stage contains %d files"), staged_files_count);
+void VersionControlEditorPlugin::_remove_branch() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->remove_branch(branch_to_remove);
+ branch_to_remove.clear();
+
+ _refresh_branch_list();
+}
+
+void VersionControlEditorPlugin::_remove_remote() {
+ CHECK_PLUGIN_INITIALIZED();
+
+ EditorVCSInterface::get_singleton()->remove_remote(remote_to_remove);
+ remote_to_remove.clear();
+
+ _refresh_remote_list();
+}
+
+void VersionControlEditorPlugin::_extra_option_selected(int p_index) {
+ CHECK_PLUGIN_INITIALIZED();
+
+ switch ((ExtraOption)p_index) {
+ case EXTRA_OPTION_FORCE_PUSH:
+ _force_push();
+ break;
+ case EXTRA_OPTION_CREATE_BRANCH:
+ branch_create_confirm->popup_centered();
+ break;
+ case EXTRA_OPTION_CREATE_REMOTE:
+ remote_create_confirm->popup_centered();
+ break;
}
- commit_status->set_text(status);
}
-void VersionControlEditorPlugin::_update_commit_status() {
- String status;
- if (staged_files_count == 1) {
- status = TTR("Committed 1 file");
- } else {
- status = vformat(TTR("Committed %d files"), staged_files_count);
+void VersionControlEditorPlugin::_popup_branch_remove_confirm(int p_index) {
+ branch_to_remove = extra_options_remove_branch_list->get_item_text(p_index);
+
+ branch_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s branch?"), branch_to_remove));
+ branch_remove_confirm->popup_centered();
+}
+
+void VersionControlEditorPlugin::_popup_remote_remove_confirm(int p_index) {
+ remote_to_remove = extra_options_remove_remote_list->get_item_text(p_index);
+
+ remote_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s remote?"), branch_to_remove));
+ remote_remove_confirm->popup_centered();
+}
+
+void VersionControlEditorPlugin::_update_extra_options() {
+ extra_options_remove_branch_list->clear();
+ for (int i = 0; i < branch_select->get_item_count(); i++) {
+ extra_options_remove_branch_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("VcsBranches"), SNAME("EditorIcons")), branch_select->get_item_text(branch_select->get_item_id(i)));
+ }
+ extra_options_remove_branch_list->update_canvas_items();
+
+ extra_options_remove_remote_list->clear();
+ for (int i = 0; i < remote_select->get_item_count(); i++) {
+ extra_options_remove_remote_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")), remote_select->get_item_text(remote_select->get_item_id(i)));
}
- commit_status->set_text(status);
- staged_files_count = 0;
+ extra_options_remove_remote_list->update_canvas_items();
}
-void VersionControlEditorPlugin::_update_commit_button() {
- commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty());
+bool VersionControlEditorPlugin::_is_staging_area_empty() {
+ return staged_files->get_root()->get_child_count() == 0;
}
void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) {
@@ -316,266 +922,660 @@ void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent>
if (k.is_valid() && k->is_pressed()) {
if (ED_IS_SHORTCUT("version_control/commit", p_event)) {
- if (staged_files_count == 0) {
+ if (_is_staging_area_empty()) {
// Stage all files only when no files were previously staged.
- _stage_all();
+ _move_all(unstaged_files);
}
- _send_commit_msg();
+
+ _commit();
+
commit_message->accept_event();
- return;
}
}
}
-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(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);
+void VersionControlEditorPlugin::_toggle_vcs_integration(bool p_toggled) {
+ if (p_toggled) {
+ _initialize_vcs();
+ } else {
+ shut_down();
}
}
-void VersionControlEditorPlugin::fetch_available_vcs_addon_names() {
- List<StringName> global_classes;
- ScriptServer::get_global_class_list(&global_classes);
-
- for (int i = 0; i != global_classes.size(); i++) {
- String path = ScriptServer::get_global_class_path(global_classes[i]);
- Ref<Script> script = ResourceLoader::load(path);
- ERR_FAIL_COND(script.is_null());
+void VersionControlEditorPlugin::_project_path_selected(String p_project_path) {
+ project_path_input->set_text(p_project_path);
+}
- if (script->get_instance_base_type() == "EditorVCSInterface") {
- available_addons.push_back(global_classes[i]);
- }
- }
+void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() {
+ available_plugins.clear();
+ ClassDB::get_direct_inheriters_from_class(EditorVCSInterface::get_class_static(), &available_plugins);
}
-void VersionControlEditorPlugin::clear_stage_area() {
- stage_files->get_root()->clear_children();
+void VersionControlEditorPlugin::register_editor() {
+ EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
+
+ version_control_dock_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
+
+ _set_vcs_ui_state(true);
}
void VersionControlEditorPlugin::shut_down() {
- if (EditorVCSInterface::get_singleton()) {
- if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) {
- EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
- }
- EditorVCSInterface::get_singleton()->shut_down();
- memdelete(EditorVCSInterface::get_singleton());
- EditorVCSInterface::set_singleton(nullptr);
+ if (!EditorVCSInterface::get_singleton()) {
+ return;
+ }
- EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock);
- EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock);
+ if (EditorFileSystem::get_singleton()->is_connected(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) {
+ EditorFileSystem::get_singleton()->disconnect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
}
-}
-bool VersionControlEditorPlugin::is_vcs_initialized() const {
- return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->is_vcs_initialized() : false;
-}
+ EditorVCSInterface::get_singleton()->shut_down();
+ memdelete(EditorVCSInterface::get_singleton());
+ EditorVCSInterface::set_singleton(nullptr);
+
+ EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock);
+ EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock);
-const String VersionControlEditorPlugin::get_vcs_name() const {
- return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->get_vcs_name() : "";
+ _set_vcs_ui_state(false);
}
VersionControlEditorPlugin::VersionControlEditorPlugin() {
singleton = this;
- staged_files_count = 0;
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));
+ metadata_dialog->get_ok_button()->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files));
version_control_actions->add_child(metadata_dialog);
VBoxContainer *metadata_vb = memnew(VBoxContainer);
+ metadata_dialog->add_child(metadata_vb);
+
HBoxContainer *metadata_hb = memnew(HBoxContainer);
metadata_hb->set_custom_minimum_size(Size2(200, 20));
+ metadata_vb->add_child(metadata_hb);
+
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));
+ set_up_dialog->set_title(TTR("Local Settings"));
+ set_up_dialog->set_min_size(Size2(600, 100));
+ set_up_dialog->add_cancel_button("Cancel");
+ set_up_dialog->set_hide_on_ok(true);
version_control_actions->add_child(set_up_dialog);
- set_up_ok_button = set_up_dialog->get_ok_button();
- set_up_ok_button->set_text(TTR("Close"));
+ Button *set_up_apply_button = set_up_dialog->get_ok_button();
+ set_up_apply_button->set_text(TTR("Apply"));
+ set_up_apply_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_set_credentials));
set_up_vbc = memnew(VBoxContainer);
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(BoxContainer::SIZE_EXPAND_FILL);
+ HBoxContainer *set_up_hbc = memnew(HBoxContainer);
+ set_up_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_up_vbc->add_child(set_up_hbc);
- set_up_vcs_status = memnew(RichTextLabel);
- set_up_vcs_status->set_text(TTR("VCS Addon is not initialized"));
- set_up_vbc->add_child(set_up_vcs_status);
-
- set_up_vcs_label = memnew(Label);
- set_up_vcs_label->set_text(TTR("Version Control System"));
+ Label *set_up_vcs_label = memnew(Label);
+ set_up_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_vcs_label->set_text(TTR("VCS Provider"));
set_up_hbc->add_child(set_up_vcs_label);
set_up_choice = memnew(OptionButton);
- set_up_choice->set_h_size_flags(HBoxContainer::SIZE_EXPAND_FILL);
- set_up_choice->connect("item_selected", callable_mp(this, &VersionControlEditorPlugin::_selected_a_vcs));
+ set_up_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_up_hbc->add_child(set_up_choice);
- set_up_init_settings = nullptr;
-
- set_up_init_button = memnew(Button);
- set_up_init_button->set_text(TTR("Initialize"));
- set_up_init_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_initialize_vcs));
- set_up_vbc->add_child(set_up_init_button);
+ HBoxContainer *project_path_hbc = memnew(HBoxContainer);
+ project_path_hbc->set_h_size_flags(Control::SIZE_FILL);
+ set_up_vbc->add_child(project_path_hbc);
+
+ Label *project_path_label = memnew(Label);
+ project_path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ project_path_label->set_text(TTR("VCS Project Path"));
+ project_path_hbc->add_child(project_path_label);
+
+ project_path_input = memnew(LineEdit);
+ project_path_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ project_path_input->set_text(OS::get_singleton()->get_resource_dir());
+ project_path_hbc->add_child(project_path_input);
+
+ FileDialog *select_project_path_file_dialog = memnew(FileDialog);
+ select_project_path_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ select_project_path_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
+ select_project_path_file_dialog->set_show_hidden_files(true);
+ select_project_path_file_dialog->set_current_dir(OS::get_singleton()->get_resource_dir());
+ select_project_path_file_dialog->connect(SNAME("dir_selected"), callable_mp(this, &VersionControlEditorPlugin::_project_path_selected));
+ project_path_hbc->add_child(select_project_path_file_dialog);
+
+ select_project_path_button = memnew(Button);
+ select_project_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
+ select_project_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(select_project_path_file_dialog));
+ select_project_path_button->set_tooltip_text(TTR("Select VCS project path"));
+ project_path_hbc->add_child(select_project_path_button);
+
+ HBoxContainer *toggle_vcs_hbc = memnew(HBoxContainer);
+ toggle_vcs_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_vbc->add_child(toggle_vcs_hbc);
+
+ Label *toggle_vcs_label = memnew(Label);
+ toggle_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ toggle_vcs_label->set_text(TTR("Connect to VCS"));
+ toggle_vcs_hbc->add_child(toggle_vcs_label);
+
+ toggle_vcs_choice = memnew(CheckButton);
+ toggle_vcs_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ toggle_vcs_choice->set_pressed_no_signal(false);
+ toggle_vcs_choice->connect(SNAME("toggled"), callable_mp(this, &VersionControlEditorPlugin::_toggle_vcs_integration));
+ toggle_vcs_hbc->add_child(toggle_vcs_choice);
+
+ set_up_vbc->add_child(memnew(HSeparator));
+
+ set_up_settings_vbc = memnew(VBoxContainer);
+ set_up_settings_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ set_up_vbc->add_child(set_up_settings_vbc);
+
+ Label *remote_login = memnew(Label);
+ remote_login->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_login->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ remote_login->set_text(TTR("Remote Login"));
+ set_up_settings_vbc->add_child(remote_login);
+
+ HBoxContainer *set_up_username_input = memnew(HBoxContainer);
+ set_up_username_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_username_input);
+
+ Label *set_up_username_label = memnew(Label);
+ set_up_username_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_username_label->set_text(TTR("Username"));
+ set_up_username_input->add_child(set_up_username_label);
+
+ set_up_username = memnew(LineEdit);
+ set_up_username->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_username->set_text(EDITOR_DEF("version_control/username", ""));
+ set_up_username->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_username_input->add_child(set_up_username);
+
+ HBoxContainer *set_up_password_input = memnew(HBoxContainer);
+ set_up_password_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_password_input);
+
+ Label *set_up_password_label = memnew(Label);
+ set_up_password_label->set_text(TTR("Password"));
+ set_up_password_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_password_input->add_child(set_up_password_label);
+
+ set_up_password = memnew(LineEdit);
+ set_up_password->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_password->set_secret(true);
+ set_up_password->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_password_input->add_child(set_up_password);
+
+ HBoxContainer *set_up_ssh_public_key_input = memnew(HBoxContainer);
+ set_up_ssh_public_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_ssh_public_key_input);
+
+ Label *set_up_ssh_public_key_label = memnew(Label);
+ set_up_ssh_public_key_label->set_text(TTR("SSH Public Key Path"));
+ set_up_ssh_public_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_label);
+
+ HBoxContainer *set_up_ssh_public_key_input_hbc = memnew(HBoxContainer);
+ set_up_ssh_public_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_input_hbc);
+
+ set_up_ssh_public_key_path = memnew(LineEdit);
+ set_up_ssh_public_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_public_key_path->set_text(EDITOR_DEF("version_control/ssh_public_key_path", ""));
+ set_up_ssh_public_key_path->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_path);
+
+ set_up_ssh_public_key_file_dialog = memnew(FileDialog);
+ set_up_ssh_public_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ set_up_ssh_public_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ set_up_ssh_public_key_file_dialog->set_show_hidden_files(true);
+ // TODO: Make this start at the user's home folder
+ Ref<DirAccess> d = DirAccess::open(OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS));
+ d->change_dir("../");
+ set_up_ssh_public_key_file_dialog->set_current_dir(d->get_current_dir());
+ set_up_ssh_public_key_file_dialog->connect(SNAME("file_selected"), callable_mp(this, &VersionControlEditorPlugin::_ssh_public_key_selected));
+ set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_file_dialog);
+
+ Button *select_public_path_button = memnew(Button);
+ select_public_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
+ select_public_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_public_key_file_dialog));
+ select_public_path_button->set_tooltip_text(TTR("Select SSH public key path"));
+ set_up_ssh_public_key_input_hbc->add_child(select_public_path_button);
+
+ HBoxContainer *set_up_ssh_private_key_input = memnew(HBoxContainer);
+ set_up_ssh_private_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_ssh_private_key_input);
+
+ Label *set_up_ssh_private_key_label = memnew(Label);
+ set_up_ssh_private_key_label->set_text(TTR("SSH Private Key Path"));
+ set_up_ssh_private_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_label);
+
+ HBoxContainer *set_up_ssh_private_key_input_hbc = memnew(HBoxContainer);
+ set_up_ssh_private_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_input_hbc);
+
+ set_up_ssh_private_key_path = memnew(LineEdit);
+ set_up_ssh_private_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_private_key_path->set_text(EDITOR_DEF("version_control/ssh_private_key_path", ""));
+ set_up_ssh_private_key_path->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_path);
+
+ set_up_ssh_private_key_file_dialog = memnew(FileDialog);
+ set_up_ssh_private_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ set_up_ssh_private_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
+ set_up_ssh_private_key_file_dialog->set_show_hidden_files(true);
+ // TODO: Make this start at the user's home folder
+ set_up_ssh_private_key_file_dialog->set_current_dir(d->get_current_dir());
+ set_up_ssh_private_key_file_dialog->connect("file_selected", callable_mp(this, &VersionControlEditorPlugin::_ssh_private_key_selected));
+ set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_file_dialog);
+
+ Button *select_private_path_button = memnew(Button);
+ select_private_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
+ select_private_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_private_key_file_dialog));
+ select_private_path_button->set_tooltip_text(TTR("Select SSH private key path"));
+ set_up_ssh_private_key_input_hbc->add_child(select_private_path_button);
+
+ HBoxContainer *set_up_ssh_passphrase_input = memnew(HBoxContainer);
+ set_up_ssh_passphrase_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_ssh_passphrase_input);
+
+ Label *set_up_ssh_passphrase_label = memnew(Label);
+ set_up_ssh_passphrase_label->set_text(TTR("SSH Passphrase"));
+ set_up_ssh_passphrase_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase_label);
+
+ set_up_ssh_passphrase = memnew(LineEdit);
+ set_up_ssh_passphrase->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_ssh_passphrase->set_secret(true);
+ set_up_ssh_passphrase->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning));
+ set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase);
+
+ set_up_warning_text = memnew(Label);
+ set_up_warning_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ set_up_warning_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_settings_vbc->add_child(set_up_warning_text);
version_commit_dock = memnew(VBoxContainer);
version_commit_dock->set_visible(false);
+ version_commit_dock->set_name(TTR("Commit"));
- commit_box_vbc = memnew(VBoxContainer);
- 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);
+ VBoxContainer *unstage_area = memnew(VBoxContainer);
+ unstage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ unstage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ version_commit_dock->add_child(unstage_area);
- stage_tools = memnew(HSplitContainer);
- stage_tools->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED);
- commit_box_vbc->add_child(stage_tools);
+ HBoxContainer *unstage_title = memnew(HBoxContainer);
+ unstage_area->add_child(unstage_title);
- staging_area_label = memnew(Label);
- staging_area_label->set_h_size_flags(Label::SIZE_EXPAND_FILL);
- staging_area_label->set_text(TTR("Staging area"));
- stage_tools->add_child(staging_area_label);
+ Label *unstage_label = memnew(Label);
+ unstage_label->set_text(TTR("Unstaged Changes"));
+ unstage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ unstage_title->add_child(unstage_label);
refresh_button = memnew(Button);
- refresh_button->set_tooltip(TTR("Detect new changes"));
- refresh_button->set_text(TTR("Refresh"));
+ refresh_button->set_tooltip_text(TTR("Detect new changes"));
+ refresh_button->set_flat(true);
refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
- refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
- stage_tools->add_child(refresh_button);
-
- stage_files = memnew(Tree);
- stage_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL);
- stage_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL);
- stage_files->set_columns(1);
- stage_files->set_column_title(0, TTR("Changes"));
- stage_files->set_column_titles_visible(true);
- stage_files->set_allow_reselect(true);
- stage_files->set_allow_rmb_select(true);
- stage_files->set_select_mode(Tree::SelectMode::SELECT_MULTI);
- stage_files->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
- stage_files->connect("cell_selected", callable_mp(this, &VersionControlEditorPlugin::_view_file_diff));
- stage_files->create_item();
- stage_files->set_hide_root(true);
- commit_box_vbc->add_child(stage_files);
-
- change_type_to_strings[CHANGE_TYPE_NEW] = TTR("New");
- change_type_to_strings[CHANGE_TYPE_MODIFIED] = TTR("Modified");
- change_type_to_strings[CHANGE_TYPE_RENAMED] = TTR("Renamed");
- change_type_to_strings[CHANGE_TYPE_DELETED] = TTR("Deleted");
- change_type_to_strings[CHANGE_TYPE_TYPECHANGE] = TTR("Typechange");
-
- change_type_to_color[CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
- change_type_to_color[CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Editor"));
-
- stage_buttons = memnew(HSplitContainer);
- stage_buttons->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED);
- commit_box_vbc->add_child(stage_buttons);
-
- stage_selected_button = memnew(Button);
- stage_selected_button->set_h_size_flags(Button::SIZE_EXPAND_FILL);
- stage_selected_button->set_text(TTR("Stage Selected"));
- stage_selected_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_selected));
- stage_buttons->add_child(stage_selected_button);
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_commit_list));
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));
+ refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));
+ unstage_title->add_child(refresh_button);
+
+ discard_all_button = memnew(Button);
+ discard_all_button->set_tooltip_text(TTR("Discard all changes"));
+ discard_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
+ discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all));
+ discard_all_button->set_flat(true);
+ unstage_title->add_child(discard_all_button);
stage_all_button = memnew(Button);
- stage_all_button->set_text(TTR("Stage All"));
- stage_all_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_all));
- stage_buttons->add_child(stage_all_button);
-
- commit_box_vbc->add_child(memnew(HSeparator));
+ stage_all_button->set_flat(true);
+ stage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
+ stage_all_button->set_tooltip_text(TTR("Stage all changes"));
+ unstage_title->add_child(stage_all_button);
+
+ unstaged_files = memnew(Tree);
+ unstaged_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL);
+ unstaged_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL);
+ unstaged_files->set_select_mode(Tree::SELECT_ROW);
+ unstaged_files->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(unstaged_files));
+ unstaged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(unstaged_files));
+ unstaged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed));
+ unstaged_files->create_item();
+ unstaged_files->set_hide_root(true);
+ unstage_area->add_child(unstaged_files);
+
+ VBoxContainer *stage_area = memnew(VBoxContainer);
+ stage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ stage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ version_commit_dock->add_child(stage_area);
+
+ HBoxContainer *stage_title = memnew(HBoxContainer);
+ stage_area->add_child(stage_title);
+
+ Label *stage_label = memnew(Label);
+ stage_label->set_text(TTR("Staged Changes"));
+ stage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ stage_title->add_child(stage_label);
+
+ unstage_all_button = memnew(Button);
+ unstage_all_button->set_flat(true);
+ unstage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
+ unstage_all_button->set_tooltip_text(TTR("Unstage all changes"));
+ stage_title->add_child(unstage_all_button);
+
+ staged_files = memnew(Tree);
+ staged_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL);
+ staged_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL);
+ staged_files->set_select_mode(Tree::SELECT_ROW);
+ staged_files->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(staged_files));
+ staged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed));
+ staged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(staged_files));
+ staged_files->create_item();
+ staged_files->set_hide_root(true);
+ stage_area->add_child(staged_files);
+
+ // Editor crashes if bind is null
+ unstage_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(staged_files));
+ stage_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(unstaged_files));
+
+ version_commit_dock->add_child(memnew(HSeparator));
+
+ VBoxContainer *commit_area = memnew(VBoxContainer);
+ version_commit_dock->add_child(commit_area);
+
+ Label *commit_label = memnew(Label);
+ commit_label->set_text(TTR("Commit Message"));
+ commit_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ commit_area->add_child(commit_label);
commit_message = memnew(TextEdit);
commit_message->set_h_size_flags(Control::SIZE_EXPAND_FILL);
commit_message->set_h_grow_direction(Control::GrowDirection::GROW_DIRECTION_BEGIN);
commit_message->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END);
commit_message->set_custom_minimum_size(Size2(200, 100));
- commit_message->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
- 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"), KeyModifierMask::CMD | Key::ENTER);
+ commit_message->set_line_wrapping_mode(TextEdit::LINE_WRAPPING_BOUNDARY);
+ commit_message->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_commit_button));
+ commit_message->connect(SNAME("gui_input"), callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input));
+ commit_area->add_child(commit_message);
+
+ ED_SHORTCUT("version_control/commit", TTR("Commit"), KeyModifierMask::CMD_OR_CTRL | Key::ENTER);
commit_button = memnew(Button);
commit_button->set_text(TTR("Commit Changes"));
commit_button->set_disabled(true);
- commit_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_send_commit_msg));
- commit_box_vbc->add_child(commit_button);
-
- commit_status = memnew(Label);
- commit_status->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- commit_box_vbc->add_child(commit_status);
-
- version_control_dock = memnew(PanelContainer);
+ commit_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_commit));
+ commit_area->add_child(commit_button);
+
+ version_commit_dock->add_child(memnew(HSeparator));
+
+ HBoxContainer *commit_list_hbc = memnew(HBoxContainer);
+ version_commit_dock->add_child(commit_list_hbc);
+
+ Label *commit_list_label = memnew(Label);
+ commit_list_label->set_text(TTR("Commit List"));
+ commit_list_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ commit_list_hbc->add_child(commit_list_label);
+
+ commit_list_size_button = memnew(OptionButton);
+ commit_list_size_button->set_tooltip_text(TTR("Commit list size"));
+ commit_list_size_button->add_item("10");
+ commit_list_size_button->set_item_metadata(0, 10);
+ commit_list_size_button->add_item("20");
+ commit_list_size_button->set_item_metadata(1, 20);
+ commit_list_size_button->add_item("30");
+ commit_list_size_button->set_item_metadata(2, 30);
+ commit_list_size_button->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_set_commit_list_size));
+ commit_list_hbc->add_child(commit_list_size_button);
+
+ commit_list = memnew(Tree);
+ commit_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ commit_list->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END);
+ commit_list->set_custom_minimum_size(Size2(200, 160));
+ commit_list->create_item();
+ commit_list->set_hide_root(true);
+ commit_list->set_select_mode(Tree::SELECT_ROW);
+ commit_list->set_columns(2); // Commit msg, author
+ commit_list->set_column_custom_minimum_width(0, 40);
+ commit_list->set_column_custom_minimum_width(1, 20);
+ commit_list->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(commit_list));
+ version_commit_dock->add_child(commit_list);
+
+ version_commit_dock->add_child(memnew(HSeparator));
+
+ HBoxContainer *menu_bar = memnew(HBoxContainer);
+ menu_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ menu_bar->set_v_size_flags(Control::SIZE_FILL);
+ version_commit_dock->add_child(menu_bar);
+
+ branch_select = memnew(OptionButton);
+ branch_select->set_tooltip_text(TTR("Branches"));
+ branch_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_branch_item_selected));
+ branch_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));
+ menu_bar->add_child(branch_select);
+
+ branch_create_confirm = memnew(AcceptDialog);
+ branch_create_confirm->set_title(TTR("Create New Branch"));
+ branch_create_confirm->set_min_size(Size2(400, 100));
+ branch_create_confirm->set_hide_on_ok(true);
+ version_commit_dock->add_child(branch_create_confirm);
+
+ branch_create_ok = branch_create_confirm->get_ok_button();
+ branch_create_ok->set_text(TTR("Create"));
+ branch_create_ok->set_disabled(true);
+ branch_create_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_branch));
+
+ branch_remove_confirm = memnew(AcceptDialog);
+ branch_remove_confirm->set_title(TTR("Remove Branch"));
+ branch_remove_confirm->add_cancel_button();
+ version_commit_dock->add_child(branch_remove_confirm);
+
+ Button *branch_remove_ok = branch_remove_confirm->get_ok_button();
+ branch_remove_ok->set_text(TTR("Remove"));
+ branch_remove_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_remove_branch));
+
+ VBoxContainer *branch_create_vbc = memnew(VBoxContainer);
+ branch_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ branch_create_confirm->add_child(branch_create_vbc);
+
+ HBoxContainer *branch_create_hbc = memnew(HBoxContainer);
+ branch_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_create_vbc->add_child(branch_create_hbc);
+
+ Label *branch_create_name_label = memnew(Label);
+ branch_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_create_name_label->set_text(TTR("Branch Name"));
+ branch_create_hbc->add_child(branch_create_name_label);
+
+ branch_create_name_input = memnew(LineEdit);
+ branch_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ branch_create_name_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_branch_create_button));
+ branch_create_hbc->add_child(branch_create_name_input);
+
+ remote_select = memnew(OptionButton);
+ remote_select->set_tooltip_text(TTR("Remotes"));
+ remote_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_remote_selected));
+ remote_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));
+ menu_bar->add_child(remote_select);
+
+ remote_create_confirm = memnew(AcceptDialog);
+ remote_create_confirm->set_title(TTR("Create New Remote"));
+ remote_create_confirm->set_min_size(Size2(400, 100));
+ remote_create_confirm->set_hide_on_ok(true);
+ version_commit_dock->add_child(remote_create_confirm);
+
+ remote_create_ok = remote_create_confirm->get_ok_button();
+ remote_create_ok->set_text(TTR("Create"));
+ remote_create_ok->set_disabled(true);
+ remote_create_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_remote));
+
+ remote_remove_confirm = memnew(AcceptDialog);
+ remote_remove_confirm->set_title(TTR("Remove Remote"));
+ remote_remove_confirm->add_cancel_button();
+ version_commit_dock->add_child(remote_remove_confirm);
+
+ Button *remote_remove_ok = remote_remove_confirm->get_ok_button();
+ remote_remove_ok->set_text(TTR("Remove"));
+ remote_remove_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_remove_remote));
+
+ VBoxContainer *remote_create_vbc = memnew(VBoxContainer);
+ remote_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ remote_create_confirm->add_child(remote_create_vbc);
+
+ HBoxContainer *remote_create_name_hbc = memnew(HBoxContainer);
+ remote_create_name_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_vbc->add_child(remote_create_name_hbc);
+
+ Label *remote_create_name_label = memnew(Label);
+ remote_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_name_label->set_text(TTR("Remote Name"));
+ remote_create_name_hbc->add_child(remote_create_name_label);
+
+ remote_create_name_input = memnew(LineEdit);
+ remote_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_name_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button));
+ remote_create_name_hbc->add_child(remote_create_name_input);
+
+ HBoxContainer *remote_create_hbc = memnew(HBoxContainer);
+ remote_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_vbc->add_child(remote_create_hbc);
+
+ Label *remote_create_url_label = memnew(Label);
+ remote_create_url_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_url_label->set_text(TTR("Remote URL"));
+ remote_create_hbc->add_child(remote_create_url_label);
+
+ remote_create_url_input = memnew(LineEdit);
+ remote_create_url_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ remote_create_url_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button));
+ remote_create_hbc->add_child(remote_create_url_input);
+
+ fetch_button = memnew(Button);
+ fetch_button->set_flat(true);
+ fetch_button->set_tooltip_text(TTR("Fetch"));
+ fetch_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ fetch_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_fetch));
+ menu_bar->add_child(fetch_button);
+
+ pull_button = memnew(Button);
+ pull_button->set_flat(true);
+ pull_button->set_tooltip_text(TTR("Pull"));
+ pull_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
+ pull_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_pull));
+ menu_bar->add_child(pull_button);
+
+ push_button = memnew(Button);
+ push_button->set_flat(true);
+ push_button->set_tooltip_text(TTR("Push"));
+ push_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
+ push_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_push));
+ menu_bar->add_child(push_button);
+
+ extra_options = memnew(MenuButton);
+ extra_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ extra_options->get_popup()->connect(SNAME("about_to_popup"), callable_mp(this, &VersionControlEditorPlugin::_update_extra_options));
+ extra_options->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected));
+ menu_bar->add_child(extra_options);
+
+ extra_options->get_popup()->add_item(TTR("Force Push"), EXTRA_OPTION_FORCE_PUSH);
+ extra_options->get_popup()->add_separator();
+ extra_options->get_popup()->add_item(TTR("Create New Branch"), EXTRA_OPTION_CREATE_BRANCH);
+
+ extra_options_remove_branch_list = memnew(PopupMenu);
+ extra_options_remove_branch_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_branch_remove_confirm));
+ extra_options_remove_branch_list->set_name("Remove Branch");
+ extra_options->get_popup()->add_child(extra_options_remove_branch_list);
+ extra_options->get_popup()->add_submenu_item(TTR("Remove Branch"), "Remove Branch");
+
+ extra_options->get_popup()->add_separator();
+ extra_options->get_popup()->add_item(TTR("Create New Remote"), EXTRA_OPTION_CREATE_REMOTE);
+
+ extra_options_remove_remote_list = memnew(PopupMenu);
+ extra_options_remove_remote_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_remote_remove_confirm));
+ extra_options_remove_remote_list->set_name("Remove Remote");
+ extra_options->get_popup()->add_child(extra_options_remove_remote_list);
+ extra_options->get_popup()->add_submenu_item(TTR("Remove Remote"), "Remove Remote");
+
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_NEW] = TTR("New");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = TTR("Modified");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_RENAMED] = TTR("Renamed");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_DELETED] = TTR("Deleted");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = TTR("Typechange");
+ change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = TTR("Unmerged");
+
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Editor"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"));
+
+ version_control_dock = memnew(VBoxContainer);
version_control_dock->set_v_size_flags(Control::SIZE_EXPAND_FILL);
version_control_dock->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
version_control_dock->hide();
- diff_vbc = memnew(VBoxContainer);
- diff_vbc->set_h_size_flags(HBoxContainer::SIZE_FILL);
- diff_vbc->set_v_size_flags(HBoxContainer::SIZE_FILL);
- version_control_dock->add_child(diff_vbc);
+ HBoxContainer *diff_heading = memnew(HBoxContainer);
+ diff_heading->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ diff_heading->set_tooltip_text(TTR("View file diffs before committing them to the latest version"));
+ version_control_dock->add_child(diff_heading);
- diff_hbc = memnew(HBoxContainer);
- diff_hbc->set_h_size_flags(HBoxContainer::SIZE_FILL);
- diff_vbc->add_child(diff_hbc);
+ diff_title = memnew(Label);
+ diff_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ diff_heading->add_child(diff_title);
- diff_heading = memnew(Label);
- diff_heading->set_text(TTR("Status"));
- diff_heading->set_tooltip(TTR("View file diffs before committing them to the latest version"));
- diff_hbc->add_child(diff_heading);
+ Label *view = memnew(Label);
+ view->set_text(TTR("View:"));
+ diff_heading->add_child(view);
- 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_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
- diff_hbc->add_child(diff_file_name);
-
- diff_refresh_button = memnew(Button);
- diff_refresh_button->set_tooltip(TTR("Detect changes in file diff"));
- diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
- diff_refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_file_diff));
- diff_hbc->add_child(diff_refresh_button);
+ diff_view_type_select = memnew(OptionButton);
+ diff_view_type_select->add_item(TTR("Split"), DIFF_VIEW_TYPE_SPLIT);
+ diff_view_type_select->add_item(TTR("Unified"), DIFF_VIEW_TYPE_UNIFIED);
+ diff_view_type_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_display_diff));
+ diff_heading->add_child(diff_view_type_select);
diff = memnew(RichTextLabel);
diff->set_h_size_flags(TextEdit::SIZE_EXPAND_FILL);
diff->set_v_size_flags(TextEdit::SIZE_EXPAND_FILL);
+ diff->set_use_bbcode(true);
diff->set_selection_enabled(true);
- diff_vbc->add_child(diff);
+ version_control_dock->add_child(diff);
+
+ _update_set_up_warning("");
}
VersionControlEditorPlugin::~VersionControlEditorPlugin() {
shut_down();
- memdelete(version_control_dock);
memdelete(version_commit_dock);
+ memdelete(version_control_dock);
memdelete(version_control_actions);
}
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index fa721268ba..3340384a92 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -33,9 +33,12 @@
#include "editor/editor_plugin.h"
#include "editor/editor_vcs_interface.h"
-#include "scene/gui/box_container.h"
+#include "scene/gui/check_button.h"
+#include "scene/gui/container.h"
+#include "scene/gui/file_dialog.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/rich_text_label.h"
-#include "scene/gui/split_container.h"
+#include "scene/gui/tab_container.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/tree.h"
@@ -43,79 +46,154 @@ class VersionControlEditorPlugin : public EditorPlugin {
GDCLASS(VersionControlEditorPlugin, EditorPlugin)
public:
- enum ChangeType {
- CHANGE_TYPE_NEW = 0,
- CHANGE_TYPE_MODIFIED = 1,
- CHANGE_TYPE_RENAMED = 2,
- CHANGE_TYPE_DELETED = 3,
- CHANGE_TYPE_TYPECHANGE = 4
+ enum ButtonType {
+ BUTTON_TYPE_OPEN = 0,
+ BUTTON_TYPE_DISCARD = 1,
+ };
+
+ enum DiffViewType {
+ DIFF_VIEW_TYPE_SPLIT = 0,
+ DIFF_VIEW_TYPE_UNIFIED = 1,
+ };
+
+ enum ExtraOption {
+ EXTRA_OPTION_FORCE_PUSH,
+ EXTRA_OPTION_CREATE_BRANCH,
+ EXTRA_OPTION_CREATE_REMOTE,
};
private:
static VersionControlEditorPlugin *singleton;
- int staged_files_count;
- List<StringName> available_addons;
+ List<StringName> available_plugins;
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;
+ CheckButton *toggle_vcs_choice = 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;
+ LineEdit *project_path_input = nullptr;
+ Button *select_project_path_button = nullptr;
+ VBoxContainer *set_up_vbc = nullptr;
+ VBoxContainer *set_up_settings_vbc = nullptr;
+ LineEdit *set_up_username = nullptr;
+ LineEdit *set_up_password = nullptr;
+ LineEdit *set_up_ssh_public_key_path = nullptr;
+ LineEdit *set_up_ssh_private_key_path = nullptr;
+ LineEdit *set_up_ssh_passphrase = nullptr;
+ FileDialog *set_up_ssh_public_key_file_dialog = nullptr;
+ FileDialog *set_up_ssh_private_key_file_dialog = nullptr;
+ Label *set_up_warning_text = nullptr;
+
+ OptionButton *commit_list_size_button = nullptr;
+
+ AcceptDialog *branch_create_confirm = nullptr;
+ LineEdit *branch_create_name_input = nullptr;
+ Button *branch_create_ok = nullptr;
+
+ AcceptDialog *remote_create_confirm = nullptr;
+ LineEdit *remote_create_name_input = nullptr;
+ LineEdit *remote_create_url_input = nullptr;
+ Button *remote_create_ok = nullptr;
+
+ HashMap<EditorVCSInterface::ChangeType, String> change_type_to_strings;
+ HashMap<EditorVCSInterface::ChangeType, Color> change_type_to_color;
+ HashMap<EditorVCSInterface::ChangeType, Ref<Texture>> change_type_to_icon;
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;
+ Tree *staged_files = nullptr;
+ Tree *unstaged_files = nullptr;
+ Tree *commit_list = nullptr;
+
+ OptionButton *branch_select = nullptr;
+ Button *branch_remove_button = nullptr;
+ AcceptDialog *branch_remove_confirm = nullptr;
+
+ Button *fetch_button = nullptr;
+ Button *pull_button = nullptr;
+ Button *push_button = nullptr;
+ OptionButton *remote_select = nullptr;
+ Button *remote_remove_button = nullptr;
+ AcceptDialog *remote_remove_confirm = nullptr;
+ MenuButton *extra_options = nullptr;
+ PopupMenu *extra_options_remove_branch_list = nullptr;
+ PopupMenu *extra_options_remove_remote_list = nullptr;
+
+ String branch_to_remove;
+ String remote_to_remove;
+
Button *stage_all_button = nullptr;
- Button *stage_selected_button = nullptr;
+ Button *unstage_all_button = nullptr;
+ Button *discard_all_button = nullptr;
Button *refresh_button = nullptr;
TextEdit *commit_message = nullptr;
Button *commit_button = nullptr;
- Label *commit_status = nullptr;
- PanelContainer *version_control_dock = nullptr;
+ VBoxContainer *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;
+ Label *diff_title = nullptr;
RichTextLabel *diff = nullptr;
+ OptionButton *diff_view_type_select = nullptr;
+ bool show_commit_diff_header = false;
+ List<EditorVCSInterface::DiffFile> diff_content;
- void _populate_available_vcs_names();
- void _create_vcs_metadata_files();
- void _selected_a_vcs(int p_id);
+ void _notification(int p_what);
void _initialize_vcs();
- void _send_commit_msg();
+ void _set_vcs_ui_state(bool p_enabled);
+ void _set_credentials();
+ void _ssh_public_key_selected(String p_path);
+ void _ssh_private_key_selected(String p_path);
+ void _populate_available_vcs_names();
+ void _update_remotes_list();
+ void _update_set_up_warning(String p_new_text);
+ void _update_opened_tabs();
+ void _update_extra_options();
+
+ bool _load_plugin(String p_name, String p_project_path);
+
+ void _pull();
+ void _push();
+ void _force_push();
+ void _fetch();
+ void _commit();
+ void _discard_all();
void _refresh_stage_area();
- void _stage_selected();
- void _stage_all();
- void _view_file_diff();
- void _display_file_diff(String p_file_path);
- void _refresh_file_diff();
- void _clear_file_diff();
- void _update_stage_status();
- void _update_commit_status();
+ void _refresh_branch_list();
+ void _set_commit_list_size(int p_index);
+ void _refresh_commit_list();
+ void _refresh_remote_list();
+ void _display_diff(int p_idx);
+ void _move_all(Object *p_tree);
+ void _load_diff(Object *p_tree);
+ void _clear_diff();
+ int _get_item_count(Tree *p_tree);
+ void _item_activated(Object *p_tree);
+ void _create_branch();
+ void _create_remote();
+ void _update_branch_create_button(String p_new_text);
+ void _update_remote_create_button(String p_new_text);
+ void _branch_item_selected(int p_index);
+ void _remote_selected(int p_index);
+ void _remove_branch();
+ void _remove_remote();
+ void _popup_branch_remove_confirm(int p_index);
+ void _popup_remote_remove_confirm(int p_index);
+ void _move_item(Tree *p_tree, TreeItem *p_itme);
+ void _display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content);
+ void _display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content);
+ void _discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change);
+ void _cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index);
+ void _add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change);
void _update_commit_button();
void _commit_message_gui_input(const Ref<InputEvent> &p_event);
+ void _extra_option_selected(int p_index);
+ bool _is_staging_area_empty();
+ String _get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const;
+ void _create_vcs_metadata_files();
+ void _popup_file_dialog(Variant p_file_dialog_variant);
+ void _toggle_vcs_integration(bool p_toggled);
+ void _project_path_selected(String p_project_path);
friend class EditorVCSInterface;
@@ -127,25 +205,15 @@ public:
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; }
PopupMenu *get_version_control_actions_panel() const { return version_control_actions; }
- VBoxContainer *get_version_commit_dock() const { return version_commit_dock; }
- PanelContainer *get_version_control_dock() const { return version_control_dock; }
-
- List<StringName> get_available_vcs_names() const { return available_addons; }
- bool is_vcs_initialized() const;
- const String get_vcs_name() const;
void register_editor();
- void fetch_available_vcs_addon_names();
- void clear_stage_area();
+ void fetch_available_vcs_plugin_names();
void shut_down();
VersionControlEditorPlugin();
~VersionControlEditorPlugin();
};
-VARIANT_ENUM_CAST(VersionControlEditorPlugin::ChangeType);
-
#endif // VERSION_CONTROL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 4a144bc391..27c34ab72e 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/shader_editor_plugin.h"
#include "scene/animation/animation_player.h"
@@ -110,7 +111,7 @@ void VisualShaderGraphPlugin::_bind_methods() {
ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);
ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);
ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);
- ClassDB::bind_method("set_uniform_name", &VisualShaderGraphPlugin::set_uniform_name);
+ ClassDB::bind_method("set_parameter_name", &VisualShaderGraphPlugin::set_parameter_name);
ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression);
ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve);
ClassDB::bind_method("update_curve_xyz", &VisualShaderGraphPlugin::update_curve_xyz);
@@ -222,9 +223,9 @@ void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_
}
}
-void VisualShaderGraphPlugin::set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {
- if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].uniform_name != nullptr) {
- links[p_node_id].uniform_name->set_text(p_name);
+void VisualShaderGraphPlugin::set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {
+ if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].parameter_name != nullptr) {
+ links[p_node_id].parameter_name->set_text(p_name);
}
}
@@ -289,9 +290,9 @@ void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, int p_index,
links[p_node_id].curve_editors[p_index] = p_curve_editor;
}
-void VisualShaderGraphPlugin::update_uniform_refs() {
+void VisualShaderGraphPlugin::update_parameter_refs() {
for (KeyValue<int, Link> &E : links) {
- VisualShaderNodeUniformRef *ref = Object::cast_to<VisualShaderNodeUniformRef>(E.value.visual_node);
+ VisualShaderNodeParameterRef *ref = Object::cast_to<VisualShaderNodeParameterRef>(E.value.visual_node);
if (ref) {
remove_node(E.value.type, E.key);
add_node(E.value.type, E.key);
@@ -333,8 +334,8 @@ void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, Te
links[p_node_id].output_ports.insert(p_port, { p_button });
}
-void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_uniform_name) {
- links[p_node_id].uniform_name = p_uniform_name;
+void VisualShaderGraphPlugin::register_parameter_name(int p_node_id, LineEdit *p_parameter_name) {
+ links[p_node_id].parameter_name = p_parameter_name;
}
void VisualShaderGraphPlugin::update_theme() {
@@ -465,29 +466,29 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
node->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
}
- Ref<VisualShaderNodeUniformRef> uniform_ref = vsnode;
- if (uniform_ref.is_valid()) {
- uniform_ref->set_shader_rid(visual_shader->get_rid());
- uniform_ref->update_uniform_type();
+ Ref<VisualShaderNodeParameterRef> parameter_ref = vsnode;
+ if (parameter_ref.is_valid()) {
+ parameter_ref->set_shader_rid(visual_shader->get_rid());
+ parameter_ref->update_parameter_type();
}
- Ref<VisualShaderNodeUniform> uniform = vsnode;
+ Ref<VisualShaderNodeParameter> parameter = vsnode;
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());
- uniform_name->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_uniform_line_edit_changed).bind(p_id));
- uniform_name->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_uniform_line_edit_focus_out).bind(uniform_name, p_id));
+ if (parameter.is_valid()) {
+ LineEdit *parameter_name = memnew(LineEdit);
+ register_parameter_name(p_id, parameter_name);
+ parameter_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ parameter_name->set_text(parameter->get_parameter_name());
+ parameter_name->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_changed).bind(p_id));
+ parameter_name->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_focus_out).bind(parameter_name, p_id));
if (vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
hb = memnew(HBoxContainer);
- hb->add_child(uniform_name);
+ hb->add_child(parameter_name);
node->add_child(hb);
} else {
- node->add_child(uniform_name);
+ node->add_child(parameter_name);
}
port_offset++;
}
@@ -753,7 +754,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->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
} else {
@@ -780,7 +781,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (is_group) {
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->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -1408,13 +1409,13 @@ void VisualShaderEditor::_update_options_menu() {
}
}
- Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(vsn.ptr());
- if (uniform_ref.is_valid()) {
+ Ref<VisualShaderNodeParameterRef> parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn.ptr());
+ if (parameter_ref.is_valid()) {
check_result = -1;
if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
- for (int j = 0; j < uniform_ref->get_uniforms_count(); j++) {
- if (visual_shader->is_port_types_compatible(uniform_ref->get_port_type_by_index(j), members_input_port_type)) {
+ for (int j = 0; j < parameter_ref->get_parameters_count(); j++) {
+ if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(j), members_input_port_type)) {
check_result = 1;
break;
}
@@ -1611,66 +1612,66 @@ void VisualShaderEditor::_update_created_node(GraphNode *node) {
node->add_theme_color_override("resizer_color", c);
}
-void VisualShaderEditor::_update_uniforms(bool p_update_refs) {
- VisualShaderNodeUniformRef::clear_uniforms(visual_shader->get_rid());
+void VisualShaderEditor::_update_parameters(bool p_update_refs) {
+ VisualShaderNodeParameterRef::clear_parameters(visual_shader->get_rid());
for (int t = 0; t < VisualShader::TYPE_MAX; t++) {
Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t);
for (int i = 0; i < tnodes.size(); i++) {
Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]);
- Ref<VisualShaderNodeUniform> uniform = vsnode;
-
- 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;
-
- VisualShaderNodeUniformRef::UniformType uniform_type;
- if (float_uniform.is_valid()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_FLOAT;
- } else if (int_uniform.is_valid()) {
- 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_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()) {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_COLOR;
+ Ref<VisualShaderNodeParameter> parameter = vsnode;
+
+ if (parameter.is_valid()) {
+ Ref<VisualShaderNodeFloatParameter> float_parameter = vsnode;
+ Ref<VisualShaderNodeIntParameter> int_parameter = vsnode;
+ Ref<VisualShaderNodeVec2Parameter> vec2_parameter = vsnode;
+ Ref<VisualShaderNodeVec3Parameter> vec3_parameter = vsnode;
+ Ref<VisualShaderNodeVec4Parameter> vec4_parameter = vsnode;
+ Ref<VisualShaderNodeColorParameter> color_parameter = vsnode;
+ Ref<VisualShaderNodeBooleanParameter> boolean_parameter = vsnode;
+ Ref<VisualShaderNodeTransformParameter> transform_parameter = vsnode;
+
+ VisualShaderNodeParameterRef::ParameterType parameter_type;
+ if (float_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_FLOAT;
+ } else if (int_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_INT;
+ } else if (boolean_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_BOOLEAN;
+ } else if (vec2_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR2;
+ } else if (vec3_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR3;
+ } else if (vec4_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR4;
+ } else if (transform_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_TRANSFORM;
+ } else if (color_parameter.is_valid()) {
+ parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_COLOR;
} else {
- uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_SAMPLER;
+ parameter_type = VisualShaderNodeParameterRef::UNIFORM_TYPE_SAMPLER;
}
- VisualShaderNodeUniformRef::add_uniform(visual_shader->get_rid(), uniform->get_uniform_name(), uniform_type);
+ VisualShaderNodeParameterRef::add_parameter(visual_shader->get_rid(), parameter->get_parameter_name(), parameter_type);
}
}
}
if (p_update_refs) {
- graph_plugin->update_uniform_refs();
+ graph_plugin->update_parameter_refs();
}
}
-void VisualShaderEditor::_update_uniform_refs(HashSet<String> &p_deleted_names) {
+void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) {
for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
VisualShader::Type type = VisualShader::Type(i);
Vector<int> nodes = visual_shader->get_node_list(type);
for (int j = 0; j < nodes.size(); j++) {
if (j > 0) {
- Ref<VisualShaderNodeUniformRef> ref = visual_shader->get_node(type, nodes[j]);
+ Ref<VisualShaderNodeParameterRef> ref = visual_shader->get_node(type, nodes[j]);
if (ref.is_valid()) {
- if (p_deleted_names.has(ref->get_uniform_name())) {
- undo_redo->add_do_method(ref.ptr(), "set_uniform_name", "[None]");
- undo_redo->add_undo_method(ref.ptr(), "set_uniform_name", ref->get_uniform_name());
+ if (p_deleted_names.has(ref->get_parameter_name())) {
+ undo_redo->add_do_method(ref.ptr(), "set_parameter_name", "[None]");
+ undo_redo->add_undo_method(ref.ptr(), "set_parameter_name", ref->get_parameter_name());
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
}
@@ -1710,7 +1711,7 @@ void VisualShaderEditor::_update_graph() {
Vector<int> nodes = visual_shader->get_node_list(type);
- _update_uniforms(false);
+ _update_parameters(false);
_update_varyings();
graph_plugin->clear_links();
@@ -2256,38 +2257,38 @@ void VisualShaderEditor::_comment_desc_popup_hide() {
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_line_edit_changed(const String &p_text, int p_node_id) {
+void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int p_node_id) {
VisualShader::Type type = get_current_shader_type();
- Ref<VisualShaderNodeUniform> node = visual_shader->get_node(type, p_node_id);
+ Ref<VisualShaderNodeParameter> node = visual_shader->get_node(type, p_node_id);
ERR_FAIL_COND(!node.is_valid());
- String validated_name = visual_shader->validate_uniform_name(p_text, node);
+ String validated_name = visual_shader->validate_parameter_name(p_text, node);
- if (validated_name == node->get_uniform_name()) {
+ if (validated_name == node->get_parameter_name()) {
return;
}
- undo_redo->create_action(TTR("Set Uniform Name"));
- undo_redo->add_do_method(node.ptr(), "set_uniform_name", validated_name);
- undo_redo->add_undo_method(node.ptr(), "set_uniform_name", node->get_uniform_name());
- undo_redo->add_do_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, validated_name);
- undo_redo->add_undo_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, node->get_uniform_name());
+ undo_redo->create_action(TTR("Set Parameter Name"));
+ undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);
+ undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());
+ undo_redo->add_do_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, validated_name);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, node->get_parameter_name());
undo_redo->add_do_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
HashSet<String> changed_names;
- changed_names.insert(node->get_uniform_name());
- _update_uniform_refs(changed_names);
+ changed_names.insert(node->get_parameter_name());
+ _update_parameter_refs(changed_names);
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_line_edit_focus_out(Object *line_edit, int p_node_id) {
- _uniform_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);
+void VisualShaderEditor::_parameter_line_edit_focus_out(Object *line_edit, int p_node_id) {
+ _parameter_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);
}
void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) {
@@ -2673,22 +2674,22 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
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) {
+ VisualShaderNodeParameterRef *parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn);
+ if (parameter_ref && to_node != -1 && to_slot != -1) {
VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);
bool success = false;
- for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) {
- if (uniform_ref->get_port_type_by_index(i) == input_port_type) {
- uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i));
+ for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
+ if (parameter_ref->get_port_type_by_index(i) == input_port_type) {
+ parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
success = true;
break;
}
}
if (!success) {
- for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) {
- if (visual_shader->is_port_types_compatible(uniform_ref->get_port_type_by_index(i), input_port_type)) {
- uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i));
+ for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
+ if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(i), input_port_type)) {
+ parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
break;
}
}
@@ -2711,7 +2712,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
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);
+ bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr);
Point2 position = graph->get_scroll_ofs();
@@ -2860,9 +2861,9 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
}
_member_cancel();
- if (is_uniform) {
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ if (is_parameter) {
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
}
if (is_curve) {
@@ -3117,7 +3118,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
}
}
- HashSet<String> uniform_names;
+ HashSet<String> parameter_names;
for (const int &F : p_nodes) {
Ref<VisualShaderNode> node = visual_shader->get_node(type, F);
@@ -3140,9 +3141,9 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
undo_redo->add_undo_method(expression, "set_expression", expression->get_expression());
}
- VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (uniform) {
- uniform_names.insert(uniform->get_uniform_name());
+ VisualShaderNodeParameter *parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ if (parameter) {
+ parameter_names.insert(parameter->get_parameter_name());
}
}
@@ -3171,12 +3172,12 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F);
}
- // update uniform refs if any uniform has been deleted
- if (uniform_names.size() > 0) {
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ // update parameter refs if any parameter has been deleted
+ if (parameter_names.size() > 0) {
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
- _update_uniform_refs(uniform_names);
+ _update_parameter_refs(parameter_names);
}
}
@@ -3195,33 +3196,33 @@ void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_no
}
}
-void VisualShaderEditor::_update_uniform(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
- Ref<VisualShaderNodeUniform> uniform = visual_shader->get_node(p_type_id, p_node_id);
- ERR_FAIL_COND(!uniform.is_valid());
+void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
+ Ref<VisualShaderNodeParameter> parameter = visual_shader->get_node(p_type_id, p_node_id);
+ ERR_FAIL_COND(!parameter.is_valid());
- String valid_name = visual_shader->validate_uniform_name(uniform->get_uniform_name(), uniform);
- uniform->set_uniform_name(valid_name);
- graph_plugin->set_uniform_name(p_type_id, p_node_id, valid_name);
+ String valid_name = visual_shader->validate_parameter_name(parameter->get_parameter_name(), parameter);
+ parameter->set_parameter_name(valid_name);
+ graph_plugin->set_parameter_name(p_type_id, p_node_id, valid_name);
- if (uniform->has_method("set_default_value_enabled")) {
- uniform->call("set_default_value_enabled", true);
- uniform->call("set_default_value", p_var);
+ if (parameter->has_method("set_default_value_enabled")) {
+ parameter->call("set_default_value_enabled", true);
+ parameter->call("set_default_value", p_var);
}
if (p_preview_port != -1) {
- uniform->set_output_port_for_preview(p_preview_port);
+ parameter->set_output_port_for_preview(p_preview_port);
}
}
-void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
+void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {
VisualShader::Type type_id = get_current_shader_type();
if (!p_vice_versa) {
- undo_redo->create_action(TTR("Convert Constant Node(s) To Uniform(s)"));
+ undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));
} else {
- undo_redo->create_action(TTR("Convert Uniform Node(s) To Constant(s)"));
+ undo_redo->create_action(TTR("Convert Parameter Node(s) To Constant(s)"));
}
- const HashSet<int> &current_set = p_vice_versa ? selected_uniforms : selected_constants;
+ const HashSet<int> &current_set = p_vice_versa ? selected_parameters : selected_constants;
HashSet<String> deleted_names;
for (const int &E : current_set) {
@@ -3234,15 +3235,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeFloatConstant> float_const = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());
if (float_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatParameter");
var = float_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeFloatUniform> float_uniform = Object::cast_to<VisualShaderNodeFloatUniform>(node.ptr());
- if (float_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeFloatUniform", "VisualShaderNodeFloatConstant");
- var = float_uniform->get_default_value();
+ Ref<VisualShaderNodeFloatParameter> float_parameter = Object::cast_to<VisualShaderNodeFloatParameter>(node.ptr());
+ if (float_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeFloatParameter", "VisualShaderNodeFloatConstant");
+ var = float_parameter->get_default_value();
caught = true;
}
}
@@ -3252,15 +3253,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());
if (int_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntParameter");
var = int_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeIntUniform> int_uniform = Object::cast_to<VisualShaderNodeIntUniform>(node.ptr());
- if (int_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeIntUniform", "VisualShaderNodeIntConstant");
- var = int_uniform->get_default_value();
+ Ref<VisualShaderNodeIntParameter> int_parameter = Object::cast_to<VisualShaderNodeIntParameter>(node.ptr());
+ if (int_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeIntParameter", "VisualShaderNodeIntConstant");
+ var = int_parameter->get_default_value();
caught = true;
}
}
@@ -3271,15 +3272,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());
if (boolean_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanParameter");
var = boolean_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeBooleanUniform> boolean_uniform = Object::cast_to<VisualShaderNodeBooleanUniform>(node.ptr());
- if (boolean_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanConstant");
- var = boolean_uniform->get_default_value();
+ Ref<VisualShaderNodeBooleanParameter> boolean_parameter = Object::cast_to<VisualShaderNodeBooleanParameter>(node.ptr());
+ if (boolean_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeBooleanParameter", "VisualShaderNodeBooleanConstant");
+ var = boolean_parameter->get_default_value();
caught = true;
}
}
@@ -3290,15 +3291,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
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");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Parameter");
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();
+ Ref<VisualShaderNodeVec2Parameter> vec2_parameter = Object::cast_to<VisualShaderNodeVec2Parameter>(node.ptr());
+ if (vec2_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec2Parameter", "VisualShaderNodeVec2Constant");
+ var = vec2_parameter->get_default_value();
caught = true;
}
}
@@ -3309,15 +3310,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());
if (vec3_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Uniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Parameter");
var = vec3_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeVec3Uniform> vec3_uniform = Object::cast_to<VisualShaderNodeVec3Uniform>(node.ptr());
- if (vec3_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Constant");
- var = vec3_uniform->get_default_value();
+ Ref<VisualShaderNodeVec3Parameter> vec3_parameter = Object::cast_to<VisualShaderNodeVec3Parameter>(node.ptr());
+ if (vec3_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec3Parameter", "VisualShaderNodeVec3Constant");
+ var = vec3_parameter->get_default_value();
caught = true;
}
}
@@ -3328,15 +3329,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
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");
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Parameter");
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();
+ Ref<VisualShaderNodeVec4Parameter> vec4_parameter = Object::cast_to<VisualShaderNodeVec4Parameter>(node.ptr());
+ if (vec4_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeVec4Parameter", "VisualShaderNodeVec4Constant");
+ var = vec4_parameter->get_default_value();
caught = true;
}
}
@@ -3347,15 +3348,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());
if (color_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorParameter");
var = color_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeColorUniform> color_uniform = Object::cast_to<VisualShaderNodeColorUniform>(node.ptr());
- if (color_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeColorUniform", "VisualShaderNodeColorConstant");
- var = color_uniform->get_default_value();
+ Ref<VisualShaderNodeColorParameter> color_parameter = Object::cast_to<VisualShaderNodeColorParameter>(node.ptr());
+ if (color_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeColorParameter", "VisualShaderNodeColorConstant");
+ var = color_parameter->get_default_value();
caught = true;
}
}
@@ -3366,15 +3367,15 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
if (!p_vice_versa) {
Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());
if (transform_const.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformUniform");
+ _replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformParameter");
var = transform_const->get_constant();
caught = true;
}
} else {
- Ref<VisualShaderNodeTransformUniform> transform_uniform = Object::cast_to<VisualShaderNodeTransformUniform>(node.ptr());
- if (transform_uniform.is_valid()) {
- _replace_node(type_id, node_id, "VisualShaderNodeTransformUniform", "VisualShaderNodeTransformConstant");
- var = transform_uniform->get_default_value();
+ Ref<VisualShaderNodeTransformParameter> transform_parameter = Object::cast_to<VisualShaderNodeTransformParameter>(node.ptr());
+ if (transform_parameter.is_valid()) {
+ _replace_node(type_id, node_id, "VisualShaderNodeTransformParameter", "VisualShaderNodeTransformConstant");
+ var = transform_parameter->get_default_value();
caught = true;
}
}
@@ -3383,27 +3384,27 @@ void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
int preview_port = node->get_output_port_for_preview();
if (!p_vice_versa) {
- undo_redo->add_do_method(this, "_update_uniform", type_id, node_id, var, preview_port);
+ undo_redo->add_do_method(this, "_update_parameter", type_id, node_id, var, preview_port);
undo_redo->add_undo_method(this, "_update_constant", type_id, node_id, var, preview_port);
} else {
undo_redo->add_do_method(this, "_update_constant", type_id, node_id, var, preview_port);
- undo_redo->add_undo_method(this, "_update_uniform", type_id, node_id, var, preview_port);
+ undo_redo->add_undo_method(this, "_update_parameter", type_id, node_id, var, preview_port);
- Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- ERR_CONTINUE(!uniform.is_valid());
+ Ref<VisualShaderNodeParameter> parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ ERR_CONTINUE(!parameter.is_valid());
- deleted_names.insert(uniform->get_uniform_name());
+ deleted_names.insert(parameter->get_parameter_name());
}
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, node_id);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, node_id);
}
- undo_redo->add_do_method(this, "_update_uniforms", true);
- undo_redo->add_undo_method(this, "_update_uniforms", true);
+ undo_redo->add_do_method(this, "_update_parameters", true);
+ undo_redo->add_undo_method(this, "_update_parameters", true);
if (deleted_names.size() > 0) {
- _update_uniform_refs(deleted_names);
+ _update_parameter_refs(deleted_names);
}
undo_redo->commit_action();
@@ -3467,7 +3468,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
selected_constants.clear();
- selected_uniforms.clear();
+ selected_parameters.clear();
selected_comment = -1;
selected_float_constant = -1;
@@ -3493,9 +3494,9 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (float_constant_node != nullptr) {
selected_float_constant = id;
}
- VisualShaderNodeUniform *uniform_node = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (uniform_node != nullptr && uniform_node->is_convertible_to_constant()) {
- selected_uniforms.insert(id);
+ VisualShaderNodeParameter *parameter_node = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
+ if (parameter_node != nullptr && parameter_node->is_convertible_to_constant()) {
+ selected_parameters.insert(id);
}
}
}
@@ -3532,11 +3533,11 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (temp != -1) {
popup_menu->remove_item(temp);
}
- temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
+ temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
- temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
@@ -3553,7 +3554,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
popup_menu->remove_item(temp);
}
- if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
+ if (selected_constants.size() > 0 || selected_parameters.size() > 0) {
popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
if (selected_float_constant != -1) {
@@ -3572,11 +3573,11 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
}
if (selected_constants.size() > 0) {
- popup_menu->add_item(TTR("Convert Constant(s) to Uniform(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
+ popup_menu->add_item(TTR("Convert Constant(s) to Parameter(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
}
- if (selected_uniforms.size() > 0) {
- popup_menu->add_item(TTR("Convert Uniform(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ if (selected_parameters.size() > 0) {
+ popup_menu->add_item(TTR("Convert Parameter(s) to Constant(s)"), NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
}
}
@@ -4063,7 +4064,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
bool type_changed = next_input_type != prev_input_type;
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Visual Shader Input Type Changed"));
undo_redo->add_do_method(p_input.ptr(), "set_input_name", p_name);
@@ -4123,32 +4124,32 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
undo_redo->commit_action();
}
-void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform_ref, String p_name) {
- String prev_name = p_uniform_ref->get_uniform_name();
+void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name) {
+ String prev_name = p_parameter_ref->get_parameter_name();
if (p_name == prev_name) {
return;
}
- bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name);
+ bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name);
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
- undo_redo->create_action(TTR("UniformRef Name Changed"));
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
+ undo_redo->create_action(TTR("ParameterRef Name Changed"));
- undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name);
- undo_redo->add_undo_method(p_uniform_ref.ptr(), "set_uniform_name", prev_name);
+ undo_redo->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);
+ undo_redo->add_undo_method(p_parameter_ref.ptr(), "set_parameter_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_uniform_ref);
+ int id = visual_shader->find_node_id(type, p_parameter_ref);
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 (E.from_node == id) {
- if (visual_shader->is_port_types_compatible(p_uniform_ref->get_uniform_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {
+ if (visual_shader->is_port_types_compatible(p_parameter_ref->get_parameter_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);
@@ -4176,7 +4177,7 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var
bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Varying Name Changed"));
undo_redo->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
@@ -4311,6 +4312,9 @@ void VisualShaderEditor::_update_varying_tree() {
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_INT:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), 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;
@@ -4320,8 +4324,8 @@ void VisualShaderEditor::_update_varying_tree() {
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")));
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), 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")));
@@ -4438,11 +4442,11 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
case NodeMenuOptions::CLEAR_COPY_BUFFER:
_clear_copy_buffer();
break;
- case NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS:
- _convert_constants_to_uniforms(false);
+ case NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS:
+ _convert_constants_to_parameters(false);
break;
- case NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS:
- _convert_constants_to_uniforms(true);
+ case NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS:
+ _convert_constants_to_parameters(true);
break;
case NodeMenuOptions::SET_COMMENT_TITLE:
_comment_title_popup_show(get_screen_position() + get_local_mouse_position(), selected_comment);
@@ -4594,7 +4598,7 @@ void VisualShaderEditor::_preview_size_changed() {
}
static ShaderLanguage::DataType _get_global_shader_uniform_type(const StringName &p_variable) {
- RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(p_variable);
+ RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_variable);
return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);
}
@@ -4651,18 +4655,18 @@ void VisualShaderEditor::_bind_methods() {
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("_parameter_ref_select_item", &VisualShaderEditor::_parameter_ref_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_parameters", &VisualShaderEditor::_update_parameters);
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);
ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);
- ClassDB::bind_method("_update_uniform", &VisualShaderEditor::_update_uniform);
+ ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter);
ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);
ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
@@ -4822,7 +4826,7 @@ VisualShaderEditor::VisualShaderEditor() {
preview_shader = memnew(Button);
preview_shader->set_flat(true);
preview_shader->set_toggle_mode(true);
- preview_shader->set_tooltip(TTR("Show generated shader code."));
+ preview_shader->set_tooltip_text(TTR("Show generated shader code."));
graph->get_zoom_hbox()->add_child(preview_shader);
preview_shader->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_preview_text));
@@ -4892,7 +4896,7 @@ VisualShaderEditor::VisualShaderEditor() {
tools = memnew(MenuButton);
filter_hb->add_child(tools);
- tools->set_tooltip(TTR("Options"));
+ tools->set_tooltip_text(TTR("Options"));
tools->get_popup()->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_tools_menu_option));
tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL);
tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL);
@@ -4924,7 +4928,7 @@ VisualShaderEditor::VisualShaderEditor() {
highend_label->set_visible(false);
highend_label->set_text("Vulkan");
highend_label->set_mouse_filter(Control::MOUSE_FILTER_STOP);
- highend_label->set_tooltip(TTR("High-end node"));
+ highend_label->set_tooltip_text(TTR("High-end node"));
node_desc = memnew(RichTextLabel);
members_vb->add_child(node_desc);
@@ -4962,10 +4966,11 @@ VisualShaderEditor::VisualShaderEditor() {
varying_type = memnew(OptionButton);
hb->add_child(varying_type);
varying_type->add_item("Float");
+ varying_type->add_item("Int");
varying_type->add_item("Vector2");
varying_type->add_item("Vector3");
varying_type->add_item("Vector4");
- varying_type->add_item("Color");
+ varying_type->add_item("Boolean");
varying_type->add_item("Transform");
varying_name = memnew(LineEdit);
@@ -5053,56 +5058,56 @@ VisualShaderEditor::VisualShaderEditor() {
// COLOR
- 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("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", "VisualShaderNodeColorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeColorFunc::FUNC_HSV2RGB, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("RGB2HSV", "Color", "Functions", "VisualShaderNodeColorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeColorFunc::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("Grayscale", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("HSV2RGB", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeColorFunc::FUNC_HSV2RGB, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("RGB2HSV", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeColorFunc::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("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("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ColorConstant", "Color/Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("ColorParameter", "Color/Variables", "VisualShaderNodeColorParameter", TTR("Color parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
// COMMON
- 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));
+ 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."), {}, 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));
+ 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("BooleanParameter", "Conditional/Variables", "VisualShaderNodeBooleanParameter", TTR("Boolean parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
// INPUT
@@ -5111,43 +5116,43 @@ VisualShaderEditor::VisualShaderEditor() {
// NODE3D-FOR-ALL
- 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));
+ 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("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));
+ 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"), { "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("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.")));
+ 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.") + translation_gdsl;
const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.") + translation_gdsl;
@@ -5165,502 +5170,511 @@ VisualShaderEditor::VisualShaderEditor() {
// NODE3D INPUTS
- 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("NodePositionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("CameraPositionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("CameraDirectionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("NodePositionView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, 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("NodePositionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("CameraPositionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("CameraDirectionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("NodePositionView", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, 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));
+ 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("NodePositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraPositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraDirectionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionView", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, 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("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraPositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraDirectionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionView", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, 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"), { "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));
+ 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"), { "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("FragCoord", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, 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));
+ 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("FragCoord", "Input/Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, 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"), { "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));
+ 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"), { "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));
+ 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, 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("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", "", {}, 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("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", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, 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."), {}, 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));
+ 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, { float_constant_defs[i].value }, VisualShaderNode::PORT_TYPE_SCALAR));
+ 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("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_FRACT }, 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));
+ 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_FRACT }, 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("FloatParameter", "Scalar/Variables", "VisualShaderNodeFloatParameter", TTR("Scalar floating-point parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("IntParameter", "Scalar/Variables", "VisualShaderNodeIntParameter", TTR("Scalar integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
// SDF
{
- 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));
+ 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."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("UVFunc", "Textures/Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("UVPolarCoord", "Textures/Common", "VisualShaderNodeUVPolarCoord", TTR("Polar coordinates conversion 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."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("CubeMap", "Textures/Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
curve_node_option_idx = add_options.size();
- add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("CurveTexture", "Textures/Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
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."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value of the DEPTH_TEXTURE node in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
texture2d_node_option_idx = add_options.size();
- add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
texture2d_array_node_option_idx = add_options.size();
- add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Texture2DArray", "Textures/Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
texture3d_node_option_idx = add_options.size();
- add_options.push_back(AddOption("Texture3D", "Textures", "Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- 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("Texture3D", "Textures/Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ 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."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
- add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
- 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."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
- add_options.push_back(AddOption("Texture3DUniform", "Textures", "Variables", "VisualShaderNodeTexture3DUniform", TTR("3D texture uniform lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("CubeMapParameter", "Textures/Variables", "VisualShaderNodeCubemapParameter", TTR("Cubic texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("Texture2DParameter", "Textures/Variables", "VisualShaderNodeTexture2DParameter", TTR("2D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("TextureParameterTriplanar", "Textures/Variables", "VisualShaderNodeTextureParameterTriplanar", TTR("2D texture parameter lookup with triplanar."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Texture2DArrayParameter", "Textures/Variables", "VisualShaderNodeTexture2DArrayParameter", TTR("2D array of textures parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
+ add_options.push_back(AddOption("Texture3DParameter", "Textures/Variables", "VisualShaderNodeTexture3DParameter", TTR("3D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
// 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("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'."), {}, 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."), {}, 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("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("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("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("TransformConstant", "Transform/Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformParameter", "Transform/Variables", "VisualShaderNodeTransformParameter", TTR("Transform parameter."), {}, 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."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ // UTILITY
- 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));
+ add_options.push_back(AddOption("DistanceFade", "Utility", "VisualShaderNodeDistanceFade", TTR("The distance fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ProximityFade", "Utility", "VisualShaderNodeProximityFade", TTR("The proximity fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("RandomRange", "Utility", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Remap", "Utility", "VisualShaderNodeRemap", TTR("Remaps a given input from the input range to the output range."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
// 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_FRACT, 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_FRACT, 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_FRACT, 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("Length2D", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Length3D", "Vector", "Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Length4D", "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_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- 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("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_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- 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("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- 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));
+ 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_FRACT, 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_FRACT, 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_FRACT, 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("Length2D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Length3D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Length4D", "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_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ 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("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_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ 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("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ 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("Vector2Parameter", "Vector/Variables", "VisualShaderNodeVec2Parameter", TTR("2D vector parameter."), {}, 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("Vector3Parameter", "Vector/Variables", "VisualShaderNodeVec3Parameter", TTR("3D vector parameter."), {}, 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("Vector4Parameter", "Vector/Variables", "VisualShaderNodeVec4Parameter", TTR("4D vector parameter."), {}, 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("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("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("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, parameters and constants.")));
+ add_options.push_back(AddOption("ParameterRef", "Special", "VisualShaderNodeParameterRef", TTR("A reference to an existing parameter.")));
+ 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));
custom_node_option_idx = add_options.size();
@@ -5668,7 +5682,7 @@ VisualShaderEditor::VisualShaderEditor() {
_update_options_menu();
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
Ref<VisualShaderNodePluginDefault> default_plugin;
default_plugin.instantiate();
@@ -5758,10 +5772,11 @@ public:
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("Color"), 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")),
};
@@ -5811,28 +5826,28 @@ public:
////////////////
-class VisualShaderNodePluginUniformRefEditor : public OptionButton {
- GDCLASS(VisualShaderNodePluginUniformRefEditor, OptionButton);
+class VisualShaderNodePluginParameterRefEditor : public OptionButton {
+ GDCLASS(VisualShaderNodePluginParameterRefEditor, OptionButton);
VisualShaderEditor *editor = nullptr;
- Ref<VisualShaderNodeUniformRef> uniform_ref;
+ Ref<VisualShaderNodeParameterRef> parameter_ref;
public:
void _notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected));
+ connect("item_selected", callable_mp(this, &VisualShaderNodePluginParameterRefEditor::_item_selected));
} break;
}
}
void _item_selected(int p_item) {
- editor->call_deferred(SNAME("_uniform_select_item"), uniform_ref, get_item_text(p_item));
+ editor->call_deferred(SNAME("_parameter_ref_select_item"), parameter_ref, get_item_text(p_item));
}
- void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeUniformRef> &p_uniform_ref) {
+ void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeParameterRef> &p_parameter_ref) {
editor = p_editor;
- uniform_ref = p_uniform_ref;
+ parameter_ref = p_parameter_ref;
Ref<Texture2D> type_icon[] = {
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
@@ -5848,11 +5863,11 @@ public:
add_item("[None]");
int to_select = -1;
- for (int i = 0; i < p_uniform_ref->get_uniforms_count(); i++) {
- if (p_uniform_ref->get_uniform_name() == p_uniform_ref->get_uniform_name_by_index(i)) {
+ for (int i = 0; i < p_parameter_ref->get_parameters_count(); i++) {
+ if (p_parameter_ref->get_parameter_name() == p_parameter_ref->get_parameter_name_by_index(i)) {
to_select = i + 1;
}
- add_icon_item(type_icon[p_uniform_ref->get_uniform_type_by_index(i)], p_uniform_ref->get_uniform_name_by_index(i));
+ add_icon_item(type_icon[p_parameter_ref->get_parameter_type_by_index(i)], p_parameter_ref->get_parameter_name_by_index(i));
}
if (to_select >= 0) {
@@ -5876,7 +5891,7 @@ public:
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
updating = true;
undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS);
@@ -5996,8 +6011,8 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
return editor;
}
- if (p_node->is_class("VisualShaderNodeUniformRef")) {
- VisualShaderNodePluginUniformRefEditor *editor = memnew(VisualShaderNodePluginUniformRefEditor);
+ if (p_node->is_class("VisualShaderNodeParameterRef")) {
+ VisualShaderNodePluginParameterRefEditor *editor = memnew(VisualShaderNodePluginParameterRefEditor);
editor->setup(vseditor, p_node);
return editor;
}
@@ -6063,7 +6078,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
return editor;
}
-void EditorPropertyShaderMode::_option_selected(int p_which) {
+void EditorPropertyVisualShaderMode::_option_selected(int p_which) {
Ref<VisualShader> visual_shader(Object::cast_to<VisualShader>(get_edited_object()));
if (visual_shader->get_mode() == p_which) {
return;
@@ -6078,7 +6093,7 @@ void EditorPropertyShaderMode::_option_selected(int p_which) {
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Visual Shader Mode Changed"));
//do is easy
undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);
@@ -6149,39 +6164,39 @@ void EditorPropertyShaderMode::_option_selected(int p_which) {
undo_redo->commit_action();
}
-void EditorPropertyShaderMode::update_property() {
+void EditorPropertyVisualShaderMode::update_property() {
int which = get_edited_object()->get(get_edited_property());
options->select(which);
}
-void EditorPropertyShaderMode::setup(const Vector<String> &p_options) {
+void EditorPropertyVisualShaderMode::setup(const Vector<String> &p_options) {
for (int i = 0; i < p_options.size(); i++) {
options->add_item(p_options[i], i);
}
}
-void EditorPropertyShaderMode::set_option_button_clip(bool p_enable) {
+void EditorPropertyVisualShaderMode::set_option_button_clip(bool p_enable) {
options->set_clip_text(p_enable);
}
-void EditorPropertyShaderMode::_bind_methods() {
+void EditorPropertyVisualShaderMode::_bind_methods() {
}
-EditorPropertyShaderMode::EditorPropertyShaderMode() {
+EditorPropertyVisualShaderMode::EditorPropertyVisualShaderMode() {
options = memnew(OptionButton);
options->set_clip_text(true);
add_child(options);
add_focusable(options);
- options->connect("item_selected", callable_mp(this, &EditorPropertyShaderMode::_option_selected));
+ options->connect("item_selected", callable_mp(this, &EditorPropertyVisualShaderMode::_option_selected));
}
-bool EditorInspectorShaderModePlugin::can_handle(Object *p_object) {
+bool EditorInspectorVisualShaderModePlugin::can_handle(Object *p_object) {
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) {
+bool EditorInspectorVisualShaderModePlugin::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 == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) {
- EditorPropertyShaderMode *mode_editor = memnew(EditorPropertyShaderMode);
+ EditorPropertyVisualShaderMode *mode_editor = memnew(EditorPropertyVisualShaderMode);
Vector<String> options = p_hint_text.split(",");
mode_editor->setup(options);
add_property_editor(p_path, mode_editor);
@@ -6207,7 +6222,7 @@ void VisualShaderNodePortPreview::_shader_changed() {
preview_shader->set_code(shader_code);
for (int i = 0; i < default_textures.size(); i++) {
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);
+ preview_shader->set_default_texture_parameter(default_textures[i].name, default_textures[i].params[j], j);
}
}
@@ -6248,7 +6263,7 @@ void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Visua
type = p_type;
port = p_port;
node = p_node;
- update();
+ queue_redraw();
_shader_changed();
}
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index b846c34f9e..f7e033d753 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -48,6 +48,7 @@ class TextEdit;
class Tree;
class VisualShaderEditor;
+class EditorUndoRedoManager;
class VisualShaderNodePlugin : public RefCounted {
GDCLASS(VisualShaderNodePlugin, RefCounted);
@@ -88,7 +89,7 @@ private:
HashMap<int, InputPort> input_ports;
HashMap<int, Port> output_ports;
VBoxContainer *preview_box = nullptr;
- LineEdit *uniform_name = nullptr;
+ LineEdit *parameter_name = nullptr;
CodeEdit *expression_edit = nullptr;
CurveEditor *curve_editors[3] = { nullptr, nullptr, nullptr };
};
@@ -109,7 +110,7 @@ public:
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);
+ void register_parameter_name(int p_id, LineEdit *p_parameter_name);
void register_default_input_button(int p_node_id, int p_port_id, Button *p_button);
void register_expression_edit(int p_node_id, CodeEdit *p_expression_edit);
void register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor);
@@ -128,8 +129,8 @@ public:
void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position);
void refresh_node_ports(VisualShader::Type p_type, int p_node);
void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value);
- void update_uniform_refs();
- void set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name);
+ void update_parameter_refs();
+ void set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name);
void update_curve(int p_node_id);
void update_curve_xyz(int p_node_id);
void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression);
@@ -192,7 +193,7 @@ class VisualShaderEditor : public VBoxContainer {
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Point2 saved_node_pos;
bool saved_node_pos_dirty = false;
@@ -268,8 +269,8 @@ class VisualShaderEditor : public VBoxContainer {
CLEAR_COPY_BUFFER,
SEPARATOR2, // ignore
FLOAT_CONSTANTS,
- CONVERT_CONSTANTS_TO_UNIFORMS,
- CONVERT_UNIFORMS_TO_CONSTANTS,
+ CONVERT_CONSTANTS_TO_PARAMETERS,
+ CONVERT_PARAMETERS_TO_CONSTANTS,
SEPARATOR3, // ignore
SET_COMMENT_TITLE,
SET_COMMENT_DESCRIPTION,
@@ -311,10 +312,10 @@ class VisualShaderEditor : public VBoxContainer {
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(), const Vector<Variant> &p_ops = Vector<Variant>(), int p_return_type = -1, int p_mode = -1, int p_func = -1, bool p_highend = false) {
+ AddOption(const String &p_name = String(), const String &p_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;
+ category = p_category;
description = p_description;
ops = p_ops;
return_type = p_return_type;
@@ -339,7 +340,7 @@ class VisualShaderEditor : public VBoxContainer {
int curve_xyz_node_option_idx;
List<String> keyword_list;
- List<VisualShaderNodeUniformRef> uniform_refs;
+ List<VisualShaderNodeParameterRef> uniform_refs;
void _draw_color_over_button(Object *obj, Color p_color);
@@ -389,14 +390,14 @@ class VisualShaderEditor : public VBoxContainer {
int from_slot = -1;
HashSet<int> selected_constants;
- HashSet<int> selected_uniforms;
+ HashSet<int> selected_parameters;
int selected_comment = -1;
int selected_float_constant = -1;
- void _convert_constants_to_uniforms(bool p_vice_versa);
+ void _convert_constants_to_parameters(bool p_vice_versa);
void _replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to);
void _update_constant(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
- void _update_uniform(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
+ void _update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
@@ -412,8 +413,8 @@ class VisualShaderEditor : public VBoxContainer {
void _comment_desc_confirm();
void _comment_desc_text_changed();
- void _uniform_line_edit_changed(const String &p_text, int p_node_id);
- void _uniform_line_edit_focus_out(Object *line_edit, int p_node_id);
+ void _parameter_line_edit_changed(const String &p_text, int p_node_id);
+ void _parameter_line_edit_focus_out(Object *line_edit, int p_node_id);
void _port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output);
@@ -448,7 +449,7 @@ class VisualShaderEditor : public VBoxContainer {
void _custom_mode_toggled(bool p_enabled);
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
- void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name);
+ void _parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name);
void _varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name);
void _float_constant_selected(int p_which);
@@ -497,8 +498,8 @@ class VisualShaderEditor : public VBoxContainer {
bool _is_available(int p_mode);
void _update_created_node(GraphNode *node);
- void _update_uniforms(bool p_update_refs);
- void _update_uniform_refs(HashSet<String> &p_names);
+ void _update_parameters(bool p_update_refs);
+ void _update_parameter_refs(HashSet<String> &p_names);
void _update_varyings();
void _visibility_changed();
@@ -529,8 +530,8 @@ public:
virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) override;
};
-class EditorPropertyShaderMode : public EditorProperty {
- GDCLASS(EditorPropertyShaderMode, EditorProperty);
+class EditorPropertyVisualShaderMode : public EditorProperty {
+ GDCLASS(EditorPropertyVisualShaderMode, EditorProperty);
OptionButton *options = nullptr;
void _option_selected(int p_which);
@@ -542,11 +543,11 @@ public:
void setup(const Vector<String> &p_options);
virtual void update_property() override;
void set_option_button_clip(bool p_enable);
- EditorPropertyShaderMode();
+ EditorPropertyVisualShaderMode();
};
-class EditorInspectorShaderModePlugin : public EditorInspectorPlugin {
- GDCLASS(EditorInspectorShaderModePlugin, EditorInspectorPlugin);
+class EditorInspectorVisualShaderModePlugin : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorVisualShaderModePlugin, EditorInspectorPlugin);
public:
virtual bool can_handle(Object *p_object) override;
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index e3b2be33df..713c90c075 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -100,7 +100,7 @@ void VoxelGIEditorPlugin::_notification(int p_what) {
return;
}
- bake->set_tooltip(text);
+ bake->set_tooltip_text(text);
} break;
}
}
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index 1c9afa8be8..4cc60c4c3c 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -176,7 +176,7 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p
} else {
cancel_hb->hide();
}
- cancel_hb->raise();
+ cancel_hb->move_to_front();
cancelled = false;
_popup();
if (p_can_cancel) {
@@ -207,7 +207,9 @@ bool ProgressDialog::task_step(const String &p_task, const String &p_state, int
DisplayServer::get_singleton()->process_events();
}
+#ifndef ANDROID_ENABLED
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
+#endif
return cancelled;
}
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 6c544e4437..39b30b31fb 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -41,9 +41,7 @@ const int ERROR_CODE = 77;
#include "core/os/time.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
-
-const uint64_t CONVERSION_MAX_FILE_SIZE_MB = 4;
-const uint64_t CONVERSION_MAX_FILE_SIZE = 1024 * 1024 * CONVERSION_MAX_FILE_SIZE_MB;
+#include "core/templates/local_vector.h"
static const char *enum_renames[][2] = {
//// constants
@@ -76,8 +74,7 @@ static const char *enum_renames[][2] = {
{ "ARVR_STEREO", "XR_STEREO" }, // XRInterface
{ "ARVR_UNKNOWN_TRACKING", "XR_UNKNOWN_TRACKING" }, // XRInterface
{ "BAKE_ERROR_INVALID_MESH", "BAKE_ERROR_MESHES_INVALID" }, // LightmapGI
- { "BODY_MODE_CHARACTER", "BODY_MODE_DYNAMIC" }, // PhysicsServer2D
- { "BODY_MODE_DYNAMIC_LOCKED", "BODY_MODE_DYNAMIC_LINEAR" }, // PhysicsServer3D
+ { "BODY_MODE_CHARACTER", "BODY_MODE_RIGID_LINEAR" }, // PhysicsServer
{ "BUTTON_LEFT", "MOUSE_BUTTON_LEFT" }, // Globals
{ "BUTTON_MASK_LEFT", "MOUSE_BUTTON_MASK_LEFT" }, // Globals
{ "BUTTON_MASK_MIDDLE", "MOUSE_BUTTON_MASK_MIDDLE" }, // Globals
@@ -94,6 +91,8 @@ static const char *enum_renames[][2] = {
{ "BUTTON_XBUTTON2", "MOUSE_BUTTON_XBUTTON2" }, // Globals
{ "CLEAR_MODE_ONLY_NEXT_FRAME", "CLEAR_MODE_ONCE" }, // SubViewport
{ "COMPRESS_PVRTC4", "COMPRESS_PVRTC1_4" }, // Image
+ { "CONNECT_ONESHOT", "CONNECT_ONE_SHOT" }, // Object
+ { "CONTAINER_PROPERTY_EDITOR_BOTTOM", "CONTAINER_INSPECTOR_BOTTOM" }, // EditorPlugin
{ "CUBEMAP_BACK", "CUBEMAP_LAYER_BACK" }, // RenderingServer
{ "CUBEMAP_BOTTOM", "CUBEMAP_LAYER_BOTTOM" }, // RenderingServer
{ "CUBEMAP_FRONT", "CUBEMAP_LAYER_FRONT" }, // RenderingServer
@@ -125,17 +124,16 @@ static const char *enum_renames[][2] = {
{ "MATH_RAND", "MATH_RANDF_RANGE" }, // VisualScriptBuiltinFunc
{ "MATH_RANDOM", "MATH_RANDI_RANGE" }, // VisualScriptBuiltinFunc
{ "MATH_STEPIFY", "MATH_STEP_DECIMALS" }, // VisualScriptBuiltinFunc
- { "MODE_CHARACTER", "MODE_DYNAMIC_LOCKED" }, // RigidBody2D, RigidBody3D
- { "MODE_KINEMATIC", "FREEZE_MODE_KINEMATIC" }, // RigidDynamicBody
+ { "MODE_KINEMATIC", "FREEZE_MODE_KINEMATIC" }, // RigidBody
{ "MODE_OPEN_ANY", "FILE_MODE_OPEN_ANY" }, // FileDialog
{ "MODE_OPEN_DIR", "FILE_MODE_OPEN_DIR" }, // FileDialog
{ "MODE_OPEN_FILE", "FILE_MODE_OPEN_FILE" }, // FileDialog
{ "MODE_OPEN_FILES", "FILE_MODE_OPEN_FILES" }, // FileDialog
- { "MODE_RIGID", "MODE_DYNAMIC" }, // RigidBody2D, RigidBody3D
{ "MODE_SAVE_FILE", "FILE_MODE_SAVE_FILE" }, // FileDialog
- { "MODE_STATIC", "FREEZE_MODE_STATIC" }, // RigidDynamicBody
+ { "MODE_STATIC", "FREEZE_MODE_STATIC" }, // RigidBody
{ "NOTIFICATION_APP_PAUSED", "NOTIFICATION_APPLICATION_PAUSED" }, // MainLoop
{ "NOTIFICATION_APP_RESUMED", "NOTIFICATION_APPLICATION_RESUMED" }, // MainLoop
+ { "NOTIFICATION_INSTANCED", "NOTIFICATION_SCENE_INSTANTIATED" }, // Node
{ "NOTIFICATION_PATH_CHANGED", "NOTIFICATION_PATH_RENAMED" }, //Node
{ "NOTIFICATION_WM_FOCUS_IN", "NOTIFICATION_APPLICATION_FOCUS_IN" }, // MainLoop
{ "NOTIFICATION_WM_FOCUS_OUT", "NOTIFICATION_APPLICATION_FOCUS_OUT" }, // MainLoop
@@ -201,13 +199,15 @@ static const char *gdscript_function_renames[][2] = {
// { "set_color", "surface_set_color"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool
// { "set_event", "set_shortcut" }, // BaseButton - Cyclic Rename
// { "set_extents", "set_size"}, // BoxShape, RectangleShape broke ReflectionProbe
- // { "set_flag", "set_particle_flag"}, // ParticlesMaterial broke Window, HingeJoint3D
+ // { "set_flag", "set_particle_flag"}, // ParticleProcessMaterial broke Window, HingeJoint3D
// { "set_h_offset", "set_drag_horizontal_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// { "set_margin", "set_offset" }, // Control broke Shape3D, AtlasTexture
// { "set_mode", "set_mode_file_mode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap
// { "set_normal", "surface_set_normal"}, // ImmediateGeometry broke SurfaceTool, WorldMarginShape2D
+ // { "set_offset", "set_progress" }, // PathFollow2D, PathFollow3D - Too common
// { "set_process_mode", "set_process_callback" }, // AnimationTree broke Node, Tween, Sky
// { "set_refuse_new_network_connections", "set_refuse_new_connections"}, // MultiplayerAPI broke SceneTree
+ // { "set_tooltip", "set_tooltip_text" }, // Control, breaks TreeItem, at least for now.
// { "set_uv", "surface_set_uv" }, // ImmediateMesh broke Polygon2D
// { "set_v_offset", "set_drag_vertical_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// {"get_points","get_points_id"},// Astar, broke Line2D, Convexpolygonshape
@@ -220,18 +220,17 @@ static const char *gdscript_function_renames[][2] = {
{ "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit
{ "add_animation", "add_animation_library" }, // AnimationPlayer
{ "add_cancel", "add_cancel_button" }, // AcceptDialog
- { "add_central_force", "apply_central_force" }, //RigidDynamicBody2D
+ { "add_central_force", "apply_central_force" }, //RigidBody2D
{ "add_child_below_node", "add_sibling" }, // Node
{ "add_color_override", "add_theme_color_override" }, // Control
{ "add_constant_override", "add_theme_constant_override" }, // Control
{ "add_font_override", "add_theme_font_override" }, // Control
- { "add_force", "apply_force" }, //RigidDynamicBody2D
+ { "add_force", "apply_force" }, //RigidBody2D
{ "add_icon_override", "add_theme_icon_override" }, // Control
{ "add_scene_import_plugin", "add_scene_format_importer_plugin" }, //EditorPlugin
{ "add_stylebox_override", "add_theme_stylebox_override" }, // Control
- { "add_torque", "apply_torque" }, //RigidDynamicBody2D
+ { "add_torque", "apply_torque" }, //RigidBody2D
{ "apply_changes", "_apply_changes" }, // EditorPlugin
- { "bind_child_node_to_bone", "set_bone_children" }, // Skeleton3D
{ "body_add_force", "body_apply_force" }, // PhysicsServer2D
{ "body_add_torque", "body_apply_torque" }, // PhysicsServer2D
{ "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image
@@ -241,16 +240,18 @@ static const char *gdscript_function_renames[][2] = {
{ "can_instance", "can_instantiate" }, // PackedScene, Script
{ "canvas_light_set_scale", "canvas_light_set_texture_scale" }, // RenderingServer
{ "center_viewport_to_cursor", "center_viewport_to_caret" }, // TextEdit
+ { "change_scene", "change_scene_to_file" }, // SceneTree
+ { "change_scene_to", "change_scene_to_packed" }, // SceneTree
{ "clip_polygons_2d", "clip_polygons" }, // Geometry2D
{ "clip_polyline_with_polygon_2d", "clip_polyline_with_polygon" }, //Geometry2D
{ "commit_handle", "_commit_handle" }, // EditorNode3DGizmo
{ "convex_hull_2d", "convex_hull" }, // Geometry2D
{ "create_gizmo", "_create_gizmo" }, // EditorNode3DGizmoPlugin
- { "cursor_get_blink_speed", "get_caret_blink_speed" }, // TextEdit
+ { "cursor_get_blink_speed", "get_caret_blink_interval" }, // TextEdit
{ "cursor_get_column", "get_caret_column" }, // TextEdit
{ "cursor_get_line", "get_caret_line" }, // TextEdit
{ "cursor_set_blink_enabled", "set_caret_blink_enabled" }, // TextEdit
- { "cursor_set_blink_speed", "set_caret_blink_speed" }, // TextEdit
+ { "cursor_set_blink_speed", "set_caret_blink_interval" }, // TextEdit
{ "cursor_set_column", "set_caret_column" }, // TextEdit
{ "cursor_set_line", "set_caret_line" }, // TextEdit
{ "damped_spring_joint_create", "joint_make_damped_spring" }, // PhysicsServer2D
@@ -275,8 +276,8 @@ static const char *gdscript_function_renames[][2] = {
{ "get_action_list", "action_get_events" }, // InputMap
{ "get_alt", "is_alt_pressed" }, // InputEventWithModifiers
{ "get_animation_process_mode", "get_process_callback" }, // AnimationPlayer
- { "get_applied_force", "get_constant_force" }, //RigidDynamicBody2D
- { "get_applied_torque", "get_constant_torque" }, //RigidDynamicBody2D
+ { "get_applied_force", "get_constant_force" }, //RigidBody2D
+ { "get_applied_torque", "get_constant_torque" }, //RigidBody2D
{ "get_audio_bus", "get_audio_bus_name" }, // Area3D
{ "get_bound_child_nodes_to_bone", "get_bone_children" }, // Skeleton3D
{ "get_camera", "get_camera_3d" }, // Viewport -> this is also convertable to get_camera_2d, broke GLTFNode
@@ -291,7 +292,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_collision_layer_bit", "get_collision_layer_value" }, // CSGShape3D and a lot of others like GridMap
{ "get_collision_mask_bit", "get_collision_mask_value" }, // CSGShape3D and a lot of others like GridMap
{ "get_color_types", "get_color_type_list" }, // Theme
- { "get_command", "is_command_pressed" }, // InputEventWithModifiers
+ { "get_command", "is_command_or_control_pressed" }, // InputEventWithModifiers
{ "get_constant_types", "get_constant_type_list" }, // Theme
{ "get_control", "is_ctrl_pressed" }, // InputEventWithModifiers
{ "get_cull_mask_bit", "get_cull_mask_value" }, // Camera3D
@@ -299,11 +300,11 @@ static const char *gdscript_function_renames[][2] = {
{ "get_d", "get_distance" }, // LineShape2D
{ "get_drag_data", "_get_drag_data" }, // Control
{ "get_drag_data_fw", "_get_drag_data_fw" }, // ScriptEditor
- { "get_editor_description", "_get_editor_description" }, // Node
- { "get_editor_viewport", "get_viewport" }, // EditorPlugin
+ { "get_editor_viewport", "get_editor_main_screen" }, // EditorPlugin
{ "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton
{ "get_endian_swap", "is_big_endian" }, // File
{ "get_error_string", "get_error_message" }, // JSON
+ { "get_filename", "get_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places
{ "get_focus_neighbour", "get_focus_neighbor" }, // Control
{ "get_font_types", "get_font_type_list" }, // Theme
{ "get_frame_color", "get_color" }, // ColorRect
@@ -335,6 +336,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_network_peer", "get_multiplayer_peer" }, // Multiplayer API
{ "get_network_unique_id", "get_unique_id" }, // Multiplayer API
{ "get_ok", "get_ok_button" }, // AcceptDialog
+ { "get_oneshot", "get_one_shot" }, // AnimatedTexture
{ "get_option_visibility", "_get_option_visibility" }, // EditorImportPlugin
{ "get_parameter_default_value", "_get_parameter_default_value" }, // AnimationNode
{ "get_parameter_list", "_get_parameter_list" }, // AnimationNode
@@ -371,6 +373,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_theme_item_types", "get_theme_item_type_list" }, // Theme
{ "get_timer_process_mode", "get_timer_process_callback" }, // Timer
{ "get_translation", "get_position" }, // Node3D broke GLTFNode which is used rarely
+ { "get_unit_offset", "get_progress_ratio" }, // PathFollow2D, PathFollow3D
{ "get_use_in_baked_light", "is_baking_navigation" }, // GridMap
{ "get_used_cells_by_id", "get_used_cells" }, // TileMap
{ "get_v_scrollbar", "get_v_scroll_bar" }, //ScrollContainer
@@ -398,9 +401,9 @@ static const char *gdscript_function_renames[][2] = {
{ "has_stylebox_override", "has_theme_stylebox_override" }, // Control
{ "http_escape", "uri_encode" }, // String
{ "http_unescape", "uri_decode" }, // String
- { "import_animation_from_other_importer", "_import_animation" }, //EditorSceneFormatImporter
{ "import_scene_from_other_importer", "_import_scene" }, //EditorSceneFormatImporter
{ "instance_set_surface_material", "instance_set_surface_override_material" }, // RenderingServer
+ { "interpolate", "sample" }, // Curve, Curve2D, Curve3D, Gradient
{ "intersect_polygons_2d", "intersect_polygons" }, // Geometry2D
{ "intersect_polyline_with_polygon_2d", "intersect_polyline_with_polygon" }, // Geometry2D
{ "is_a_parent_of", "is_ancestor_of" }, // Node
@@ -477,7 +480,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_collision_layer_bit", "set_collision_layer_value" }, // CSGShape3D and a lot of others like GridMap
{ "set_collision_mask_bit", "set_collision_mask_value" }, // CSGShape3D and a lot of others like GridMap
{ "set_column_min_width", "set_column_custom_minimum_width" }, // Tree
- { "set_command", "set_command_pressed" }, // InputEventWithModifiers
+ { "set_command", "set_meta_pressed" }, // InputEventWithModifiers
{ "set_control", "set_ctrl_pressed" }, // InputEventWithModifiers
{ "set_create_options", "_set_create_options" }, // EditorResourcePicker
{ "set_cull_mask_bit", "set_cull_mask_value" }, // Camera3D
@@ -509,6 +512,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_mid_height", "set_height" }, // CapsuleMesh
{ "set_network_master", "set_multiplayer_authority" }, // Node
{ "set_network_peer", "set_multiplayer_peer" }, // Multiplayer API
+ { "set_oneshot", "set_one_shot" }, // AnimatedTexture
{ "set_pause_mode", "set_process_mode" }, // Node
{ "set_physical_scancode", "set_physical_keycode" }, // InputEventKey
{ "set_refuse_new_network_connections", "set_refuse_new_connections" }, // Multiplayer API
@@ -529,8 +533,8 @@ static const char *gdscript_function_renames[][2] = {
{ "set_tangent", "surface_set_tangent" }, // ImmediateGeometry broke SurfaceTool
{ "set_text_align", "set_text_alignment" }, // Button
{ "set_timer_process_mode", "set_timer_process_callback" }, // Timer
- { "set_tonemap_auto_exposure", "set_tonemap_auto_exposure_enabled" }, // Environment
{ "set_translation", "set_position" }, // Node3D - this broke GLTFNode which is used rarely
+ { "set_unit_offset", "set_progress_ratio" }, // PathFollow2D, PathFollow3D
{ "set_uv2", "surface_set_uv2" }, // ImmediateMesh broke Surffacetool
{ "set_v_drag_enabled", "set_drag_vertical_enabled" }, // Camera2D
{ "set_valign", "set_vertical_alignment" }, // Label
@@ -544,15 +548,20 @@ static const char *gdscript_function_renames[][2] = {
{ "targeting_property", "tween_property" }, // Tween
{ "track_remove_key_at_position", "track_remove_key_at_time" }, // Animation
{ "triangulate_delaunay_2d", "triangulate_delaunay" }, // Geometry2D
- { "unbind_child_node_from_bone", "remove_bone_child" }, // Skeleton3D
{ "unselect", "deselect" }, // ItemList
{ "unselect_all", "deselect_all" }, // ItemList
{ "update_configuration_warning", "update_configuration_warnings" }, // Node
{ "update_gizmo", "update_gizmos" }, // Node3D
{ "viewport_set_use_arvr", "viewport_set_use_xr" }, // RenderingServer
{ "warp_mouse_position", "warp_mouse" }, // Input
+ { "world_to_map", "local_to_map" }, // TileMap, GridMap
+ { "set_shader_param", "set_shader_parameter" }, // ShaderMaterial
+ { "get_shader_param", "get_shader_parameter" }, // ShaderMaterial
+ { "set_uniform_name", "set_parameter_name" }, // ParameterRef
+ { "get_uniform_name", "get_parameter_name" }, // ParameterRef
// Builtin types
+ // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed
// { "empty", "is_empty" }, // Array - Used as custom rule // Be careful, this will be used everywhere
{ "clamped", "clamp" }, // Vector2 // Be careful, this will be used everywhere
{ "get_rotation_quat", "get_rotation_quaternion" }, // Basis
@@ -565,9 +574,26 @@ static const char *gdscript_function_renames[][2] = {
{ "to_utf8", "to_utf8_buffer" }, // String
{ "to_wchar", "to_utf32_buffer" }, // String // TODO - utf32 or utf16?
- // Globals
+ // @GlobalScope
+ // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed
+ { "bytes2var", "bytes_to_var" },
+ { "bytes2var_with_objects", "bytes_to_var_with_objects" },
+ { "db2linear", "db_to_linear" },
+ { "deg2rad", "deg_to_rad" },
+ { "linear2db", "linear_to_db" },
+ { "rad2deg", "rad_to_deg" },
{ "rand_range", "randf_range" },
+ { "range_lerp", "remap" },
{ "stepify", "snapped" },
+ { "str2var", "str_to_var" },
+ { "var2str", "var_to_str" },
+ { "var2bytes", "var_to_bytes" },
+ { "var2bytes_with_objects", "var_to_bytes_with_objects" },
+
+ // @GDScript
+ // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed
+ { "dict2inst", "dict_to_inst" },
+ { "inst2dict", "inst_to_dict" },
{ nullptr, nullptr },
};
@@ -606,13 +632,15 @@ static const char *csharp_function_renames[][2] = {
// { "SetColor", "SurfaceSetColor"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool
// { "SetEvent", "SetShortcut" }, // BaseButton - Cyclic Rename
// { "SetExtents", "SetSize"}, // BoxShape, RectangleShape broke ReflectionProbe
- // { "SetFlag", "SetParticleFlag"}, // ParticlesMaterial broke Window, HingeJoint3D
+ // { "SetFlag", "SetParticleFlag"}, // ParticleProcessMaterial broke Window, HingeJoint3D
// { "SetHOffset", "SetDragHorizontalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// { "SetMargin", "SetOffset" }, // Control broke Shape3D, AtlasTexture
// { "SetMode", "SetModeFileMode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap
// { "SetNormal", "SurfaceSetNormal"}, // ImmediateGeometry broke SurfaceTool, WorldMarginShape2D
+ // { "SetOffset", "SetProgress" }, // PathFollow2D, PathFollow3D - Too common
// { "SetProcessMode", "SetProcessCallback" }, // AnimationTree broke Node, Tween, Sky
// { "SetRefuseNewNetworkConnections", "SetRefuseNewConnections"}, // MultiplayerAPI broke SceneTree
+ // { "SetTooltip", "SetTooltipText" }, // Control, breaks TreeItem, at least for now.
// { "SetUv", "SurfaceSetUv" }, // ImmediateMesh broke Polygon2D
// { "SetVOffset", "SetDragVerticalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// {"GetPoints","GetPointsId"},// Astar, broke Line2D, Convexpolygonshape
@@ -626,16 +654,16 @@ static const char *csharp_function_renames[][2] = {
{ "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit
{ "AddAnimation", "AddAnimationLibrary" }, // AnimationPlayer
{ "AddCancel", "AddCancelButton" }, // AcceptDialog
- { "AddCentralForce", "AddConstantCentralForce" }, //RigidDynamicBody2D
+ { "AddCentralForce", "AddConstantCentralForce" }, //RigidBody2D
{ "AddChildBelowNode", "AddSibling" }, // Node
{ "AddColorOverride", "AddThemeColorOverride" }, // Control
{ "AddConstantOverride", "AddThemeConstantOverride" }, // Control
{ "AddFontOverride", "AddThemeFontOverride" }, // Control
- { "AddForce", "AddConstantForce" }, //RigidDynamicBody2D
+ { "AddForce", "AddConstantForce" }, //RigidBody2D
{ "AddIconOverride", "AddThemeIconOverride" }, // Control
{ "AddSceneImportPlugin", "AddSceneFormatImporterPlugin" }, //EditorPlugin
{ "AddStyleboxOverride", "AddThemeStyleboxOverride" }, // Control
- { "AddTorque", "AddConstantTorque" }, //RigidDynamicBody2D
+ { "AddTorque", "AddConstantTorque" }, //RigidBody2D
{ "BindChildNodeToBone", "SetBoneChildren" }, // Skeleton3D
{ "BumpmapToNormalmap", "BumpMapToNormalMap" }, // Image
{ "CanBeHidden", "_CanBeHidden" }, // EditorNode3DGizmoPlugin
@@ -644,15 +672,17 @@ static const char *csharp_function_renames[][2] = {
{ "CanInstance", "CanInstantiate" }, // PackedScene, Script
{ "CanvasLightSetScale", "CanvasLightSetTextureScale" }, // RenderingServer
{ "CenterViewportToCursor", "CenterViewportToCaret" }, // TextEdit
+ { "ChangeScene", "ChangeSceneToFile" }, // SceneTree
+ { "ChangeSceneTo", "ChangeSceneToPacked" }, // SceneTree
{ "ClipPolygons2d", "ClipPolygons" }, // Geometry2D
{ "ClipPolylineWithPolygon2d", "ClipPolylineWithPolygon" }, //Geometry2D
{ "CommitHandle", "_CommitHandle" }, // EditorNode3DGizmo
{ "ConvexHull2d", "ConvexHull" }, // Geometry2D
- { "CursorGetBlinkSpeed", "GetCaretBlinkSpeed" }, // TextEdit
+ { "CursorGetBlinkSpeed", "GetCaretBlinkInterval" }, // TextEdit
{ "CursorGetColumn", "GetCaretColumn" }, // TextEdit
{ "CursorGetLine", "GetCaretLine" }, // TextEdit
{ "CursorSetBlinkEnabled", "SetCaretBlinkEnabled" }, // TextEdit
- { "CursorSetBlinkSpeed", "SetCaretBlinkSpeed" }, // TextEdit
+ { "CursorSetBlinkSpeed", "SetCaretBlinkInterval" }, // TextEdit
{ "CursorSetColumn", "SetCaretColumn" }, // TextEdit
{ "CursorSetLine", "SetCaretLine" }, // TextEdit
{ "DampedSpringJointCreate", "JointMakeDampedSpring" }, // PhysicsServer2D
@@ -674,8 +704,8 @@ static const char *csharp_function_renames[][2] = {
{ "GetActionList", "ActionGetEvents" }, // InputMap
{ "GetAlt", "IsAltPressed" }, // InputEventWithModifiers
{ "GetAnimationProcessMode", "GetProcessCallback" }, // AnimationPlayer
- { "GetAppliedForce", "GetConstantForce" }, //RigidDynamicBody2D
- { "GetAppliedTorque", "GetConstantTorque" }, //RigidDynamicBody2D
+ { "GetAppliedForce", "GetConstantForce" }, //RigidBody2D
+ { "GetAppliedTorque", "GetConstantTorque" }, //RigidBody2D
{ "GetAudioBus", "GetAudioBusName" }, // Area3D
{ "GetBoundChildNodesToBone", "GetBoneChildren" }, // Skeleton3D
{ "GetCamera", "GetCamera3d" }, // Viewport -> this is also convertable to getCamera2d, broke GLTFNode
@@ -731,6 +761,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetNetworkMaster", "GetMultiplayerAuthority" }, // Node
{ "GetNetworkPeer", "GetMultiplayerPeer" }, // Multiplayer API
{ "GetNetworkUniqueId", "GetUniqueId" }, // Multiplayer API
+ { "GetOneshot", "GetOneShot" }, // AnimatedTexture
{ "GetOk", "GetOkButton" }, // AcceptDialog
{ "GetOptionVisibility", "_GetOptionVisibility" }, // EditorImportPlugin
{ "GetParameterDefaultValue", "_GetParameterDefaultValue" }, // AnimationNode
@@ -766,6 +797,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetThemeItemTypes", "GetThemeItemTypeList" }, // Theme
{ "GetTimerProcessMode", "GetTimerProcessCallback" }, // Timer
{ "GetTranslation", "GetPosition" }, // Node3D broke GLTFNode which is used rarely
+ { "GetUnitOffset", "GetProgressRatio" }, // PathFollow2D, PathFollow3D
{ "GetUseInBakedLight", "IsBakingNavigation" }, // GridMap
{ "GetUsedCellsById", "GetUsedCells" }, // TileMap
{ "GetVScrollbar", "GetVScrollBar" }, //ScrollContainer
@@ -896,6 +928,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetMidHeight", "SetHeight" }, // CapsuleMesh
{ "SetNetworkMaster", "SetMultiplayerAuthority" }, // Node
{ "SetNetworkPeer", "SetMultiplayerPeer" }, // Multiplayer API
+ { "SetOneshot", "SetOneShot" }, // AnimatedTexture
{ "SetPhysicalScancode", "SetPhysicalKeycode" }, // InputEventKey
{ "SetRefuseNewNetworkConnections", "SetRefuseNewConnections" }, // Multiplayer API
{ "SetRegion", "SetRegionEnabled" }, // Sprite2D, Sprite broke AtlasTexture
@@ -917,6 +950,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetTimerProcessMode", "SetTimerProcessCallback" }, // Timer
{ "SetTonemapAutoExposure", "SetTonemapAutoExposureEnabled" }, // Environment
{ "SetTranslation", "SetPosition" }, // Node3D - this broke GLTFNode which is used rarely
+ { "SetUnitOffset", "SetProgressRatio" }, // PathFollow2D, PathFollow3D
{ "SetUv2", "SurfaceSetUv2" }, // ImmediateMesh broke Surffacetool
{ "SetVDragEnabled", "SetDragVerticalEnabled" }, // Camera2D
{ "SetValign", "SetVerticalAlignment" }, // Label
@@ -937,6 +971,11 @@ static const char *csharp_function_renames[][2] = {
{ "UpdateGizmo", "UpdateGizmos" }, // Node3D
{ "ViewportSetUseArvr", "ViewportSetUseXr" }, // RenderingServer
{ "WarpMousePosition", "WarpMouse" }, // Input
+ { "WorldToMap", "LocalToMap" }, // TileMap, GridMap
+ { "SetShaderParam", "SetShaderParameter" }, // ShaderMaterial
+ { "GetShaderParam", "GetShaderParameter" }, // ShaderMaterial
+ { "SetUniformName", "SetParameterName" }, // ParameterRef
+ { "GetUniformName", "GetParameterName" }, // ParameterRef
// Builtin types
// { "Empty", "IsEmpty" }, // Array - Used as custom rule // Be careful, this will be used everywhere
@@ -951,9 +990,24 @@ static const char *csharp_function_renames[][2] = {
{ "ToUtf8", "ToUtf8Buffer" }, // String
{ "ToWchar", "ToUtf32Buffer" }, // String // TODO - utf32 or utf16?
- // Globals
+ // @GlobalScope
+ { "Bytes2Var", "BytesToVar" },
+ { "Bytes2VarWithObjects", "BytesToVarWithObjects" },
+ { "Db2Linear", "DbToLinear" },
+ { "Deg2Rad", "DegToRad" },
+ { "Linear2Db", "LinearToDb" },
+ { "Rad2Deg", "RadToDeg" },
{ "RandRange", "RandfRange" },
+ { "RangeLerp", "Remap" },
{ "Stepify", "Snapped" },
+ { "Str2Var", "StrToVar" },
+ { "Var2Str", "VarToStr" },
+ { "Var2Bytes", "VarToBytes" },
+ { "Var2BytesWithObjects", "VarToBytesWithObjects" },
+
+ // @GDScript
+ { "Dict2Inst", "DictToInst" },
+ { "Inst2Dict", "InstToDict" },
{ nullptr, nullptr },
};
@@ -968,6 +1022,7 @@ static const char *gdscript_properties_renames[][2] = {
// // {"meta","meta_pressed"},// This may broke a lot of comments and user variables
// // {"pause_mode","process_mode"}, // Node - Cyclic rename, look for others
// // {"rotate","rotates"}, // PathFollow2D - probably function exists with same name
+ // // {"offset","progress"}, // PathFollow2D, PathFollow3D - Name is way too vague
// // {"shift","shift_pressed"},// This may broke a lot of comments and user variables
// { "autowrap", "autowrap_mode" }, // Label
// { "cast_to", "target_position" }, // RayCast2D, RayCast3D
@@ -983,12 +1038,16 @@ static const char *gdscript_properties_renames[][2] = {
// { "filename", "scene_file_path" }, // Node
{ "as_normalmap", "as_normal_map" }, // NoiseTexture
{ "bbcode_text", "text" }, // RichTextLabel
+ { "bg", "panel" }, // Theme
+ { "bg_focus", "focus" }, // Theme
+ { "caret_blink_speed", "caret_blink_interval" }, // TextEdit, LineEdit
{ "caret_moving_by_right_click", "caret_move_on_right_click" }, // TextEdit
{ "caret_position", "caret_column" }, // LineEdit
- { "check_vadjust", "check_v_adjust" }, // Theme
+ { "check_vadjust", "check_v_offset" }, // Theme
{ "close_h_ofs", "close_h_offset" }, // Theme
{ "close_v_ofs", "close_v_offset" }, // Theme
{ "commentfocus", "comment_focus" }, // Theme
+ { "contacts_reported", "max_contacts_reported" }, // RigidBody
{ "drag_margin_bottom", "drag_bottom_margin" }, // Camera2D
{ "drag_margin_h_enabled", "drag_horizontal_enabled" }, // Camera2D
{ "drag_margin_left", "drag_left_margin" }, // Camera2D
@@ -1002,11 +1061,16 @@ static const char *gdscript_properties_renames[][2] = {
{ "focus_neighbour_left", "focus_neighbor_left" }, // Control
{ "focus_neighbour_right", "focus_neighbor_right" }, // Control
{ "focus_neighbour_top", "focus_neighbor_top" }, // Control
+ { "file_icon_modulate", "file_icon_color" }, // Theme
+ { "files_disabled", "file_disabled_color" }, // Theme
+ { "folder_icon_modulate", "folder_icon_color" }, // Theme
{ "global_rate_scale", "playback_speed_scale" }, // AudioServer
{ "gravity_distance_scale", "gravity_point_distance_scale" }, // Area2D
{ "gravity_vec", "gravity_direction" }, // Area2D
+ { "hint_tooltip", "tooltip_text" }, // Control
{ "hseparation", "h_separation" }, // Theme
{ "iterations_per_second", "physics_ticks_per_second" }, // Engine
+ { "invert_enable", "invert_enabled" }, // Polygon2D
{ "margin_bottom", "offset_bottom" }, // Control broke NinePatchRect, StyleBox
{ "margin_left", "offset_left" }, // Control broke NinePatchRect, StyleBox
{ "margin_right", "offset_right" }, // Control broke NinePatchRect, StyleBox
@@ -1014,11 +1078,24 @@ static const char *gdscript_properties_renames[][2] = {
{ "mid_height", "height" }, // CapsuleMesh
{ "offset_h", "drag_horizontal_offset" }, // Camera2D
{ "offset_v", "drag_vertical_offset" }, // Camera2D
+ { "off", "unchecked" }, // Theme
+ { "off_disabled", "unchecked_disabled" }, // Theme
{ "ofs", "offset" }, // Theme
+ { "on", "checked" }, // Theme
+ { "on_disabled", "checked_disabled" }, // Theme
+ { "oneshot", "one_shot" }, // AnimatedTexture
{ "out_of_range_mode", "max_polyphony" }, // AudioStreamPlayer3D
{ "pause_mode", "process_mode" }, // Node
{ "physical_scancode", "physical_keycode" }, // InputEventKey
{ "popup_exclusive", "exclusive" }, // Window
+ { "rect_position", "position" }, // Control
+ { "rect_global_position", "global_position" }, // Control
+ { "rect_size", "size" }, // Control
+ { "rect_min_size", "minimum_size" }, // Control
+ { "rect_rotation", "rotation" }, // Control
+ { "rect_scale", "scale" }, // Control
+ { "rect_pivot_offset", "pivot_offset" }, // Control
+ { "rect_clip_content", "clip_contents" }, // Control
{ "refuse_new_network_connections", "refuse_new_connections" }, // MultiplayerAPI
{ "region_filter_clip", "region_filter_clip_enabled" }, // Sprite2D
{ "selectedframe", "selected_frame" }, // Theme
@@ -1035,6 +1112,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "table_hseparation", "table_h_separation" }, // Theme
{ "table_vseparation", "table_v_separation" }, // Theme
{ "translation", "position" }, // Node3D - broke GLTFNode
+ { "unit_offset", "progress_ratio" }, // PathFollow2D, PathFollow3D
{ "vseparation", "v_separation" }, // Theme
{ nullptr, nullptr },
@@ -1050,11 +1128,13 @@ static const char *csharp_properties_renames[][2] = {
// // {"Meta","MetaPressed"},// This may broke a lot of comments and user variables
// // {"PauseMode","ProcessMode"}, // Node - Cyclic rename, look for others
// // {"Rotate","Rotates"}, // PathFollow2D - probably function exists with same name
+ // // {"Offset","Progress"}, // PathFollow2D, PathFollow3D - Name is way too vague
// // {"Shift","ShiftPressed"},// This may broke a lot of comments and user variables
// { "Autowrap", "AutowrapMode" }, // Label
// { "CastTo", "TargetPosition" }, // RayCast2D, RayCast3D
// { "Doubleclick", "DoubleClick" }, // InputEventMouseButton
// { "Group", "ButtonGroup" }, // BaseButton
+ // { "PercentVisible, "ShowPercentage}, // ProgressBar, conflicts with Label and RichTextLabel, but may be a worth it.
// { "ProcessMode", "ProcessCallback" }, // AnimationTree, Camera2D
// { "Scancode", "Keycode" }, // InputEventKey
// { "Toplevel", "TopLevel" }, // Node
@@ -1064,6 +1144,7 @@ static const char *csharp_properties_renames[][2] = {
// { "Znear", "Near" }, // Camera3D
{ "AsNormalmap", "AsNormalMap" }, // NoiseTexture
{ "BbcodeText", "Text" }, // RichTextLabel
+ { "CaretBlinkSpeed", "CaretBlinkInterval" }, // TextEdit, LineEdit
{ "CaretMovingByRightClick", "CaretMoveOnRightClick" }, // TextEdit
{ "CaretPosition", "CaretColumn" }, // LineEdit
{ "CheckVadjust", "CheckVAdjust" }, // Theme
@@ -1086,8 +1167,10 @@ static const char *csharp_properties_renames[][2] = {
{ "GlobalRateScale", "PlaybackSpeedScale" }, // AudioServer
{ "GravityDistanceScale", "GravityPointDistanceScale" }, // Area2D
{ "GravityVec", "GravityDirection" }, // Area2D
+ { "HintTooltip", "TooltipText" }, // Control
{ "Hseparation", "HSeparation" }, // Theme
{ "IterationsPerSecond", "PhysicsTicksPerSecond" }, // Engine
+ { "InvertEnable", "InvertEnabled" }, // Polygon2D
{ "MarginBottom", "OffsetBottom" }, // Control broke NinePatchRect, StyleBox
{ "MarginLeft", "OffsetLeft" }, // Control broke NinePatchRect, StyleBox
{ "MarginRight", "OffsetRight" }, // Control broke NinePatchRect, StyleBox
@@ -1096,6 +1179,7 @@ static const char *csharp_properties_renames[][2] = {
{ "OffsetH", "DragHorizontalOffset" }, // Camera2D
{ "OffsetV", "DragVerticalOffset" }, // Camera2D
{ "Ofs", "Offset" }, // Theme
+ { "Oneshot", "OneShot" }, // AnimatedTexture
{ "OutOfRangeMode", "MaxPolyphony" }, // AudioStreamPlayer3D
{ "PauseMode", "ProcessMode" }, // Node
{ "PhysicalScancode", "PhysicalKeycode" }, // InputEventKey
@@ -1116,6 +1200,7 @@ static const char *csharp_properties_renames[][2] = {
{ "TableHseparation", "TableHSeparation" }, // Theme
{ "TableVseparation", "TableVSeparation" }, // Theme
{ "Translation", "Position" }, // Node3D - broke GLTFNode
+ { "UnitOffset", "ProgressRatio" }, // PathFollow2D, PathFollow3D
{ "Vseparation", "VSeparation" }, // Theme
{ nullptr, nullptr },
@@ -1185,7 +1270,7 @@ static const char *project_settings_renames[][2] = {
{ "network/limits/debugger_stdout/max_errors_per_second", "network/limits/debugger/max_errors_per_second" },
{ "network/limits/debugger_stdout/max_messages_per_frame", "network/limits/debugger/max_queued_messages" },
{ "network/limits/debugger_stdout/max_warnings_per_second", "network/limits/debugger/max_warnings_per_second" },
- { "network/ssl/certificates", "network/ssl/certificate_bundle_override" },
+ { "network/ssl/certificates", "network/tls/certificate_bundle_override" },
{ "physics/2d/thread_model", "physics/2d/run_on_thread" }, // TODO not sure
{ "rendering/environment/default_clear_color", "rendering/environment/defaults/default_clear_color" },
{ "rendering/environment/default_environment", "rendering/environment/defaults/default_environment" },
@@ -1197,12 +1282,12 @@ static const char *project_settings_renames[][2] = {
{ "rendering/quality/shading/force_lambert_over_burley.mobile", "rendering/shading/overrides/force_lambert_over_burley.mobile" },
{ "rendering/quality/shading/force_vertex_shading", "rendering/shading/overrides/force_vertex_shading" },
{ "rendering/quality/shading/force_vertex_shading.mobile", "rendering/shading/overrides/force_vertex_shading.mobile" },
- { "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/shadows/shadow_atlas/quadrant_0_subdiv" },
- { "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/shadows/shadow_atlas/quadrant_1_subdiv" },
- { "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/shadows/shadow_atlas/quadrant_2_subdiv" },
- { "rendering/quality/shadow_atlas/quadrant_3_subdiv", "rendering/shadows/shadow_atlas/quadrant_3_subdiv" },
- { "rendering/quality/shadow_atlas/size", "rendering/shadows/shadow_atlas/size" },
- { "rendering/quality/shadow_atlas/size.mobile", "rendering/shadows/shadow_atlas/size.mobile" },
+ { "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_0_subdiv" },
+ { "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_1_subdiv" },
+ { "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_2_subdiv" },
+ { "rendering/quality/shadow_atlas/quadrant_3_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_3_subdiv" },
+ { "rendering/quality/shadow_atlas/size", "rendering/lights_and_shadows/shadow_atlas/size" },
+ { "rendering/quality/shadow_atlas/size.mobile", "rendering/lights_and_shadows/shadow_atlas/size.mobile" },
{ "rendering/vram_compression/import_bptc", "rendering/textures/vram_compression/import_bptc" },
{ "rendering/vram_compression/import_etc", "rendering/textures/vram_compression/import_etc" },
{ "rendering/vram_compression/import_etc2", "rendering/textures/vram_compression/import_etc2" },
@@ -1228,9 +1313,19 @@ static const char *builtin_types_renames[][2] = {
static const char *shaders_renames[][2] = {
{ "ALPHA_SCISSOR", "ALPHA_SCISSOR_THRESHOLD" },
+ { "CAMERA_MATRIX", "INV_VIEW_MATRIX" },
+ { "INV_CAMERA_MATRIX", "VIEW_MATRIX" },
{ "NORMALMAP", "NORMAL_MAP" },
{ "NORMALMAP_DEPTH", "NORMAL_MAP_DEPTH" },
- { "TRANSMISSION", "SSS_TRANSMITTANCE_COLOR" },
+ { "TRANSMISSION", "BACKLIGHT" },
+ { "WORLD_MATRIX", "MODEL_MATRIX" },
+ { "depth_draw_alpha_prepass", "depth_draw_opaque" },
+ { "hint_albedo", "source_color" },
+ { "hint_aniso", "hint_anisotropy" },
+ { "hint_black", "hint_default_black" },
+ { "hint_black_albedo", "hint_default_black" },
+ { "hint_color", "source_color" },
+ { "hint_white", "hint_default_white" },
{ nullptr, nullptr },
};
@@ -1343,6 +1438,7 @@ static const char *class_renames[][2] = {
{ "PanoramaSky", "Sky" },
{ "Particles", "GPUParticles3D" }, // Be careful, this will be used everywhere
{ "Particles2D", "GPUParticles2D" },
+ { "ParticlesMaterial", "ParticleProcessMaterial" },
{ "Path", "Path3D" }, // Be careful, this will be used everywhere
{ "PathFollow", "PathFollow3D" },
{ "PhysicalBone", "PhysicalBone3D" },
@@ -1361,6 +1457,8 @@ static const char *class_renames[][2] = {
{ "PinJoint", "PinJoint3D" },
{ "PlaneShape", "WorldBoundaryShape3D" },
{ "PopupDialog", "Popup" },
+ { "Position2D", "Marker2D" },
+ { "Position3D", "Marker3D" },
{ "ProceduralSky", "Sky" },
{ "RayCast", "RayCast3D" },
{ "RayShape", "SeparationRayShape3D" },
@@ -1368,19 +1466,17 @@ static const char *class_renames[][2] = {
{ "Reference", "RefCounted" }, // Be careful, this will be used everywhere
{ "RemoteTransform", "RemoteTransform3D" },
{ "ResourceInteractiveLoader", "ResourceLoader" },
- { "RigidBody", "RigidDynamicBody3D" },
- { "RigidBody2D", "RigidDynamicBody2D" },
+ { "RigidBody", "RigidBody3D" },
{ "SceneTreeTween", "Tween" },
{ "Shape", "Shape3D" }, // Be careful, this will be used everywhere
{ "ShortCut", "Shortcut" },
{ "Skeleton", "Skeleton3D" },
{ "SkeletonIK", "SkeletonIK3D" },
{ "SliderJoint", "SliderJoint3D" },
- { "SoftBody", "SoftDynamicBody3D" },
+ { "SoftBody", "SoftBody3D" },
{ "Spatial", "Node3D" },
{ "SpatialGizmo", "Node3DGizmo" },
{ "SpatialMaterial", "StandardMaterial3D" },
- { "SpatialVelocityTracker", "VelocityTracker3D" },
{ "SphereShape", "SphereShape3D" },
{ "SpotLight", "SpotLight3D" },
{ "SpringArm", "SpringArm3D" },
@@ -1389,6 +1485,7 @@ static const char *class_renames[][2] = {
{ "StreamCubemap", "CompressedCubemap" },
{ "StreamCubemapArray", "CompressedCubemapArray" },
{ "StreamPeerGDNative", "StreamPeerExtension" },
+ { "StreamPeerSSL", "StreamPeerTLS" },
{ "StreamTexture", "CompressedTexture2D" },
{ "StreamTexture2D", "CompressedTexture2D" },
{ "StreamTexture2DArray", "CompressedTexture2DArray" },
@@ -1413,7 +1510,6 @@ static const char *class_renames[][2] = {
{ "VisualInstance", "VisualInstance3D" },
{ "VisualServer", "RenderingServer" },
{ "VisualShaderNodeCubeMap", "VisualShaderNodeCubemap" },
- { "VisualShaderNodeCubeMapUniform", "VisualShaderNodeCubemapUniform" },
{ "VisualShaderNodeScalarClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant" },
{ "VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc" },
@@ -1422,7 +1518,6 @@ static const char *class_renames[][2] = {
{ "VisualShaderNodeScalarSmoothStep", "VisualShaderNodeSmoothStep" },
{ "VisualShaderNodeScalarSwitch", "VisualShaderNodeSwitch" },
{ "VisualShaderNodeScalarTransformMult", "VisualShaderNodeTransformOp" },
- { "VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform" },
{ "VisualShaderNodeTransformMult", "VisualShaderNode" },
{ "VisualShaderNodeVectorClamp", "VisualShaderNodeClamp" },
{ "VisualShaderNodeVectorInterp", "VisualShaderNodeMix" },
@@ -1430,6 +1525,16 @@ static const char *class_renames[][2] = {
{ "VisualShaderNodeVectorScalarSmoothStep", "VisualShaderNodeSmoothStep" },
{ "VisualShaderNodeVectorScalarStep", "VisualShaderNodeStep" },
{ "VisualShaderNodeVectorSmoothStep", "VisualShaderNodeSmoothStep" },
+ { "VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanParameter" },
+ { "VisualShaderNodeColorUniform", "VisualShaderNodeColorParameter" },
+ { "VisualShaderNodeScalarUniform", "VisualShaderNodeFloatParameter" },
+ { "VisualShaderNodeCubemapUniform", "VisualShaderNodeCubemapParameter" },
+ { "VisualShaderNodeTextureUniform", "VisualShaderNodeTexture2DParameter" },
+ { "VisualShaderNodeTextureUniformTriplanar", "VisualShaderNodeTextureParameterTriplanar" },
+ { "VisualShaderNodeTransformUniform", "VisualShaderNodeTransformParameter" },
+ { "VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Parameter" },
+ { "VisualShaderNodeUniform", "VisualShaderNodeParameter" },
+ { "VisualShaderNodeUniformRef", "VisualShaderNodeParameterRef" },
{ "WebRTCDataChannelGDNative", "WebRTCDataChannelExtension" },
{ "WebRTCMultiplayer", "WebRTCMultiplayerPeer" },
{ "WebRTCPeerConnectionGDNative", "WebRTCPeerConnectionExtension" },
@@ -1449,8 +1554,7 @@ static const char *class_renames[][2] = {
{ nullptr, nullptr },
};
-// TODO - this colors needs to be validated(not all are valid)
-static const char *colors_renames[][2] = {
+static const char *color_renames[][2] = {
{ "aliceblue", "ALICE_BLUE" },
{ "antiquewhite", "ANTIQUE_WHITE" },
{ "aqua", "AQUA" },
@@ -1603,64 +1707,246 @@ static const char *colors_renames[][2] = {
class ProjectConverter3To4::RegExContainer {
public:
+ // Custom GDScript.
RegEx reg_is_empty = RegEx("\\bempty\\(");
RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])");
RegEx reg_json_to = RegEx("\\bto_json\\b");
- RegEx reg_json_parse = RegEx("([\t]{0,})([^\n]+)parse_json\\(([^\n]+)");
- RegEx reg_json_non_new = RegEx("([\t]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)");
+ RegEx reg_json_parse = RegEx("([\t ]{0,})([^\n]+)parse_json\\(([^\n]+)");
+ RegEx reg_json_non_new = RegEx("([\t ]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)");
RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)");
RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)");
RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)");
RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$");
RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$");
RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)");
- RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)");
RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)");
RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)");
RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)");
+ RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)");
+
+ // GDScript keywords.
+ RegEx keyword_gdscript_tool = RegEx("^tool");
+ RegEx keyword_gdscript_export_single = RegEx("^export");
+ RegEx keyword_gdscript_export_mutli = RegEx("([\t]+)export\\b");
+ RegEx keyword_gdscript_onready = RegEx("^onready");
+ RegEx keyword_gdscript_remote = RegEx("^remote func");
+ RegEx keyword_gdscript_remotesync = RegEx("^remotesync func");
+ RegEx keyword_gdscript_sync = RegEx("^sync func");
+ RegEx keyword_gdscript_slave = RegEx("^slave func");
+ RegEx keyword_gdscript_puppet = RegEx("^puppet func");
+ RegEx keyword_gdscript_puppetsync = RegEx("^puppetsync func");
+ RegEx keyword_gdscript_master = RegEx("^master func");
+ RegEx keyword_gdscript_mastersync = RegEx("^mastersync func");
+
+ // CSharp keywords.
+ RegEx keyword_csharp_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_master = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_mastersync = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
+
+ // Colors.
+ LocalVector<RegEx *> color_regexes;
+ LocalVector<String> color_renamed;
+
+ // Classes.
+ LocalVector<RegEx *> class_tscn_regexes;
+ LocalVector<RegEx *> class_gd_regexes;
+ LocalVector<RegEx *> class_shader_regexes;
+
+ LocalVector<RegEx *> class_regexes;
+
+ RegEx class_temp_tscn = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b");
+ RegEx class_temp_gd = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
+ RegEx class_temp_shader = RegEx("\\bTEMP_RENAMED_CLASS.shader\\b");
+
+ LocalVector<String> class_temp_tscn_renames;
+ LocalVector<String> class_temp_gd_renames;
+ LocalVector<String> class_temp_shader_renames;
+
+ // Common.
+ LocalVector<RegEx *> enum_regexes;
+ LocalVector<RegEx *> gdscript_function_regexes;
+ LocalVector<RegEx *> project_settings_regexes;
+ LocalVector<RegEx *> gdscript_properties_regexes;
+ LocalVector<RegEx *> gdscript_signals_regexes;
+ LocalVector<RegEx *> shaders_regexes;
+ LocalVector<RegEx *> builtin_types_regexes;
+ LocalVector<RegEx *> csharp_function_regexes;
+ LocalVector<RegEx *> csharp_properties_regexes;
+ LocalVector<RegEx *> csharp_signal_regexes;
+
+ RegExContainer() {
+ // Common.
+ {
+ // Enum.
+ for (unsigned int current_index = 0; enum_renames[current_index][0]; current_index++) {
+ enum_regexes.push_back(memnew(RegEx(String("\\b") + enum_renames[current_index][0] + "\\b")));
+ }
+ // GDScript functions.
+ for (unsigned int current_index = 0; gdscript_function_renames[current_index][0]; current_index++) {
+ gdscript_function_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_function_renames[current_index][0] + "\\b")));
+ }
+ // Project Settings.
+ for (unsigned int current_index = 0; project_settings_renames[current_index][0]; current_index++) {
+ project_settings_regexes.push_back(memnew(RegEx(String("\\b") + project_settings_renames[current_index][0] + "\\b")));
+ }
+ // GDScript properties.
+ for (unsigned int current_index = 0; gdscript_properties_renames[current_index][0]; current_index++) {
+ gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_properties_renames[current_index][0] + "\\b")));
+ }
+ // GDScript Signals.
+ for (unsigned int current_index = 0; gdscript_signals_renames[current_index][0]; current_index++) {
+ gdscript_signals_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_signals_renames[current_index][0] + "\\b")));
+ }
+ // Shaders.
+ for (unsigned int current_index = 0; shaders_renames[current_index][0]; current_index++) {
+ shaders_regexes.push_back(memnew(RegEx(String("\\b") + shaders_renames[current_index][0] + "\\b")));
+ }
+ // Builtin types.
+ for (unsigned int current_index = 0; builtin_types_renames[current_index][0]; current_index++) {
+ builtin_types_regexes.push_back(memnew(RegEx(String("\\b") + builtin_types_renames[current_index][0] + "\\b")));
+ }
+ // CSharp function renames.
+ for (unsigned int current_index = 0; csharp_function_renames[current_index][0]; current_index++) {
+ csharp_function_regexes.push_back(memnew(RegEx(String("\\b") + csharp_function_renames[current_index][0] + "\\b")));
+ }
+ // CSharp properties renames.
+ for (unsigned int current_index = 0; csharp_properties_renames[current_index][0]; current_index++) {
+ csharp_properties_regexes.push_back(memnew(RegEx(String("\\b") + csharp_properties_renames[current_index][0] + "\\b")));
+ }
+ // CSharp signals renames.
+ for (unsigned int current_index = 0; csharp_signals_renames[current_index][0]; current_index++) {
+ csharp_signal_regexes.push_back(memnew(RegEx(String("\\b") + csharp_signals_renames[current_index][0] + "\\b")));
+ }
+ }
+
+ // Colors.
+ {
+ for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) {
+ color_regexes.push_back(memnew(RegEx(String("\\bColor.") + color_renames[current_index][0] + "\\b")));
+ color_renamed.push_back(String("Color.") + color_renames[current_index][1]);
+ }
+ }
+ // Classes.
+ {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ class_tscn_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b")));
+ class_gd_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b")));
+ class_shader_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b")));
+
+ class_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + "\\b")));
+
+ class_temp_tscn_renames.push_back(String(class_renames[current_index][0]) + ".tscn");
+ class_temp_gd_renames.push_back(String(class_renames[current_index][0]) + ".gd");
+ class_temp_shader_renames.push_back(String(class_renames[current_index][0]) + ".shader");
+ }
+ }
+ }
+ ~RegExContainer() {
+ for (unsigned int i = 0; i < color_regexes.size(); i++) {
+ memdelete(color_regexes[i]);
+ }
+ for (unsigned int i = 0; i < class_tscn_regexes.size(); i++) {
+ memdelete(class_tscn_regexes[i]);
+ memdelete(class_gd_regexes[i]);
+ memdelete(class_shader_regexes[i]);
+ memdelete(class_regexes[i]);
+ }
+ for (unsigned int i = 0; i < enum_regexes.size(); i++) {
+ memdelete(enum_regexes[i]);
+ }
+ for (unsigned int i = 0; i < gdscript_function_regexes.size(); i++) {
+ memdelete(gdscript_function_regexes[i]);
+ }
+ for (unsigned int i = 0; i < project_settings_regexes.size(); i++) {
+ memdelete(project_settings_regexes[i]);
+ }
+ for (unsigned int i = 0; i < gdscript_properties_regexes.size(); i++) {
+ memdelete(gdscript_properties_regexes[i]);
+ }
+ for (unsigned int i = 0; i < gdscript_signals_regexes.size(); i++) {
+ memdelete(gdscript_signals_regexes[i]);
+ }
+ for (unsigned int i = 0; i < shaders_regexes.size(); i++) {
+ memdelete(shaders_regexes[i]);
+ }
+ for (unsigned int i = 0; i < builtin_types_regexes.size(); i++) {
+ memdelete(builtin_types_regexes[i]);
+ }
+ for (unsigned int i = 0; i < csharp_function_regexes.size(); i++) {
+ memdelete(csharp_function_regexes[i]);
+ }
+ for (unsigned int i = 0; i < csharp_properties_regexes.size(); i++) {
+ memdelete(csharp_properties_regexes[i]);
+ }
+ for (unsigned int i = 0; i < csharp_signal_regexes.size(); i++) {
+ memdelete(csharp_signal_regexes[i]);
+ }
+ }
};
-// Function responsible for converting project
+ProjectConverter3To4::ProjectConverter3To4(int p_maximum_file_size_kb, int p_maximum_line_length) {
+ maximum_file_size = p_maximum_file_size_kb * 1024;
+ maximum_line_length = p_maximum_line_length;
+}
+
+// Function responsible for converting project.
int ProjectConverter3To4::convert() {
print_line("Starting conversion.");
+ uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
RegExContainer reg_container = RegExContainer();
+ int cached_maximum_line_length = maximum_line_length;
+ maximum_line_length = 10000; // Use only for tests bigger value, to not break them.
+
ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays.");
ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays.");
+ maximum_line_length = cached_maximum_line_length;
+
// Checking if folder contains valid Godot 3 project.
- // Project cannot be converted 2 times
+ // Project should not be converted more than once.
{
- String conventer_text = "; Project was converted by built-in tool to Godot 4.0";
+ String converter_text = "; Project was converted by built-in tool to Godot 4.0";
- ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), ERROR_CODE, "Current directory doesn't contains any Godot 3 project");
+ ERR_FAIL_COND_V_MSG(!FileAccess::exists("project.godot"), ERROR_CODE, "Current working directory doesn't contain a \"project.godot\" file for a Godot 3 project.");
Error err = OK;
String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
- ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file.");
- ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool.");
+ ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Unable to read \"project.godot\".");
+ ERR_FAIL_COND_V_MSG(project_godot_content.contains(converter_text), ERROR_CODE, "Project was already converted with this tool.");
Ref<FileAccess> file = FileAccess::open("project.godot", FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(file.is_null(), ERROR_CODE, "Failed to open project.godot file.");
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERROR_CODE, "Unable to open \"project.godot\".");
- file->store_string(conventer_text + "\n" + project_godot_content);
+ file->store_string(converter_text + "\n" + project_godot_content);
}
Vector<String> collected_files = check_for_files();
uint32_t converted_files = 0;
- // Check file by file
+ // Check file by file.
for (int i = 0; i < collected_files.size(); i++) {
String file_name = collected_files[i];
- Error err = OK;
- String file_content = FileAccess::get_file_as_string(file_name, &err);
- ERR_CONTINUE_MSG(err != OK, "Failed to read content of \"" + file_name + "\".");
- uint64_t hash_before = file_content.hash64();
- uint64_t file_size = file_content.size();
- print_line("Trying to convert\t" + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB");
+ Vector<String> lines;
+ uint32_t ignored_lines = 0;
+ {
+ Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
+ ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to read content of \"%s\".", file_name));
+ while (!file->eof_reached()) {
+ String line = file->get_line();
+ lines.append(line);
+ }
+ }
+ String file_content_before = collect_string_from_vector(lines);
+ uint64_t hash_before = file_content_before.hash();
+ uint64_t file_size = file_content_before.size();
+ print_line(vformat("Trying to convert\t%d/%d file - \"%s\" with size - %d KB", i + 1, collected_files.size(), file_name.trim_prefix("res://"), file_size / 1024));
Vector<String> reason;
bool is_ignored = false;
@@ -1671,112 +1957,130 @@ int ProjectConverter3To4::convert() {
file_name = file_name.replace(".shader", ".gdshader");
}
- if (file_size < CONVERSION_MAX_FILE_SIZE) {
- // TSCN must be the same work exactly same as .gd file because it may contains builtin script
+ if (file_size < uint64_t(maximum_file_size)) {
+ // ".tscn" must work exactly the same as ".gd" files because they may contain built-in Scripts.
if (file_name.ends_with(".gd")) {
- rename_classes(file_content); // Using only specialized function
+ rename_classes(lines, reg_container); // Using only specialized function.
- rename_common(enum_renames, file_content);
- rename_enums(file_content); // Require to additional rename
+ rename_common(enum_renames, reg_container.enum_regexes, lines);
+ rename_colors(lines, reg_container); // Require to additional rename.
- rename_common(gdscript_function_renames, file_content);
- rename_gdscript_functions(file_content, reg_container, false); // Require to additional rename
+ rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines);
+ rename_gdscript_functions(lines, reg_container, false); // Require to additional rename.
- rename_common(project_settings_renames, file_content);
- rename_gdscript_keywords(file_content);
- rename_common(gdscript_properties_renames, file_content);
- rename_common(gdscript_signals_renames, file_content);
- rename_common(shaders_renames, file_content);
- rename_common(builtin_types_renames, file_content);
+ rename_common(project_settings_renames, reg_container.project_settings_regexes, lines);
+ rename_gdscript_keywords(lines, reg_container);
+ rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines);
+ rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
- custom_rename(file_content, "\\.shader", ".gdshader");
- custom_rename(file_content, "instance", "instantiate");
+ custom_rename(lines, "\\.shader", ".gdshader");
} else if (file_name.ends_with(".tscn")) {
- rename_classes(file_content); // Using only specialized function
-
- rename_common(enum_renames, file_content);
- rename_enums(file_content); // Require to additional rename
-
- rename_common(gdscript_function_renames, file_content);
- rename_gdscript_functions(file_content, reg_container, true); // Require to additional rename
-
- rename_common(project_settings_renames, file_content);
- rename_gdscript_keywords(file_content);
- rename_common(gdscript_properties_renames, file_content);
- rename_common(gdscript_signals_renames, file_content);
- rename_common(shaders_renames, file_content);
- rename_common(builtin_types_renames, file_content);
-
- custom_rename(file_content, "\\.shader", ".gdshader");
- } else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods
- rename_classes(file_content); // Using only specialized function
- rename_common(csharp_function_renames, file_content);
- rename_common(builtin_types_renames, file_content);
- rename_common(csharp_properties_renames, file_content);
- rename_common(csharp_signals_renames, file_content);
- rename_csharp_functions(file_content);
- rename_csharp_attributes(file_content);
- custom_rename(file_content, "public class ", "public partial class ");
+ rename_classes(lines, reg_container); // Using only specialized function.
+
+ rename_common(enum_renames, reg_container.enum_regexes, lines);
+ rename_colors(lines, reg_container); // Require to do additional renames.
+
+ rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines);
+ rename_gdscript_functions(lines, reg_container, true); // Require to do additional renames.
+
+ rename_common(project_settings_renames, reg_container.project_settings_regexes, lines);
+ rename_gdscript_keywords(lines, reg_container);
+ rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines);
+ rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
+
+ custom_rename(lines, "\\.shader", ".gdshader");
+ } else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods.
+ rename_classes(lines, reg_container); // Using only specialized function.
+ rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
+ rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines);
+ rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines);
+ rename_csharp_functions(lines, reg_container);
+ rename_csharp_attributes(lines, reg_container);
+ custom_rename(lines, "public class ", "public partial class ");
} else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
- rename_common(shaders_renames, file_content);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
} else if (file_name.ends_with("tres")) {
- rename_classes(file_content); // Using only specialized function
+ rename_classes(lines, reg_container); // Using only specialized function.
- rename_common(shaders_renames, file_content);
- rename_common(builtin_types_renames, file_content);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
- custom_rename(file_content, "\\.shader", ".gdshader");
+ custom_rename(lines, "\\.shader", ".gdshader");
} else if (file_name.ends_with("project.godot")) {
- rename_common(project_settings_renames, file_content);
- rename_common(builtin_types_renames, file_content);
+ rename_common(project_settings_renames, reg_container.project_settings_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
} else if (file_name.ends_with(".csproj")) {
// TODO
} else {
ERR_PRINT(file_name + " is not supported!");
continue;
}
+
+ for (String &line : lines) {
+ if (uint64_t(line.length()) > maximum_line_length) {
+ ignored_lines += 1;
+ }
+ }
} else {
- reason.append(" ERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB");
+ reason.append(vformat(" ERROR: File has exceeded the maximum size allowed - %d KB", maximum_file_size / 1024));
is_ignored = true;
}
uint64_t end_time = Time::get_singleton()->get_ticks_msec();
-
- if (!is_ignored) {
- uint64_t hash_after = file_content.hash64();
- // Don't need to save file without any changes
- // Save if this is a shader, because it was renamed
+ if (is_ignored) {
+ String end_message = vformat(" Checking file took %d ms.", end_time - start_time);
+ print_line(end_message);
+ } else {
+ String file_content_after = collect_string_from_vector(lines);
+ uint64_t hash_after = file_content_after.hash64();
+ // Don't need to save file without any changes.
+ // Save if this is a shader, because it was renamed.
if (hash_before != hash_after || file_name.ends_with(".gdshader")) {
converted_files++;
Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::WRITE);
- ERR_CONTINUE_MSG(file.is_null(), "Failed to open \"" + file_name + "\" to save data to file.");
- file->store_string(file_content);
- reason.append(" File was changed, conversion took " + itos(end_time - start_time) + " ms.");
+ ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to apply changes to \"%s\", no writing access.", file_name));
+ file->store_string(file_content_after);
+ reason.append(vformat(" File was changed, conversion took %d ms.", end_time - start_time));
} else {
- reason.append(" File was not changed, checking took " + itos(end_time - start_time) + " ms.");
+ reason.append(vformat(" File was left unchanged, checking took %d ms.", end_time - start_time));
+ }
+ if (ignored_lines != 0) {
+ reason.append(vformat(" Ignored %d lines, because their length exceeds maximum allowed characters - %d.", ignored_lines, maximum_line_length));
}
}
for (int k = 0; k < reason.size(); k++) {
print_line(reason[k]);
}
}
-
- print_line("Conversion ended - all files(" + itos(collected_files.size()) + "), converted files(" + itos(converted_files) + "), not converted files(" + itos(collected_files.size() - converted_files) + ").");
+ print_line(vformat("Conversion ended - all files(%d), converted files: (%d), not converted files: (%d).", collected_files.size(), converted_files, collected_files.size() - converted_files));
+ uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
+ print_line(vformat("Conversion of all files took %10.3f seconds.", (conversion_end_time - conversion_start_time) / 1000.0));
return 0;
};
// Function responsible for validating project conversion.
int ProjectConverter3To4::validate_conversion() {
print_line("Starting checking if project conversion can be done.");
+ uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
RegExContainer reg_container = RegExContainer();
+ int cached_maximum_line_length = maximum_line_length;
+ maximum_line_length = 10000; // To avoid breaking the tests, only use this for the their larger value.
+
ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays.");
ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays.");
+ maximum_line_length = cached_maximum_line_length;
+
// Checking if folder contains valid Godot 3 project.
- // Project cannot be converted 2 times
+ // Project should not be converted more than once.
{
String conventer_text = "; Project was converted by built-in tool to Godot 4.0";
@@ -1786,28 +2090,29 @@ int ProjectConverter3To4::validate_conversion() {
String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file.");
- ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool.");
+ ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), ERROR_CODE, "Project already was converted with this tool.");
}
Vector<String> collected_files = check_for_files();
uint32_t converted_files = 0;
- // Check file by file
+ // Check file by file.
for (int i = 0; i < collected_files.size(); i++) {
String file_name = collected_files[i];
- Vector<String> file_content;
+ Vector<String> lines;
+ uint32_t ignored_lines = 0;
uint64_t file_size = 0;
{
Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
- ERR_CONTINUE_MSG(file.is_null(), "Failed to read content of \"" + file_name + "\".");
+ ERR_CONTINUE_MSG(file.is_null(), vformat("Unable to read content of \"%s\".", file_name));
while (!file->eof_reached()) {
String line = file->get_line();
file_size += line.size();
- file_content.append(line);
+ lines.append(line);
}
}
- print_line("Checking for conversion - " + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB");
+ print_line(vformat("Checking for conversion - %d/%d file - \"%s\" with size - %d KB"), i + 1, collected_files.size(), file_name.trim_prefix("res://"), file_size / 1024);
Vector<String> changed_elements;
Vector<String> reason;
@@ -1815,79 +2120,88 @@ int ProjectConverter3To4::validate_conversion() {
uint64_t start_time = Time::get_singleton()->get_ticks_msec();
if (file_name.ends_with(".shader")) {
- reason.append("\tFile extension will be renamed from `shader` to `gdshader`.");
+ reason.append("\tFile extension will be renamed from \"shader\" to \"gdshader\".");
}
- if (file_size < CONVERSION_MAX_FILE_SIZE) {
+ if (file_size < uint64_t(maximum_file_size)) {
if (file_name.ends_with(".gd")) {
- changed_elements.append_array(check_for_rename_classes(file_content));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(enum_renames, file_content));
- changed_elements.append_array(check_for_rename_enums(file_content));
+ changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines));
+ changed_elements.append_array(check_for_rename_colors(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, false));
+ changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, false));
- changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_keywords(file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content));
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container));
+ changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
- changed_elements.append_array(check_for_custom_rename(file_content, "instance", "instantiate"));
- changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader"));
+ changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
} else if (file_name.ends_with(".tscn")) {
- changed_elements.append_array(check_for_rename_classes(file_content));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(enum_renames, file_content));
- changed_elements.append_array(check_for_rename_enums(file_content));
+ changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines));
+ changed_elements.append_array(check_for_rename_colors(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, true));
+ changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, true));
- changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_keywords(file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content));
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container));
+ changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
- changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader"));
+ changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
} else if (file_name.ends_with(".cs")) {
- changed_elements.append_array(check_for_rename_common(class_renames, file_content));
- changed_elements.append_array(check_for_rename_common(csharp_function_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
- changed_elements.append_array(check_for_rename_common(csharp_properties_renames, file_content));
- changed_elements.append_array(check_for_rename_common(csharp_signals_renames, file_content));
- changed_elements.append_array(check_for_rename_csharp_functions(file_content));
- changed_elements.append_array(check_for_rename_csharp_attributes(file_content));
- changed_elements.append_array(check_for_custom_rename(file_content, "public class ", "public partial class "));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
+ changed_elements.append_array(check_for_rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines));
+ changed_elements.append_array(check_for_rename_csharp_functions(lines, reg_container));
+ changed_elements.append_array(check_for_rename_csharp_attributes(lines, reg_container));
+ changed_elements.append_array(check_for_custom_rename(lines, "public class ", "public partial class "));
} else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
} else if (file_name.ends_with("tres")) {
- changed_elements.append_array(check_for_rename_classes(file_content));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
- changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader"));
+ changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
} else if (file_name.ends_with("project.godot")) {
- changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
} else if (file_name.ends_with(".csproj")) {
// TODO
} else {
- ERR_PRINT(file_name + " is not supported!");
+ ERR_PRINT(vformat("\"%s\", is not supported!", file_name));
continue;
}
+
+ for (String &line : lines) {
+ if (uint64_t(line.length()) > maximum_line_length) {
+ ignored_lines += 1;
+ }
+ }
} else {
- reason.append("\tERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB");
+ reason.append(vformat("\tERROR: File has exceeded the maximum size allowed - %d KB.", maximum_file_size / 1024));
is_ignored = true;
}
uint64_t end_time = Time::get_singleton()->get_ticks_msec();
- print_line(" Checking file took " + itos(end_time - start_time) + " ms.");
+ String end_message = vformat(" Checking file took %10.3f ms.", (end_time - start_time) / 1000.0);
+ if (ignored_lines != 0) {
+ end_message += vformat(" Ignored %d lines, because their length exceeds maximum allowed characters - %d.", ignored_lines, maximum_line_length);
+ }
+ print_line(end_message);
for (int k = 0; k < reason.size(); k++) {
print_line(reason[k]);
@@ -1902,11 +2216,13 @@ int ProjectConverter3To4::validate_conversion() {
}
}
- print_line("Checking for valid conversion ended - all files(" + itos(collected_files.size()) + "), files which would be converted(" + itos(converted_files) + "), files which would not be converted(" + itos(collected_files.size() - converted_files) + ").");
+ print_line(vformat("Checking for valid conversion ended - all files(%d), files which would be converted(%d), files which would not be converted(%d).", collected_files.size(), converted_files, collected_files.size() - converted_files));
+ uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
+ print_line(vformat("Conversion of all files took %10.3f seconds.", (conversion_end_time - conversion_start_time) / 1000.0));
return 0;
}
-// Collect files which will be checked, it will not touch txt, mp4, wav etc. files
+// Collect files which will be checked, excluding ".txt", ".mp4", ".wav" etc. files.
Vector<String> ProjectConverter3To4::check_for_files() {
Vector<String> collected_files = Vector<String>();
@@ -1916,7 +2232,7 @@ Vector<String> ProjectConverter3To4::check_for_files() {
core_bind::Directory dir = core_bind::Directory();
while (!directories_to_check.is_empty()) {
String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function?
- directories_to_check.resize(directories_to_check.size() - 1); // Remove last element
+ directories_to_check.resize(directories_to_check.size() - 1); // Remove last element.
if (dir.open(path) == OK) {
dir.set_include_hidden(true);
dir.list_dir_begin();
@@ -1929,14 +2245,14 @@ Vector<String> ProjectConverter3To4::check_for_files() {
continue;
}
if (dir.current_is_dir()) {
- directories_to_check.append(current_dir.plus_file(file_name) + "/");
+ directories_to_check.append(current_dir.path_join(file_name) + "/");
} else {
bool proper_extension = false;
if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj"))
proper_extension = true;
if (proper_extension) {
- collected_files.append(current_dir.plus_file(file_name));
+ collected_files.append(current_dir.path_join(file_name));
}
}
file_name = dir.get_next();
@@ -1948,216 +2264,222 @@ Vector<String> ProjectConverter3To4::check_for_files() {
return collected_files;
}
-bool ProjectConverter3To4::test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what) {
- String got = name;
- (this->*func)(got);
- if (expected != got) {
- ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`");
- return false;
- }
+// Test expected results of gdscript
+bool ProjectConverter3To4::test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin_script) {
+ Vector<String> got = name.split("\n");
+ (this->*func)(got, reg_container, builtin_script);
+ String got_str = collect_string_from_vector(got);
+ ERR_FAIL_COND_V_MSG(expected != got_str, false, vformat("Failed to convert %s \"%s\" to \"%s\", got instead \"%s\"", what, name, expected, got_str));
return true;
}
-bool ProjectConverter3To4::test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin_script) {
- String got = name;
- (this->*func)(got, reg_container, builtin_script);
- if (expected != got) {
- ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`");
- return false;
- }
+bool ProjectConverter3To4::test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer &reg_container) {
+ Vector<String> got = name.split("\n");
+ (this->*func)(got, reg_container);
+ String got_str = collect_string_from_vector(got);
+ ERR_FAIL_COND_V_MSG(expected != got_str, false, vformat("Failed to convert %s \"%s\" to \"%s\", got instead \"%s\"", what, name, expected, got_str));
return true;
}
-bool ProjectConverter3To4::test_conversion_single_normal(String name, String expected, const char *array[][2], String what) {
- String got = name;
- rename_common(array, got);
- if (expected != got) {
- ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`");
- return false;
- }
+bool ProjectConverter3To4::test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> &regex_cache, String what) {
+ Vector<String> got = name.split("\n");
+ rename_common(array, regex_cache, got);
+ String got_str = collect_string_from_vector(got);
+ ERR_FAIL_COND_V_MSG(expected != got_str, false, vformat("Failed to convert %s \"%s\" to \"%s\", got instead \"%s\"", what, name, expected, got_str));
+
return true;
}
-// Validate if conversions are proper
-bool ProjectConverter3To4::test_conversion(const RegExContainer &reg_container) {
+// Validate if conversions are proper.
+bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
bool valid = true;
- valid = valid & test_conversion_single_normal("Spatial", "Node3D", class_renames, "class");
-
- valid = valid & test_conversion_single_normal("TYPE_REAL", "TYPE_FLOAT", enum_renames, "enum");
-
- valid = valid & test_conversion_single_normal("can_instance", "can_instantiate", gdscript_function_renames, "gdscript function");
+ valid = valid && test_conversion_basic("TYPE_REAL", "TYPE_FLOAT", enum_renames, reg_container.enum_regexes, "enum");
- valid = valid & test_conversion_single_normal("CanInstance", "CanInstantiate", csharp_function_renames, "csharp function");
+ valid = valid && test_conversion_basic("can_instance", "can_instantiate", gdscript_function_renames, reg_container.gdscript_function_regexes, "gdscript function");
- valid = valid & test_conversion_single_normal("translation", "position", gdscript_properties_renames, "gdscript property");
+ valid = valid && test_conversion_basic("CanInstance", "CanInstantiate", csharp_function_renames, reg_container.csharp_function_regexes, "csharp function");
- valid = valid & test_conversion_single_normal("Translation", "Position", csharp_properties_renames, "csharp property");
+ valid = valid && test_conversion_basic("translation", "position", gdscript_properties_renames, reg_container.gdscript_properties_regexes, "gdscript property");
- valid = valid & test_conversion_single_normal("NORMALMAP", "NORMAL_MAP", shaders_renames, "shader");
+ valid = valid && test_conversion_basic("Translation", "Position", csharp_properties_renames, reg_container.csharp_properties_regexes, "csharp property");
- valid = valid & test_conversion_single_normal("text_entered", "text_submitted", gdscript_signals_renames, "gdscript signal");
+ valid = valid && test_conversion_basic("NORMALMAP", "NORMAL_MAP", shaders_renames, reg_container.shaders_regexes, "shader");
- valid = valid & test_conversion_single_normal("TextEntered", "TextSubmitted", csharp_signals_renames, "csharp signal");
+ valid = valid && test_conversion_basic("text_entered", "text_submitted", gdscript_signals_renames, reg_container.gdscript_signals_regexes, "gdscript signal");
- valid = valid & test_conversion_single_normal("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, "project setting");
+ valid = valid && test_conversion_basic("TextEntered", "TextSubmitted", csharp_signals_renames, reg_container.csharp_signal_regexes, "csharp signal");
- valid = valid & test_conversion_single_normal("Transform", "Transform3D", builtin_types_renames, "builtin type");
+ valid = valid && test_conversion_basic("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, reg_container.project_settings_regexes, "project setting");
- // Custom Renames
+ valid = valid && test_conversion_basic("Transform", "Transform3D", builtin_types_renames, reg_container.builtin_types_regexes, "builtin type");
- valid = valid & test_conversion_single_additional("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp");
- valid = valid & test_conversion_single_additional("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp");
- valid = valid & test_conversion_single_additional("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename");
+ // Custom Renames.
- valid = valid & test_conversion_single_additional("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
- valid = valid & test_conversion_single_additional("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp");
+ valid = valid && test_conversion_with_regex("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename", reg_container);
- valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
- valid = valid & test_conversion_single_additional_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_with_regex("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid && test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+
+ valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
+ valid = valid && test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
-
- valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
-
- valid = valid & test_conversion_single_additional_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround
- valid = valid & test_conversion_single_additional_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin(" aa", " aa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\taa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("\t aa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin(" \taa", " \taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid & test_conversion_single_additional_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
-
- valid = valid & test_conversion_single_additional("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_enums, "custom rename");
+ valid = valid && test_conversion_with_regex("extends CSGBox", "extends CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid && test_conversion_with_regex("CSGBox", "CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid && test_conversion_with_regex("Spatial", "Node3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid && test_conversion_with_regex("Spatial.tscn", "Spatial.tscn", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid && test_conversion_with_regex("Spatial.gd", "Spatial.gd", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid && test_conversion_with_regex("Spatial.shader", "Spatial.shader", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid && test_conversion_with_regex("Spatial.other", "Node3D.other", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+
+ valid = valid && test_conversion_with_regex("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid && test_conversion_with_regex("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+
+ valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
+
+ valid = valid && test_conversion_gdscript_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround
+ valid = valid && test_conversion_gdscript_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("func _init(", "func _init(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("map_to_world(a, b,c)", "map_to_local(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a,b,c,d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("button.pressed SF", "button.pressed SF", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "custom rename", reg_container);
// Custom rule conversion
{
String from = "instance";
String to = "instantiate";
String name = "AA.instance()";
- String got = "AA.instance()";
+ Vector<String> got = String("AA.instance()").split("\n");
String expected = "AA.instantiate()";
custom_rename(got, from, to);
- if (got != expected) {
- ERR_PRINT("Failed to convert custom rename `" + name + "` to `" + expected + "`, got instead `" + got + "`");
+ String got_str = collect_string_from_vector(got);
+ if (got_str != expected) {
+ ERR_PRINT(vformat("Failed to convert custom rename \"%s\" to \"%s\", got \"%s\", instead.", name, expected, got_str));
}
- valid = valid & (got == expected);
+ valid = valid && (got_str == expected);
}
// get_object_of_execution
@@ -2166,27 +2488,36 @@ bool ProjectConverter3To4::test_conversion(const RegExContainer &reg_container)
String expected = "kieliszek.";
String got = get_object_of_execution(base);
if (got != expected) {
- ERR_PRINT("Failed to get proper data from get_object_of_execution `" + base + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
{
String base = "r.";
String expected = "r.";
String got = get_object_of_execution(base);
if (got != expected) {
- ERR_PRINT("Failed to get proper data from get_object_of_execution `" + base + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
{
String base = "mortadela(";
String expected = "";
String got = get_object_of_execution(base);
if (got != expected) {
- ERR_PRINT("Failed to get proper data from get_object_of_execution `" + base + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
+ }
+ valid = valid && (got == expected);
+}
+{
+ String base = "var node = $world/ukraine/lviv.";
+ String expected = "$world/ukraine/lviv.";
+ String got = get_object_of_execution(base);
+ if (got != expected) {
+ ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
}
// get_starting_space
@@ -2195,9 +2526,9 @@ bool ProjectConverter3To4::test_conversion(const RegExContainer &reg_container)
String expected = "\t\t\t";
String got = get_starting_space(base);
if (got != expected) {
- ERR_PRINT("Failed to get proper data from get_starting_space `" + base + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from get_object_of_execution. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", base, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
// Parse Arguments
{
@@ -2209,9 +2540,9 @@ bool ProjectConverter3To4::test_conversion(const RegExContainer &reg_container)
got += part + "|||";
}
if (got != expected) {
- ERR_PRINT("Failed to get proper data from parse_arguments `" + line + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
{
String line = "(a , b , c)";
@@ -2222,9 +2553,9 @@ bool ProjectConverter3To4::test_conversion(const RegExContainer &reg_container)
got += part + "|||";
}
if (got != expected) {
- ERR_PRINT("Failed to get proper data from parse_arguments `" + line + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
{
String line = "(a , \"b,\" , c)";
@@ -2235,9 +2566,9 @@ bool ProjectConverter3To4::test_conversion(const RegExContainer &reg_container)
got += part + "|||";
}
if (got != expected) {
- ERR_PRINT("Failed to get proper data from parse_arguments `" + line + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
{
String line = "(a , \"(,),,,,\" , c)";
@@ -2248,174 +2579,148 @@ bool ProjectConverter3To4::test_conversion(const RegExContainer &reg_container)
got += part + "|||";
}
if (got != expected) {
- ERR_PRINT("Failed to get proper data from parse_arguments `" + line + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ ERR_PRINT(vformat("Failed to get proper data from parse_arguments. \"%s\" should return \"%s\"(%d), got \"%s\"(%d), instead.", line, expected, expected.size(), got, got.size()));
}
- valid = valid & (got == expected);
+ valid = valid && (got == expected);
}
return valid;
}
-// Validate in all arrays if names don't do cyclic renames `Node` -> `Node2D` | `Node2D` -> `2DNode`
+// Validate in all arrays if names don't do cyclic renames "Node" -> "Node2D" | "Node2D" -> "2DNode"
bool ProjectConverter3To4::test_array_names() {
bool valid = true;
Vector<String> names = Vector<String>();
- // Validate if all classes are valid
+ // Validate if all classes are valid.
{
- int current_index = 0;
- while (class_renames[current_index][0]) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
const String old_class = class_renames[current_index][0];
const String new_class = class_renames[current_index][1];
- // Light2D, Texture, Viewport are special classes(probably virtual ones)
+ // Light2D, Texture, Viewport are special classes(probably virtual ones).
if (ClassDB::class_exists(StringName(old_class)) && old_class != "Light2D" && old_class != "Texture" && old_class != "Viewport") {
- ERR_PRINT(String("Class `") + old_class + "` exists in Godot 4.0, so cannot be renamed to something else.");
- valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI
+ ERR_PRINT(vformat("Class \"%s\" exists in Godot 4.0, so it cannot be renamed to something else.", old_class));
+ valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
}
- // Callable is special class, to which normal classes may be renamed
+ // Callable is special class, to which normal classes may be renamed.
if (!ClassDB::class_exists(StringName(new_class)) && new_class != "Callable") {
- ERR_PRINT(String("Class `") + new_class + "` doesn't exists in Godot 4.0, so cannot be used in conversion.");
- valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI
- }
- current_index++;
- }
- }
-
- // // TODO To be able to fully work, it needs https://github.com/godotengine/godot/pull/49053
- // // TODO this needs to be changed to hashset when available https://github.com/godotengine/godot-proposals/issues/867, to speedup searchng
- // {
- // OrderedHashMap<String, bool> all_functions;
-
- // List<StringName> classes_list;
- // ClassDB::get_class_list(&classes_list);
- // for (StringName &name_of_class : classes_list) {
- // List<MethodInfo> method_list;
- // ClassDB::get_method_list(name_of_class, &method_list, true);
- // for (MethodInfo &function_data : method_list) {
- // if (!all_functions.has(function_data.name)) {
- // all_functions.insert(function_data.name, false);
- // }
- // }
- // }
-
- // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
- // List<MethodInfo> method_list;
- // Variant::get_method_list_by_type(&method_list, Variant::Type(type));
- // for (MethodInfo &function_data : method_list) {
- // if (!all_functions.has(function_data.name)) {
- // all_functions.insert(function_data.name, false);
- // }
- // }
- // }
-
- // int current_element = 0;
- // while (gdscript_function_renames[current_element][0] != nullptr) {
- // if (!all_functions.has(gdscript_function_renames[current_element][1])) {
- // ERR_PRINT(String("Missing gdscript function in pair (") + gdscript_function_renames[current_element][0] + " - ===> " + gdscript_function_renames[current_element][1] + " <===)");
- // valid = false;
- // }
- // // // DEBUG, disable below after tests
- // // if (all_functions.has(gdscript_function_renames[current_element][0])) {
- // // String used_in_classes = "";
- // //
- // // for (StringName &name_of_class : classes_list) {
- // // List<MethodInfo> method_list;
- // // ClassDB::get_method_list(name_of_class, &method_list, true);
- // // for (MethodInfo &function_data : method_list) {
- // // if (function_data.name == gdscript_function_renames[current_element][0]) {
- // // used_in_classes += String(name_of_class) + ", ";
- // // }
- // // }
- // // }
- // // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
- // // List<MethodInfo> method_list;
- // // Variant::get_method_list_by_type(&method_list, Variant::Type(type));
- // // for (MethodInfo &function_data : method_list) {
- // // if (function_data.name == gdscript_function_renames[current_element][0]) {
- // // used_in_classes += Variant::get_type_name(Variant::Type(type)) + ", ";
- // // }
- // // }
- // // }
- // // used_in_classes = used_in_classes.trim_suffix(", ");
- // //
- // // WARN_PRINT(String("Godot contains function which will be renamed in pair ( ===> ") + gdscript_function_renames[current_element][0] + " <=== - " + gdscript_function_renames[current_element][1] + ") in class " + used_in_classes + " - check for possible invalid rule.");
- // // }
- // current_element++;
- // }
- // }
-
- valid = valid & test_single_array(enum_renames);
- valid = valid & test_single_array(class_renames, true);
- valid = valid & test_single_array(gdscript_function_renames, true);
- valid = valid & test_single_array(csharp_function_renames, true);
- valid = valid & test_single_array(gdscript_properties_renames);
- valid = valid & test_single_array(csharp_properties_renames);
- valid = valid & test_single_array(shaders_renames);
- valid = valid & test_single_array(gdscript_signals_renames);
- valid = valid & test_single_array(project_settings_renames);
- valid = valid & test_single_array(builtin_types_renames);
- valid = valid & test_single_array(colors_renames);
+ ERR_PRINT(vformat("Class \"%s\" does not exist in Godot 4.0, so it cannot be used in the conversion.", old_class));
+ valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI.
+ }
+ }
+ }
+
+ {
+ HashSet<String> all_functions;
+
+ // List of excluded functions from builtin types and global namespace, because currently it is not possible to get list of functions from them.
+ // This will be available when https://github.com/godotengine/godot/pull/49053 or similar will be included into Godot.
+ static const char *builtin_types_excluded_functions[] = { "dict_to_inst", "inst_to_dict", "bytes_to_var", "bytes_to_var_with_objects", "db_to_linear", "deg_to_rad", "linear_to_db", "rad_to_deg", "randf_range", "snapped", "str_to_var", "var_to_str", "var_to_bytes", "var_to_bytes_with_objects", "move_toward", "uri_encode", "uri_decode", "remove_at", "get_rotation_quaternion", "clamp", "grow_side", "is_absolute_path", "is_valid_int", "lerp", "to_ascii_buffer", "to_utf8_buffer", "to_utf32_buffer", "snapped", "remap", nullptr };
+ for (int current_index = 0; builtin_types_excluded_functions[current_index]; current_index++) {
+ all_functions.insert(builtin_types_excluded_functions[current_index]);
+ }
+
+ // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
+ // List<MethodInfo> method_list;
+ // Variant::get_method_list_by_type(&method_list, Variant::Type(type));
+ // for (MethodInfo &function_data : method_list) {
+ // if (!all_functions.has(function_data.name)) {
+ // all_functions.insert(function_data.name);
+ // }
+ // }
+ // }
+
+ List<StringName> classes_list;
+ ClassDB::get_class_list(&classes_list);
+ for (StringName &name_of_class : classes_list) {
+ List<MethodInfo> method_list;
+ ClassDB::get_method_list(name_of_class, &method_list, true);
+ for (MethodInfo &function_data : method_list) {
+ if (!all_functions.has(function_data.name)) {
+ all_functions.insert(function_data.name);
+ }
+ }
+ }
+
+ int current_element = 0;
+ while (gdscript_function_renames[current_element][0] != nullptr) {
+ String name_3_x = gdscript_function_renames[current_element][0];
+ String name_4_0 = gdscript_function_renames[current_element][1];
+ if (!all_functions.has(gdscript_function_renames[current_element][1])) {
+ ERR_PRINT(vformat("Missing GDScript function in pair (%s - ===> %s <===)", name_3_x, name_4_0));
+ valid = false;
+ }
+ current_element++;
+ }
+ }
+ if (!valid) {
+ ERR_PRINT("Found function which is used in the converter, but it cannot be found in Godot 4. Rename this element or remove its entry if it's obsolete.");
+ }
+
+ valid = valid && test_single_array(enum_renames);
+ valid = valid && test_single_array(class_renames, true);
+ valid = valid && test_single_array(gdscript_function_renames, true);
+ valid = valid && test_single_array(csharp_function_renames, true);
+ valid = valid && test_single_array(gdscript_properties_renames, true);
+ valid = valid && test_single_array(csharp_properties_renames);
+ valid = valid && test_single_array(shaders_renames, true);
+ valid = valid && test_single_array(gdscript_signals_renames);
+ valid = valid && test_single_array(project_settings_renames);
+ valid = valid && test_single_array(builtin_types_renames);
+ valid = valid && test_single_array(color_renames);
return valid;
}
-// Validate in one array if names don't do cyclic renames `Node` -> `Node2D` | `Node2D` -> `2DNode`
-// Also checks if in name contains spaces at the end or beginning
-bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore_second_check) {
+// Validates the array to prevent cyclic renames, such as `Node` -> `Node2D`, then `Node2D` -> `2DNode`.
+// Also checks if names contain leading or trailing spaces.
+bool ProjectConverter3To4::test_single_array(const char *p_array[][2], bool p_ignore_4_0_name) {
bool valid = true;
- int current_index = 0;
Vector<String> names = Vector<String>();
- while (array[current_index][0]) {
- if (String(array[current_index][0]).begins_with(" ") || String(array[current_index][0]).ends_with(" ")) {
- {
- ERR_PRINT(String("Entry \"") + array[current_index][0] + "\" ends or stars with space.");
- valid = false;
- }
+ for (unsigned int current_index = 0; p_array[current_index][0]; current_index++) {
+ String name_3_x = p_array[current_index][0];
+ String name_4_0 = p_array[current_index][1];
+ if (name_3_x != name_3_x.strip_edges()) {
+ ERR_PRINT(vformat("Invalid Entry \"%s\" contains leading or trailing spaces.", name_3_x));
+ valid = false;
}
- if (names.has(array[current_index][0])) {
- ERR_PRINT(String("Found duplicated things, pair ( -> ") + array[current_index][0] + " , " + array[current_index][1] + ")");
+ if (names.has(name_3_x)) {
+ ERR_PRINT(vformat("Found duplicated entry, pair ( -> %s , %s)", name_3_x, name_4_0));
valid = false;
}
- names.append(array[current_index][0]);
+ names.append(name_3_x);
- if (String(array[current_index][1]).begins_with(" ") || String(array[current_index][1]).ends_with(" ")) {
- {
- ERR_PRINT(String("Entry \"") + array[current_index][1] + "\" ends or stars with space.");
- valid = false;
- }
+ if (name_4_0 != name_4_0.strip_edges()) {
+ ERR_PRINT(vformat("Invalid Entry \"%s\" contains leading or trailing spaces.", name_3_x));
+ valid = false;
}
- if (names.has(array[current_index][1])) {
- ERR_PRINT(String("Found duplicated things, pair (") + array[current_index][0] + " , ->" + array[current_index][1] + ")");
+ if (names.has(name_4_0)) {
+ ERR_PRINT(vformat("Found duplicated entry, pair ( -> %s , %s)", name_3_x, name_4_0));
valid = false;
}
- if (!ignore_second_check) {
- names.append(array[current_index][1]);
+ if (!p_ignore_4_0_name) {
+ names.append(name_4_0);
}
- current_index++;
}
return valid;
};
-// Returns arguments from given function execution, this cannot be really done as regex
+// Returns arguments from given function execution, this cannot be really done as regex.
// `abc(d,e(f,g),h)` -> [d], [e(f,g)], [h]
Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
Vector<String> parts;
int string_size = line.length();
- int current_index = 0;
- int start_part = 0; // Index of beginning of start par
+ int start_part = 0; // Index of beginning of start part.
int parts_counter = 0;
char32_t previous_character = '\0';
- bool is_inside_string = false; // if true, it ignore this 3 characters ( , ) inside string
+ bool is_inside_string = false; // If true, it ignores these 3 characters ( , ) inside string.
- if (line.count("(") != line.count(")")) {
- ERR_PRINT("Bug: substring should have equal number of open and close parenthess - `" + line + "`");
- return parts;
- }
+ ERR_FAIL_COND_V_MSG(line.count("(") != line.count(")"), parts, vformat("Converter internal bug: substring should have equal number of open and close parentheses in line - \"%s\".", line));
- while (current_index < string_size) {
+ for (int current_index = 0; current_index < string_size; current_index++) {
char32_t character = line.get(current_index);
switch (character) {
case '(': {
@@ -2433,6 +2738,21 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
}
break;
};
+ case '[': {
+ parts_counter++;
+ if (parts_counter == 1 && !is_inside_string) {
+ start_part = current_index;
+ }
+ break;
+ };
+ case ']': {
+ parts_counter--;
+ if (parts_counter == 0 && !is_inside_string) {
+ parts.append(line.substr(start_part, current_index - start_part));
+ start_part = current_index;
+ }
+ break;
+ };
case ',': {
if (parts_counter == 1 && !is_inside_string) {
parts.append(line.substr(start_part + 1, current_index - start_part - 1));
@@ -2445,7 +2765,6 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
is_inside_string = !is_inside_string;
}
}
- current_index++;
previous_character = character;
}
@@ -2460,12 +2779,11 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
return clean_parts;
}
-// Finds latest parenthess owned by function
+// Finds latest parenthesis owned by function.
// `function(abc(a,b),DD)):` finds this parenthess `function(abc(a,b),DD => ) <= ):`
-int ProjectConverter3To4::get_end_parenthess(const String &line) const {
- int current_index = 0;
+int ProjectConverter3To4::get_end_parenthesis(const String &line) const {
int current_state = 0;
- while (line.length() > current_index) {
+ for (int current_index = 0; line.length() > current_index; current_index++) {
char32_t character = line.get(current_index);
if (character == '(') {
current_state++;
@@ -2476,13 +2794,12 @@ int ProjectConverter3To4::get_end_parenthess(const String &line) const {
return current_index;
}
}
- current_index++;
}
return -1;
}
-// Connects arguments from vector to one string
-// Needed when after processing e.g. 2 arguments, later arguments are not changed in any way
+// Merges multiple arguments into a single String.
+// Needed when after processing e.g. 2 arguments, later arguments are not changed in any way.
String ProjectConverter3To4::connect_arguments(const Vector<String> &arguments, int from, int to) const {
if (to == -1) {
to = arguments.size();
@@ -2502,7 +2819,7 @@ String ProjectConverter3To4::connect_arguments(const Vector<String> &arguments,
return value;
}
-// Return spaces or tabs which starts line e.g. `\t\tmove_this` will return `\t\t`
+// Returns the indentation (spaces and tabs) at the start of the line e.g. `\t\tmove_this` returns `\t\t`.
String ProjectConverter3To4::get_starting_space(const String &line) const {
String empty_space;
int current_character = 0;
@@ -2534,251 +2851,263 @@ String ProjectConverter3To4::get_starting_space(const String &line) const {
return empty_space;
}
-// Return object which execute specific function
-// e.g. in `var roman = kieliszek.funkcja()` to this function is passed everything before function which we want to check
-// so it is `var roman = kieliszek.` and this function return `kieliszek.`
+// Returns the object that’s executing the function in the line.
+// e.g. Passing the line "var roman = kieliszek.funkcja()" to this function returns "kieliszek".
String ProjectConverter3To4::get_object_of_execution(const String &line) const {
int end = line.size() - 1; // Last one is \0
+ int variable_start = end - 1;
int start = end - 1;
+ bool is_possibly_nodepath = false;
+ bool is_valid_nodepath = false;
+
while (start >= 0) {
char32_t character = line[start];
- if ((character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || character == '.' || character == '_') {
+ bool is_variable_char = (character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || character == '.' || character == '_';
+ bool is_nodepath_start = character == '$';
+ bool is_nodepath_sep = character == '/';
+ if (is_variable_char || is_nodepath_start || is_nodepath_sep) {
if (start == 0) {
break;
+ } else if (is_nodepath_sep) {
+ // Freeze variable_start, try to fetch more chars since this might be a Node path literal.
+ is_possibly_nodepath = true;
+ } else if (is_nodepath_start) {
+ // Found $, this is a Node path literal.
+ is_valid_nodepath = true;
+ break;
+ }
+ if (!is_possibly_nodepath) {
+ variable_start--;
}
start--;
continue;
} else {
- start++; // Found invalid character, needs to be ignored
+ // Abandon all hope, this is neither a variable nor a Node path literal.
+ variable_start++; // Found invalid character, needs to be ignored.
break;
}
}
- return line.substr(start, (end - start));
+ if (is_valid_nodepath) {
+ variable_start = start;
+ }
+ return line.substr(variable_start, (end - variable_start));
}
-void ProjectConverter3To4::rename_enums(String &file_content) {
- int current_index = 0;
-
- // Rename colors
- if (file_content.find("Color.") != -1) {
- while (colors_renames[current_index][0]) {
- RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, String("Color.") + colors_renames[current_index][1], true);
- current_index++;
+void ProjectConverter3To4::rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ if (line.contains("Color.")) {
+ for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) {
+ line = reg_container.color_regexes[current_index]->sub(line, reg_container.color_renamed[current_index], true);
+ }
+ }
}
}
};
-Vector<String> ProjectConverter3To4::check_for_rename_enums(Vector<String> &file_content) {
- int current_index = 0;
+Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
- Vector<String> found_things;
-
- // Rename colors
- if (file_content.find("Color.") != -1) {
- while (colors_renames[current_index][0]) {
- RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
-
- int current_line = 1;
- for (String &line : file_content) {
- TypedArray<RegExMatch> reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, colors_renames[current_index][0], colors_renames[current_index][1], line));
+ int current_line = 1;
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ if (line.contains("Color.")) {
+ for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) {
+ TypedArray<RegExMatch> reg_match = reg_container.color_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, color_renames[current_index][0], color_renames[current_index][1], line));
+ }
}
- current_line++;
}
- current_index++;
}
+ current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_classes(String &file_content) {
- int current_index = 0;
-
- // TODO Maybe it is better way to not rename gd, tscn and other files which are named as classes
- while (class_renames[current_index][0]) {
- // Begin renaming workaround `Resource.gd` -> `RefCounter.gd`
- RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b");
- CRASH_COND(!reg_before.is_valid());
- file_content = reg_before.sub(file_content, "TEMP_RENAMED_CLASS.tscn", true);
- RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b");
- CRASH_COND(!reg_before2.is_valid());
- file_content = reg_before2.sub(file_content, "TEMP_RENAMED_CLASS.gd", true);
- RegEx reg_before3 = RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b");
- CRASH_COND(!reg_before3.is_valid());
- file_content = reg_before3.sub(file_content, "TEMP_RENAMED_CLASS.gd", true);
- // End
-
- RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, class_renames[current_index][1], true);
-
- // Begin renaming workaround `Resource.gd` -> `RefCounter.gd`
- RegEx reg_after = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b");
- CRASH_COND(!reg_after.is_valid());
- file_content = reg_after.sub(file_content, String(class_renames[current_index][0]) + ".tscn", true);
- RegEx reg_after2 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
- CRASH_COND(!reg_after2.is_valid());
- file_content = reg_after2.sub(file_content, String(class_renames[current_index][0]) + ".gd", true);
- RegEx reg_after3 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
- CRASH_COND(!reg_after3.is_valid());
- file_content = reg_after3.sub(file_content, String(class_renames[current_index][0]) + ".shader", true);
- // End
-
- current_index++;
- }
-
- // OS.get_ticks_msec -> Time.get_ticks_msec
- RegEx reg_time1 = RegEx("OS.get_ticks_msec");
- CRASH_COND(!reg_time1.is_valid());
- file_content = reg_time1.sub(file_content, "Time.get_ticks_msec", true);
- RegEx reg_time2 = RegEx("OS.get_ticks_usec");
- CRASH_COND(!reg_time2.is_valid());
- file_content = reg_time2.sub(file_content, "Time.get_ticks_usec", true);
-};
-
-Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &file_content) {
- int current_index = 0;
-
- Vector<String> found_things;
-
- while (class_renames[current_index][0]) {
- RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b");
- CRASH_COND(!reg_before.is_valid());
- RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b");
- CRASH_COND(!reg_before2.is_valid());
-
- RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
+void ProjectConverter3To4::rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ if (line.contains(class_renames[current_index][0])) {
+ bool found_ignored_items = false;
+ // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn.
+ if (line.contains(String(class_renames[current_index][0]) + ".")) {
+ found_ignored_items = true;
+ line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
+ line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
+ }
- int current_line = 1;
- for (String &line : file_content) {
- line = reg_before.sub(line, "TEMP_RENAMED_CLASS.tscn", true);
- line = reg_before2.sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ // Causal renaming Spatial -> Node3D.
+ line = reg_container.class_regexes[current_index]->sub(line, class_renames[current_index][1], true);
- TypedArray<RegExMatch> reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], line));
+ // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn.
+ if (found_ignored_items) {
+ line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
+ line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
+ line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
+ }
+ }
}
- current_line++;
}
- current_index++;
}
+};
+
+Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
- // TODO OS -> TIME
int current_line = 1;
- RegEx reg_time1 = RegEx("OS.get_ticks_msec");
- CRASH_COND(!reg_time1.is_valid());
- RegEx reg_time2 = RegEx("OS.get_ticks_usec");
- CRASH_COND(!reg_time2.is_valid());
- for (String &line : file_content) {
- String old = line;
- line = reg_time1.sub(line, "Time.get_ticks_msec", true);
- line = reg_time2.sub(line, "Time.get_ticks_usec", true);
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ if (line.contains(class_renames[current_index][0])) {
+ String old_line = line;
+ bool found_ignored_items = false;
+ // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn.
+ if (line.contains(String(class_renames[current_index][0]) + ".")) {
+ found_ignored_items = true;
+ line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
+ line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
+ }
+
+ // Causal renaming Spatial -> Node3D.
+ TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], old_line));
+ }
- if (old != line) {
- found_things.append(simple_line_formatter(current_line, old, line));
+ // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn.
+ if (found_ignored_items) {
+ line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
+ line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
+ line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
+ }
+ }
+ }
}
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_gdscript_functions(String &file_content, const RegExContainer &reg_container, bool builtin) {
- Vector<String> lines = file_content.split("\n");
-
+void ProjectConverter3To4::rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
for (String &line : lines) {
- process_gdscript_line(line, reg_container, builtin);
- }
-
- // Collect vector to string
- file_content = "";
- for (int i = 0; i < lines.size(); i++) {
- file_content += lines[i];
-
- if (i != lines.size() - 1) {
- file_content += "\n";
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ process_gdscript_line(line, reg_container, builtin);
}
}
};
-Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer &reg_container, bool builtin) {
+Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
int current_line = 1;
- Vector<String> found_things;
+ Vector<String> found_renames;
- for (String &line : file_content) {
- String old_line = line;
- process_gdscript_line(line, reg_container, builtin);
- if (old_line != line) {
- found_things.append(simple_line_formatter(current_line, old_line, line));
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old_line = line;
+ process_gdscript_line(line, reg_container, builtin);
+ if (old_line != line) {
+ found_renames.append(simple_line_formatter(current_line, old_line, line));
+ }
}
}
- return found_things;
+ return found_renames;
}
+
+// TODO, this function should run only on all ".gd" files and also on lines in ".tscn" files which are parts of built-in Scripts.
void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer &reg_container, bool builtin) {
- if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) {
- line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
- line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
- }
+ // In this and other functions, reg.sub() is used only after checking lines with str.contains().
+ // With longer lines, doing so can sometimes be significantly faster.
- // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure
- line = reg_container.reg_mixed_tab_space.sub(line, "$1", true);
+ if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) {
+ line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
+ line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, Image no longer requires locking, `false` helps to not break one line if/else, so it can freely be removed", true);
+ }
// PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
- line = reg_container.reg_join.sub(line, "$2.join($1)", true);
+ if (line.contains(".join")) {
+ line = reg_container.reg_join.sub(line, "$2.join($1)", true);
+ }
// -- empty() -> is_empty() Pool*Array
- line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
+ if (line.contains("empty")) {
+ line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
+ }
// -- \t.func() -> \tsuper.func() Object
- line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore"
+ if (line.contains("(") && line.contains(".")) {
+ line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this broke String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore"
+ }
// -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
- line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ if (line.contains("parse")) {
+ line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ }
// -- to_json(a) -> JSON.new().stringify(a) Object
- line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
-
+ if (line.contains("to_json")) {
+ line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
+ }
// -- parse_json(a) -> JSON.get_data() etc. Object
- line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ if (line.contains("parse_json")) {
+ line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ }
// -- get_node(@ -> get_node( Node
- line = line.replace("get_node(@", "get_node(");
+ if (line.contains("get_node")) {
+ line = line.replace("get_node(@", "get_node(");
+ }
// export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript
- line = reg_container.reg_export.sub(line, "export var $2: $1");
+ if (line.contains("export")) {
+ line = reg_container.reg_export.sub(line, "export var $2: $1");
+ }
// export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript
- line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ if (line.contains("export")) {
+ line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ }
// Setget Setget
- line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ }
// Setget set
- line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ }
// Setget get
- line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
+ }
// OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
- if (builtin) {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
- } else {
- line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
+ if (line.contains("window_fullscreen")) {
+ if (builtin) {
+ line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
+ } else {
+ line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
+ }
+ }
+
+ // Instantiate
+ if (line.contains("instance")) {
+ line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
}
// -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide(") != -1) {
+ if (line.contains(("move_and_slide("))) {
int start = line.find("move_and_slide(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
String base_obj = get_object_of_execution(line.substr(0, start));
String starting_space = get_starting_space(line);
@@ -2822,9 +3151,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide_with_snap(") != -1) {
+ if (line.contains("move_and_slide_with_snap(")) {
int start = line.find("move_and_slide_with_snap(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
String base_obj = get_object_of_execution(line.substr(0, start));
String starting_space = get_starting_space(line);
@@ -2873,9 +3202,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object
- if (line.find("sort_custom(") != -1) {
+ if (line.contains("sort_custom(")) {
int start = line.find("sort_custom(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
@@ -2885,18 +3214,18 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- list_dir_begin( ) -> list_dir_begin() Object
- if (line.find("list_dir_begin(") != -1) {
+ if (line.contains("list_dir_begin(")) {
int start = line.find("list_dir_begin(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547";
}
}
// -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem
- if (line.find("draw_line(") != -1) {
+ if (line.contains("draw_line(")) {
int start = line.find("draw_line(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 5) {
@@ -2906,10 +3235,10 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- func c(var a, var b) -> func c(a, b)
- if (line.find("func ") != -1 && line.find("var ") != -1) {
+ if (line.contains("func ") && line.contains("var ")) {
int start = line.find("func ");
start = line.substr(start).find("(") + start;
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
@@ -2925,9 +3254,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- yield(this, \"timeout\") -> await this.timeout GDScript
- if (line.find("yield(") != -1) {
+ if (line.contains("yield(")) {
int start = line.find("yield(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
@@ -2941,9 +3270,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- parse_json( AA ) -> TODO Object
- if (line.find("parse_json(") != -1) {
+ if (line.contains("parse_json(")) {
int start = line.find("parse_json(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start);
@@ -2951,9 +3280,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
- if (line.find(".xform(") != -1) {
+ if (line.contains(".xform(")) {
int start = line.find(".xform(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 1) {
@@ -2963,12 +3292,12 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
- if (line.find(".xform_inv(") != -1) {
+ if (line.contains(".xform_inv(")) {
int start = line.find(".xform_inv(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
String object_exec = get_object_of_execution(line.substr(0, start));
- if (line.find(object_exec + ".xform") != -1) {
+ if (line.contains(object_exec + ".xform")) {
int start2 = line.find(object_exec + ".xform");
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 1) {
@@ -2979,11 +3308,11 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- "(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) Object
- if (line.find("connect(") != -1) {
+ if (line.contains("connect(")) {
int start = line.find("connect(");
// Protection from disconnect
if (start == 0 || line.get(start - 1) != 's') {
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
@@ -2995,9 +3324,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object
- if (line.find("disconnect(") != -1) {
+ if (line.contains("disconnect(")) {
int start = line.find("disconnect(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
@@ -3006,9 +3335,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object
- if (line.find("is_connected(") != -1) {
+ if (line.contains("is_connected(")) {
int start = line.find("is_connected(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
@@ -3018,9 +3347,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- "(tween_method(A,B,C,D,E) != OK):", "(tween_method(Callable(A,B),C,D,E) Object
// -- "(tween_method(A,B,C,D,E,[F,G]) != OK):", "(tween_method(Callable(A,B).bind(F,G),C,D,E) Object
- if (line.find("tween_method(") != -1) {
+ if (line.contains("tween_method(")) {
int start = line.find("tween_method(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 5) {
@@ -3031,9 +3360,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- "(tween_callback(A,B,[C,D]) != OK):", "(connect(Callable(A,B).bind(C,D)) Object
- if (line.find("tween_callback(") != -1) {
+ if (line.contains("tween_callback(")) {
int start = line.find("tween_callback(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
@@ -3045,9 +3374,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
// -- start(a,b) -> start(Callable(a,b)) Thread
// -- start(a,b,c,d) -> start(Callable(a,b).bind(c),d) Thread
- if (line.find("start(") != -1) {
+ if (line.contains("start(")) {
int start = line.find("start(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
// Protection from 'func start'
if (!line.begins_with("func ")) {
if (end > -1) {
@@ -3061,18 +3390,20 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589
- if (line.find(" _init(") != -1) {
+ if (line.contains(" _init(")) {
int start = line.find(" _init(");
- int end = line.rfind(":") + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start);
+ if (line.contains(":")) {
+ int end = line.rfind(":") + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start);
+ }
}
}
// assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message
- if (line.find("assert(") != -1) {
+ if (line.contains("assert(")) {
int start = line.find("assert(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
@@ -3081,9 +3412,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture
- if (line.find("create_from_image(") != -1) {
+ if (line.contains("create_from_image(")) {
int start = line.find("create_from_image(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
@@ -3092,9 +3423,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e)
- if (line.find("set_cell_item(") != -1) {
+ if (line.contains("set_cell_item(")) {
int start = line.find("set_cell_item(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() > 2) {
@@ -3103,9 +3434,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c))
- if (line.find("get_cell_item(") != -1) {
+ if (line.contains("get_cell_item(")) {
int start = line.find("get_cell_item(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
@@ -3114,9 +3445,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c))
- if (line.find("get_cell_item_orientation(") != -1) {
+ if (line.contains("get_cell_item_orientation(")) {
int start = line.find("get_cell_item_orientation(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
@@ -3125,9 +3456,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// apply_impulse(A, B) -> apply_impulse(B, A)
- if (line.find("apply_impulse(") != -1) {
+ if (line.contains("apply_impulse(")) {
int start = line.find("apply_impulse(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
@@ -3136,9 +3467,9 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// apply_force(A, B) -> apply_force(B, A)
- if (line.find("apply_force(") != -1) {
+ if (line.contains("apply_force(")) {
int start = line.find("apply_force(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 2) {
@@ -3146,21 +3477,23 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
}
- // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c))
- if (line.find("map_to_world(") != -1) {
+ // map_to_world(a, b, c) -> map_to_local(Vector3i(a, b, c))
+ if (line.contains("map_to_world(")) {
int start = line.find("map_to_world(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
- line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ line = line.substr(0, start) + "map_to_local(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ } else if (parts.size() == 1) {
+ line = line.substr(0, start) + "map_to_local(" + parts[0] + ")" + line.substr(end + start);
}
}
}
// OS.get_window_safe_area() -> DisplayServer.get_display_safe_area()
- if (line.find("OS.get_window_safe_area(") != -1) {
+ if (line.contains("OS.get_window_safe_area(")) {
int start = line.find("OS.get_window_safe_area(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 0) {
@@ -3168,18 +3501,63 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
}
+ // draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOGODOT4 Antialiasing argument is missing
+ if (line.contains("draw_rect(")) {
+ int start = line.find("draw_rect(");
+ int end = get_end_parenthesis(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 5) {
+ line = line.substr(0, start) + "draw_rect(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing";
+ }
+ }
+ }
+ // get_focus_owner() -> get_viewport().gui_get_focus_owner()
+ if (line.contains("get_focus_owner()")) {
+ line = line.replace("get_focus_owner()", "get_viewport().gui_get_focus_owner()");
+ }
+
+ // button.pressed = 1 -> button.button_pressed = 1
+ if (line.contains(".pressed")) {
+ int start = line.find(".pressed");
+ bool foundNextEqual = false;
+ String line_to_check = line.substr(start + String(".pressed").length());
+ for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
+ char32_t chr = line_to_check.get(current_index);
+ if (chr == '\t' || chr == ' ') {
+ continue;
+ } else if (chr == '=') {
+ foundNextEqual = true;
+ } else {
+ break;
+ }
+ }
+ if (foundNextEqual) {
+ line = line.substr(0, start) + ".button_pressed" + line.substr(start + String(".pressed").length());
+ }
+ }
+
+ // OS -> Time functions
+ if (line.contains("OS.get_ticks_msec")) {
+ line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec");
+ }
+ if (line.contains("OS.get_ticks_usec")) {
+ line = line.replace("OS.get_ticks_usec", "Time.get_ticks_usec");
+ }
+ if (line.contains("OS.get_unix_time")) {
+ line = line.replace("OS.get_unix_time", "Time.get_unix_time_from_system");
+ }
}
-void ProjectConverter3To4::process_csharp_line(String &line) {
- // TODO maybe this can be changed to normal rule
+void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer &reg_container) {
line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
// -- Connect(,,,things) -> Connect(,Callable(,),things) Object
- if (line.find("Connect(") != -1) {
+ if (line.contains("Connect(")) {
int start = line.find("Connect(");
// Protection from disconnect
if (start == 0 || line.get(start - 1) != 's') {
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() >= 3) {
@@ -3189,9 +3567,9 @@ void ProjectConverter3To4::process_csharp_line(String &line) {
}
}
// -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object
- if (line.find("Disconnect(") != -1) {
+ if (line.contains("Disconnect(")) {
int start = line.find("Disconnect(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
@@ -3200,9 +3578,9 @@ void ProjectConverter3To4::process_csharp_line(String &line) {
}
}
// -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object
- if (line.find("IsConnected(") != -1) {
+ if (line.contains("IsConnected(")) {
int start = line.find("IsConnected(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 3) {
@@ -3212,415 +3590,317 @@ void ProjectConverter3To4::process_csharp_line(String &line) {
}
}
-void ProjectConverter3To4::rename_csharp_functions(String &file_content) {
- Vector<String> lines = file_content.split("\n");
-
+void ProjectConverter3To4::rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
for (String &line : lines) {
- process_csharp_line(line);
- }
-
- // Collect vector to string
- file_content = "";
- for (int i = 0; i < lines.size(); i++) {
- file_content += lines[i];
-
- if (i != lines.size() - 1) {
- file_content += "\n";
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ process_csharp_line(line, reg_container);
}
}
};
-// This is almost 1:1 copy of function which rename gdscript functions
-Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &file_content) {
+Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
int current_line = 1;
- Vector<String> found_things;
+ Vector<String> found_renames;
- for (String &line : file_content) {
- String old_line = line;
- process_csharp_line(line);
- if (old_line != line) {
- found_things.append(simple_line_formatter(current_line, old_line, line));
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old_line = line;
+ process_csharp_line(line, reg_container);
+ if (old_line != line) {
+ found_renames.append(simple_line_formatter(current_line, old_line, line));
+ }
}
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_csharp_attributes(String &file_content) {
- // -- [Remote] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer)]
- {
- RegEx reg_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remote.is_valid());
- file_content = reg_remote.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
- }
- // -- [RemoteSync] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]
- {
- RegEx reg_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remotesync.is_valid());
- file_content = reg_remotesync.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
- }
- // -- [Puppet] -> [RPC]
- {
- RegEx reg_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_puppet.is_valid());
- file_content = reg_puppet.sub(file_content, "[RPC]", true);
- }
- // -- [PuppetSync] -> [RPC(CallLocal = true)]
- {
- RegEx reg_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_puppetsync.is_valid());
- file_content = reg_puppetsync.sub(file_content, "[RPC(CallLocal = true)]", true);
- }
- String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n";
- // -- [Master] -> [RPC]
- {
- RegEx reg_remote = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remote.is_valid());
- file_content = reg_remote.sub(file_content, error_message + "[RPC]", true);
- }
- // -- [MasterSync] -> [RPC(CallLocal = true)]
- {
- RegEx reg_remote = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!reg_remote.is_valid());
- file_content = reg_remote.sub(file_content, error_message + "[RPC(CallLocal = true)]", true);
+void ProjectConverter3To4::rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container) {
+ static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n";
+
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
+ line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
+ line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
+ line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
+ line = reg_container.keyword_csharp_master.sub(line, error_message + "[RPC]", true);
+ line = reg_container.keyword_csharp_mastersync.sub(line, error_message + "[RPC(CallLocal = true)]", true);
+ }
}
}
-Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &file_content) {
+Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container) {
int current_line = 1;
- Vector<String> found_things;
+ Vector<String> found_renames;
- for (String &line : file_content) {
- String old;
- old = line;
- {
- RegEx regex = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[Puppet(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[Puppet]", "[RPC]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[(Puppet|Slave)Sync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(CallLocal = true)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[Master]", "[RPC]", line));
- }
- old = line;
- {
- RegEx regex = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "[RPC(CallLocal = true)]", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line));
- }
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old;
+ old = line;
+ line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line));
+ }
+ old = line;
+ line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line));
+ }
+
+ old = line;
+ line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[Puppet]", "[RPC]", line));
+ }
+
+ old = line;
+ line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line));
+ }
+
+ old = line;
+ line = reg_container.keyword_csharp_master.sub(line, "[RPC]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[Master]", "[RPC]", line));
+ }
+
+ old = line;
+ line = reg_container.keyword_csharp_mastersync.sub(line, "[RPC(CallLocal = true)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line));
+ }
+ }
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_gdscript_keywords(String &file_content) {
- {
- RegEx reg_first = RegEx("([\n]+)tool");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@tool", true);
- RegEx reg_second = RegEx("^tool");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@tool", true);
- }
- {
- RegEx reg_first = RegEx("([\n\t]+)export\\b");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@export", true);
- RegEx reg_second = RegEx("^export");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@export", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)onready");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@onready", true);
- RegEx reg_second = RegEx("^onready");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@onready", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)remote func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(any_peer) func", true);
- RegEx reg_second = RegEx("^remote func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(any_peer) func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)remotesync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true);
- RegEx reg_second = RegEx("^remotesync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)sync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true);
- RegEx reg_second = RegEx("^sync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)slave func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc func", true);
- RegEx reg_second = RegEx("^slave func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)puppet func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc func", true);
- RegEx reg_second = RegEx("^puppet func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)puppetsync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1@rpc(call_local) func", true);
- RegEx reg_second = RegEx("^puppetsync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, "@rpc(call_local) func", true);
- }
- String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n";
- {
- RegEx reg_first = RegEx("([\n]+)master func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc func", true);
- RegEx reg_second = RegEx("^master func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, error_message + "@rpc func", true);
- }
- {
- RegEx reg_first = RegEx("([\n]+)mastersync func");
- CRASH_COND(!reg_first.is_valid());
- file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc(call_local) func", true);
- RegEx reg_second = RegEx("^mastersync func");
- CRASH_COND(!reg_second.is_valid());
- file_content = reg_second.sub(file_content, error_message + "@rpc(call_local) func", true);
+void ProjectConverter3To4::rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container) {
+ static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n";
+
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ if (line.contains("tool")) {
+ line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true);
+ }
+ if (line.contains("export")) {
+ line = reg_container.keyword_gdscript_export_single.sub(line, "@export", true);
+ }
+ if (line.contains("export")) {
+ line = reg_container.keyword_gdscript_export_mutli.sub(line, "$1@export", true);
+ }
+ if (line.contains("onready")) {
+ line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true);
+ }
+ if (line.contains("remote")) {
+ line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true);
+ }
+ if (line.contains("remote")) {
+ line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local) func", true);
+ }
+ if (line.contains("sync")) {
+ line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local) func", true);
+ }
+ if (line.contains("slave")) {
+ line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
+ }
+ if (line.contains("puppet")) {
+ line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
+ }
+ if (line.contains("puppet")) {
+ line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true);
+ }
+ if (line.contains("master")) {
+ line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true);
+ }
+ if (line.contains("master")) {
+ line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(call_local) func", true);
+ }
+ }
}
}
-Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &file_content) {
- Vector<String> found_things;
+Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
int current_line = 1;
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old;
+
+ if (line.contains("tool")) {
+ old = line;
+ line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "tool", "@tool", line));
+ }
+ }
- for (String &line : file_content) {
- String old;
- old = line;
- {
- RegEx reg_first = RegEx("^tool");
- CRASH_COND(!reg_first.is_valid());
- line = reg_first.sub(line, "@tool", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "tool", "@tool", line));
- }
- old = line;
- {
- RegEx reg_first = RegEx("([\t]+)export\\b");
- CRASH_COND(!reg_first.is_valid());
- line = reg_first.sub(line, "$1@export", true);
- RegEx reg_second = RegEx("^export");
- CRASH_COND(!reg_second.is_valid());
- line = reg_second.sub(line, "@export", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "export", "@export", line));
- }
- old = line;
- {
- RegEx reg_first = RegEx("^onready");
- CRASH_COND(!reg_first.is_valid());
- line = reg_first.sub(line, "@onready", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "onready", "@onready", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^remote func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(any_peer) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^remotesync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(any_peer, call_local)) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^sync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(any_peer, call_local)) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^slave func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "slave func", "@rpc func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^puppet func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "puppet func", "@rpc func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^puppetsync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(call_local) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^master func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "master func", "@rpc func", line));
- }
- old = line;
- {
- RegEx regex = RegEx("^mastersync func");
- CRASH_COND(!regex.is_valid());
- line = regex.sub(line, "@rpc(call_local) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line));
- }
- old = line;
+ if (line.contains("export")) {
+ old = line;
+ line = reg_container.keyword_gdscript_export_single.sub(line, "$1@export", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "export", "@export", line));
+ }
+ }
+
+ if (line.contains("export")) {
+ old = line;
+ line = reg_container.keyword_gdscript_export_mutli.sub(line, "@export", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "export", "@export", line));
+ }
+ }
+
+ if (line.contains("onready")) {
+ old = line;
+ line = reg_container.keyword_gdscript_tool.sub(line, "@onready", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "onready", "@onready", line));
+ }
+ }
+
+ if (line.contains("remote")) {
+ old = line;
+ line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line));
+ }
+ }
+ if (line.contains("remote")) {
+ old = line;
+ line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local)) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line));
+ }
+ }
+
+ if (line.contains("sync")) {
+ old = line;
+ line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local)) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line));
+ }
+ }
+
+ if (line.contains("slave")) {
+ old = line;
+ line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "slave func", "@rpc func", line));
+ }
+ }
+
+ if (line.contains("puppet")) {
+ old = line;
+ line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "puppet func", "@rpc func", line));
+ }
+ }
+
+ if (line.contains("puppet")) {
+ old = line;
+ line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line));
+ }
+ }
+
+ if (line.contains("master")) {
+ old = line;
+ line = reg_container.keyword_gdscript_master.sub(line, "@rpc func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "master func", "@rpc func", line));
+ }
+ }
+
+ if (line.contains("master")) {
+ old = line;
+ line = reg_container.keyword_gdscript_master.sub(line, "@rpc(call_local) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line));
+ }
+ }
+ }
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::custom_rename(String &file_content, String from, String to) {
+void ProjectConverter3To4::custom_rename(Vector<String> &lines, String from, String to) {
RegEx reg = RegEx(String("\\b") + from + "\\b");
CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, to, true);
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ line = reg.sub(line, to, true);
+ }
+ }
};
-Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &file_content, String from, String to) {
- Vector<String> found_things;
+Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, String from, String to) {
+ Vector<String> found_renames;
RegEx reg = RegEx(String("\\b") + from + "\\b");
CRASH_COND(!reg.is_valid());
int current_line = 1;
- for (String &line : file_content) {
- TypedArray<RegExMatch> reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader"
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ TypedArray<RegExMatch> reg_match = reg.search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader".
+ }
}
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_common(const char *array[][2], String &file_content) {
- int current_index = 0;
- while (array[current_index][0]) {
- RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, array[current_index][1], true);
- current_index++;
+void ProjectConverter3To4::rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
+ if (line.contains(array[current_index][0])) {
+ line = cached_regexes[current_index]->sub(line, array[current_index][1], true);
+ }
+ }
+ }
}
}
-// Common renaming,
-Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], Vector<String> &file_content) {
- int current_index = 0;
+Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) {
+ Vector<String> found_renames;
- Vector<String> found_things;
-
- while (array[current_index][0]) {
- RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
+ int current_line = 1;
- int current_line = 1;
- for (String &line : file_content) {
- TypedArray<RegExMatch> reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line));
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
+ if (line.contains(array[current_index][0])) {
+ TypedArray<RegExMatch> reg_match = cached_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line));
+ }
+ }
}
- current_line++;
}
- current_index++;
+ current_line++;
}
- return found_things;
+
+ return found_renames;
}
-// Formats data to print them into user console when trying to convert data
+// Prints full info about renamed things e.g.:
+// Line (67) remove -> remove_at - LINE """ doubler._blacklist.remove(0) """
String ProjectConverter3To4::line_formatter(int current_line, String from, String to, String line) {
if (from.size() > 200) {
from = from.substr(0, 197) + "...";
@@ -3631,27 +3911,51 @@ String ProjectConverter3To4::line_formatter(int current_line, String from, Strin
if (line.size() > 400) {
line = line.substr(0, 397) + "...";
}
- return String("Line (") + itos(current_line) + ") " + from.replace("\r", "").replace("\n", "") + " -> " + to.replace("\r", "").replace("\n", "") + " - LINE \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\"";
+
+ from = from.strip_escapes();
+ to = to.strip_escapes();
+ line = line.replace("\r", "").replace("\n", "").strip_edges();
+
+ return vformat("Line(%d), %s -> %s - LINE \"\"\" %s \"\"\"", current_line, from, to, line);
}
-String ProjectConverter3To4::simple_line_formatter(int current_line, String old_line, String line) {
+// Prints only full lines e.g.:
+// Line (1) - FULL LINES - """yield(get_tree().create_timer(3), 'timeout')""" =====> """ await get_tree().create_timer(3).timeout """
+String ProjectConverter3To4::simple_line_formatter(int current_line, String old_line, String new_line) {
if (old_line.size() > 1000) {
old_line = old_line.substr(0, 997) + "...";
}
- if (line.size() > 1000) {
- line = line.substr(0, 997) + "...";
+ if (new_line.size() > 1000) {
+ new_line = new_line.substr(0, 997) + "...";
+ }
+
+ old_line = old_line.replace("\r", "").replace("\n", "").strip_edges();
+ new_line = new_line.replace("\r", "").replace("\n", "").strip_edges();
+
+ return vformat("Line (%d) - FULL LINES - \"\"\" %s \"\"\" =====> \"\"\" %s \"\"\"", current_line, old_line, new_line);
+}
+
+// Collects string from vector strings
+String ProjectConverter3To4::collect_string_from_vector(Vector<String> &vector) {
+ String string = "";
+ for (int i = 0; i < vector.size(); i++) {
+ string += vector[i];
+
+ if (i != vector.size() - 1) {
+ string += "\n";
+ }
}
- return String("Line (") + itos(current_line) + ") - FULL LINES - \"\"\"" + old_line.replace("\r", "").replace("\n", "").strip_edges() + "\"\"\" =====> \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\"";
+ return string;
}
-#else // No regex.
+#else // No RegEx.
int ProjectConverter3To4::convert() {
- ERR_FAIL_V_MSG(ERROR_CODE, "Can't run converter for Godot 3.x projects as RegEx module is disabled.");
+ ERR_FAIL_V_MSG(ERROR_CODE, "Can't run converter for Godot 3.x projects, because RegEx module is disabled.");
}
int ProjectConverter3To4::validate_conversion() {
- ERR_FAIL_V_MSG(ERROR_CODE, "Can't validate conversion for Godot 3.x projects as RegEx module is disabled.");
+ ERR_FAIL_V_MSG(ERROR_CODE, "Can't validate conversion for Godot 3.x projects, because RegEx module is disabled.");
}
#endif // MODULE_REGEX_ENABLED
diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h
index 8526e2ceb9..2cecb9da79 100644
--- a/editor/project_converter_3_to_4.h
+++ b/editor/project_converter_3_to_4.h
@@ -35,57 +35,65 @@
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
+#include "core/templates/local_vector.h"
+
+class RegEx;
class ProjectConverter3To4 {
public:
class RegExContainer;
private:
- void rename_enums(String &file_content);
- Vector<String> check_for_rename_enums(Vector<String> &file_content);
+ uint64_t maximum_file_size;
+ uint64_t maximum_line_length;
+
+ void rename_colors(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container);
- void rename_classes(String &file_content);
- Vector<String> check_for_rename_classes(Vector<String> &file_content);
+ void rename_classes(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container);
- void rename_gdscript_functions(String &file_content, const RegExContainer &reg_container, bool builtin);
- Vector<String> check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer &reg_container, bool builtin);
+ void rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin);
+ Vector<String> check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin);
void process_gdscript_line(String &line, const RegExContainer &reg_container, bool builtin);
- void rename_csharp_functions(String &file_content);
- Vector<String> check_for_rename_csharp_functions(Vector<String> &file_content);
- void process_csharp_line(String &line);
+ void rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container);
+ void process_csharp_line(String &line, const RegExContainer &reg_container);
- void rename_csharp_attributes(String &file_content);
- Vector<String> check_for_rename_csharp_attributes(Vector<String> &file_content);
+ void rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container);
- void rename_gdscript_keywords(String &file_content);
- Vector<String> check_for_rename_gdscript_keywords(Vector<String> &file_content);
+ void rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container);
- void custom_rename(String &file_content, String from, String to);
- Vector<String> check_for_custom_rename(Vector<String> &file_content, String from, String to);
+ void custom_rename(Vector<String> &lines, String from, String to);
+ Vector<String> check_for_custom_rename(Vector<String> &lines, String from, String to);
- void rename_common(const char *array[][2], String &file_content);
- Vector<String> check_for_rename_common(const char *array[][2], Vector<String> &file_content);
+ void rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines);
+ Vector<String> check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines);
Vector<String> check_for_files();
Vector<String> parse_arguments(const String &line);
- int get_end_parenthess(const String &line) const;
+ int get_end_parenthesis(const String &line) const;
String connect_arguments(const Vector<String> &line, int from, int to = -1) const;
String get_starting_space(const String &line) const;
String get_object_of_execution(const String &line) const;
String line_formatter(int current_line, String from, String to, String line);
String simple_line_formatter(int current_line, String old_line, String line);
+ String collect_string_from_vector(Vector<String> &vector);
bool test_single_array(const char *array[][2], bool ignore_second_check = false);
- bool test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what);
- bool test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin);
- bool test_conversion_single_normal(String name, String expected, const char *array[][2], String what);
+ bool test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin);
+ bool test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer &reg_container);
+ bool test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> &regex_cache, String what);
bool test_array_names();
- bool test_conversion(const RegExContainer &reg_container);
+ bool test_conversion(RegExContainer &reg_container);
public:
+ ProjectConverter3To4(int, int);
int validate_conversion();
int convert();
};
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 21891e381b..544e8c9323 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -35,7 +35,7 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
-#include "core/io/stream_peer_ssl.h"
+#include "core/io/stream_peer_tls.h"
#include "core/io/zip_io.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -47,6 +47,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_themes.h"
#include "editor/editor_vcs_interface.h"
+#include "main/main.h"
#include "scene/gui/center_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/margin_container.h"
@@ -437,7 +438,7 @@ private:
ProjectSettings::CustomMap edited_settings;
edited_settings["application/config/name"] = project_name->get_text().strip_edges();
- if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) {
+ if (current->save_custom(dir2.path_join("project.godot"), edited_settings, Vector<String>(), true) != OK) {
set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
}
}
@@ -483,12 +484,20 @@ private:
project_features.sort();
initial_settings["application/config/features"] = project_features;
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
- initial_settings["application/config/icon"] = "res://icon.png";
+ initial_settings["application/config/icon"] = "res://icon.svg";
- if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) {
+ if (ProjectSettings::get_singleton()->save_custom(dir.path_join("project.godot"), initial_settings, Vector<String>(), false) != OK) {
set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
} else {
- ResourceSaver::save(create_unscaled_default_project_icon(), dir.plus_file("icon.png"));
+ // Store default project icon in SVG format.
+ Error err;
+ Ref<FileAccess> fa_icon = FileAccess::open(dir.path_join("icon.svg"), FileAccess::WRITE, &err);
+ fa_icon->store_string(get_default_project_icon());
+
+ if (err != OK) {
+ set_message(TTR("Couldn't create icon.svg in project path."), MESSAGE_ERROR);
+ }
+
EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(vcs_metadata_selection->get_selected()), dir);
}
} else if (mode == MODE_INSTALL) {
@@ -547,7 +556,7 @@ private:
String rel_path = path.substr(zip_root.length());
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- da->make_dir(dir.plus_file(rel_path));
+ da->make_dir(dir.path_join(rel_path));
} else {
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
@@ -559,7 +568,7 @@ private:
ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", rel_path));
unzCloseCurrentFile(pkg);
- Ref<FileAccess> f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(dir.path_join(rel_path), FileAccess::WRITE);
if (f.is_valid()) {
f->store_buffer(data.ptr(), data.size());
} else {
@@ -953,12 +962,12 @@ public:
switch (p_what) {
case NOTIFICATION_MOUSE_ENTER: {
hover = true;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_MOUSE_EXIT: {
hover = false;
- update();
+ queue_redraw();
} break;
case NOTIFICATION_DRAW: {
@@ -1117,7 +1126,7 @@ ProjectList::ProjectList() {
_icon_load_index = 0;
project_opening_initiated = false;
- _config_path = EditorPaths::get_singleton()->get_data_dir().plus_file("projects.cfg");
+ _config_path = EditorPaths::get_singleton()->get_data_dir().path_join("projects.cfg");
}
ProjectList::~ProjectList() {
@@ -1164,13 +1173,19 @@ void ProjectList::load_project_icon(int p_index) {
icon = default_icon;
}
+ // The default project icon is 128×128 to look crisp on hiDPI displays,
+ // but we want the actual displayed size to be 64×64 on loDPI displays.
+ item.control->icon->set_ignore_texture_size(true);
+ item.control->icon->set_custom_minimum_size(Size2(64, 64) * EDSCALE);
+ item.control->icon->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+
item.control->icon->set_texture(icon);
item.control->icon_needs_reload = false;
}
// Load project data from p_property_key and return it in a ProjectList::Item. p_favorite is passed directly into the Item.
ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_favorite) {
- String conf = p_path.plus_file("project.godot");
+ String conf = p_path.path_join("project.godot");
bool grayed = false;
bool missing = false;
@@ -1206,7 +1221,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
// when editing a project (but not when running it).
last_edited = FileAccess::get_modified_time(conf);
- String fscache = p_path.plus_file(".fscache");
+ String fscache = p_path.path_join(".fscache");
if (FileAccess::exists(fscache)) {
uint64_t cache_modified = FileAccess::get_modified_time(fscache);
if (cache_modified > last_edited) {
@@ -1306,7 +1321,7 @@ void ProjectList::update_dock_menu() {
}
favs_added = 0;
}
- DisplayServer::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", callable_mp(this, &ProjectList::_global_menu_open_project), i);
+ DisplayServer::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", callable_mp(this, &ProjectList::_global_menu_open_project), Callable(), i);
total_added++;
}
}
@@ -1326,7 +1341,7 @@ void ProjectList::_global_menu_open_project(const Variant &p_tag) {
int idx = (int)p_tag;
if (idx >= 0 && idx < _projects.size()) {
- String conf = _projects[idx].path.plus_file("project.godot");
+ String conf = _projects[idx].path.path_join("project.godot");
List<String> args;
args.push_back(conf);
OS::get_singleton()->create_instance(args);
@@ -1347,7 +1362,7 @@ void ProjectList::create_project_item_control(int p_index) {
hb->connect("draw", callable_mp(this, &ProjectList::_panel_draw).bind(hb));
hb->connect("gui_input", callable_mp(this, &ProjectList::_panel_input).bind(hb));
hb->add_theme_constant_override("separation", 10 * EDSCALE);
- hb->set_tooltip(item.description);
+ hb->set_tooltip_text(item.description);
VBoxContainer *favorite_box = memnew(VBoxContainer);
favorite_box->set_name("FavoriteBox");
@@ -1430,9 +1445,9 @@ void ProjectList::create_project_item_control(int p_index) {
if (!item.missing) {
show->connect("pressed", callable_mp(this, &ProjectList::_show_project).bind(item.path));
- show->set_tooltip(TTR("Show in File Manager"));
+ show->set_tooltip_text(TTR("Show in File Manager"));
} else {
- show->set_tooltip(TTR("Error: Project is missing on the filesystem."));
+ show->set_tooltip_text(TTR("Error: Project is missing on the filesystem."));
}
Label *fpath = memnew(Label(item.path));
@@ -1667,7 +1682,7 @@ void ProjectList::select_project(int p_index) {
_selected_project_paths.clear();
for (int i = 0; i < previous_selected_items.size(); ++i) {
- previous_selected_items[i].control->update();
+ previous_selected_items[i].control->queue_redraw();
}
toggle_select(p_index);
@@ -1713,7 +1728,7 @@ void ProjectList::toggle_select(int p_index) {
} else {
_selected_project_paths.insert(item.path);
}
- item.control->update();
+ item.control->queue_redraw();
}
void ProjectList::erase_selected_projects(bool p_delete_project_contents) {
@@ -1845,7 +1860,7 @@ void ProjectManager::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -1886,11 +1901,13 @@ void ProjectManager::_notification(int p_what) {
filter_option->select(default_sorting);
_project_list->set_order_option(default_sorting);
+#ifndef ANDROID_ENABLED
if (_project_list->get_project_count() >= 1) {
// Focus on the search box immediately to allow the user
// to search without having to reach for their mouse
search_box->grab_focus();
}
+#endif
if (asset_library) {
// Removes extra border margins.
@@ -1976,7 +1993,7 @@ void ProjectManager::shortcut_input(const Ref<InputEvent> &p_ev) {
// This is handled by the platform implementation on macOS,
// so only define the shortcut on other platforms
#ifndef MACOS_ENABLED
- if (k->get_keycode_with_modifiers() == (KeyModifierMask::CMD | Key::Q)) {
+ if (k->get_keycode_with_modifiers() == (KeyModifierMask::META | Key::Q)) {
_dim_window();
get_tree()->quit();
}
@@ -2034,7 +2051,7 @@ void ProjectManager::shortcut_input(const Ref<InputEvent> &p_ev) {
} break;
case Key::F: {
- if (k->is_command_pressed()) {
+ if (k->is_command_or_control_pressed()) {
this->search_box->grab_focus();
} else {
keycode_handled = false;
@@ -2091,13 +2108,13 @@ void ProjectManager::_confirm_update_settings() {
void ProjectManager::_open_selected_projects() {
// Show loading text to tell the user that the project manager is busy loading.
- // This is especially important for the HTML5 project manager.
+ // This is especially important for the Web project manager.
loading_label->show();
const HashSet<String> &selected_list = _project_list->get_selected_project_keys();
for (const String &path : selected_list) {
- String conf = path.plus_file("project.godot");
+ String conf = path.path_join("project.godot");
if (!FileAccess::exists(conf)) {
dialog_error->set_text(vformat(TTR("Can't open project at '%s'."), path));
@@ -2109,27 +2126,15 @@ void ProjectManager::_open_selected_projects() {
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
+ args.push_back(a);
+ }
+
args.push_back("--path");
args.push_back(path);
args.push_back("--editor");
- if (OS::get_singleton()->is_stdout_debug_enabled()) {
- args.push_back("--debug");
- }
-
- if (OS::get_singleton()->is_stdout_verbose()) {
- args.push_back("--verbose");
- }
-
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
- if (OS::get_singleton()->is_single_window()) {
- args.push_back("--single-window");
- }
-
Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
}
@@ -2159,7 +2164,7 @@ void ProjectManager::_open_selected_projects_ask() {
}
// Update the project settings or don't open
- const String conf = project.path.plus_file("project.godot");
+ const String conf = project.path.path_join("project.godot");
const int config_version = project.version;
PackedStringArray unsupported_features = project.unsupported_features;
@@ -2232,7 +2237,7 @@ void ProjectManager::_run_project_confirm() {
const String &path = selected_list[i].path;
// `.substr(6)` on `ProjectSettings::get_singleton()->get_imported_files_path()` strips away the leading "res://".
- if (!DirAccess::exists(path.plus_file(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
+ if (!DirAccess::exists(path.path_join(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import."));
run_error_diag->popup_centered();
continue;
@@ -2242,13 +2247,13 @@ void ProjectManager::_run_project_confirm() {
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_PROJECT)) {
+ args.push_back(a);
+ }
+
args.push_back("--path");
args.push_back(path);
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
}
@@ -2277,7 +2282,7 @@ void ProjectManager::_scan_dir(const String &path) {
String n = da->get_next();
while (!n.is_empty()) {
if (da->current_is_dir() && !n.begins_with(".")) {
- _scan_dir(da->get_current_dir().plus_file(n));
+ _scan_dir(da->get_current_dir().path_join(n));
} else if (n == "project.godot") {
_project_list->add_project(da->get_current_dir(), false);
}
@@ -2440,6 +2445,7 @@ void ProjectManager::_on_order_option_changed(int p_idx) {
}
void ProjectManager::_on_tab_changed(int p_tab) {
+#ifndef ANDROID_ENABLED
if (p_tab == 0) { // Projects
// Automatically grab focus when the user moves from the Templates tab
// back to the Projects tab.
@@ -2448,6 +2454,7 @@ void ProjectManager::_on_tab_changed(int p_tab) {
// The Templates tab's search field is focused on display in the asset
// library editor plugin code.
+#endif
}
void ProjectManager::_on_search_term_changed(const String &p_term) {
@@ -2567,7 +2574,7 @@ ProjectManager::ProjectManager() {
search_box = memnew(LineEdit);
search_box->set_placeholder(TTR("Filter Projects"));
- search_box->set_tooltip(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
+ search_box->set_tooltip_text(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
search_box->connect("text_changed", callable_mp(this, &ProjectManager::_on_search_term_changed));
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(search_box);
@@ -2599,7 +2606,7 @@ ProjectManager::ProjectManager() {
}
PanelContainer *pc = memnew(PanelContainer);
- pc->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ pc->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
pc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
search_tree_vb->add_child(pc);
@@ -2621,21 +2628,21 @@ ProjectManager::ProjectManager() {
create_btn = memnew(Button);
create_btn->set_text(TTR("New Project"));
create_btn->add_theme_constant_override("h_separation", btn_h_separation);
- create_btn->set_shortcut(ED_SHORTCUT("project_manager/new_project", TTR("New Project"), KeyModifierMask::CMD | Key::N));
+ create_btn->set_shortcut(ED_SHORTCUT("project_manager/new_project", TTR("New Project"), KeyModifierMask::CMD_OR_CTRL | Key::N));
create_btn->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
tree_vb->add_child(create_btn);
import_btn = memnew(Button);
import_btn->set_text(TTR("Import"));
import_btn->add_theme_constant_override("h_separation", btn_h_separation);
- import_btn->set_shortcut(ED_SHORTCUT("project_manager/import_project", TTR("Import Project"), KeyModifierMask::CMD | Key::I));
+ import_btn->set_shortcut(ED_SHORTCUT("project_manager/import_project", TTR("Import Project"), KeyModifierMask::CMD_OR_CTRL | Key::I));
import_btn->connect("pressed", callable_mp(this, &ProjectManager::_import_project));
tree_vb->add_child(import_btn);
scan_btn = memnew(Button);
scan_btn->set_text(TTR("Scan"));
scan_btn->add_theme_constant_override("h_separation", btn_h_separation);
- scan_btn->set_shortcut(ED_SHORTCUT("project_manager/scan_projects", TTR("Scan Projects"), KeyModifierMask::CMD | Key::S));
+ scan_btn->set_shortcut(ED_SHORTCUT("project_manager/scan_projects", TTR("Scan Projects"), KeyModifierMask::CMD_OR_CTRL | Key::S));
scan_btn->connect("pressed", callable_mp(this, &ProjectManager::_scan_projects));
tree_vb->add_child(scan_btn);
@@ -2644,14 +2651,14 @@ ProjectManager::ProjectManager() {
open_btn = memnew(Button);
open_btn->set_text(TTR("Edit"));
open_btn->add_theme_constant_override("h_separation", btn_h_separation);
- open_btn->set_shortcut(ED_SHORTCUT("project_manager/edit_project", TTR("Edit Project"), KeyModifierMask::CMD | Key::E));
+ open_btn->set_shortcut(ED_SHORTCUT("project_manager/edit_project", TTR("Edit Project"), KeyModifierMask::CMD_OR_CTRL | Key::E));
open_btn->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask));
tree_vb->add_child(open_btn);
run_btn = memnew(Button);
run_btn->set_text(TTR("Run"));
run_btn->add_theme_constant_override("h_separation", btn_h_separation);
- run_btn->set_shortcut(ED_SHORTCUT("project_manager/run_project", TTR("Run Project"), KeyModifierMask::CMD | Key::R));
+ run_btn->set_shortcut(ED_SHORTCUT("project_manager/run_project", TTR("Run Project"), KeyModifierMask::CMD_OR_CTRL | Key::R));
run_btn->connect("pressed", callable_mp(this, &ProjectManager::_run_project));
tree_vb->add_child(run_btn);
@@ -2707,7 +2714,7 @@ ProjectManager::ProjectManager() {
// Fade the version label to be less prominent, but still readable.
version_btn->set_self_modulate(Color(1, 1, 1, 0.6));
version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
- version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->set_tooltip_text(TTR("Click to copy."));
version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed));
spacer_vb->add_child(version_btn);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index ca5eeaa787..2da49f11cc 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "servers/movie_writer/movie_writer.h"
ProjectSettingsEditor *ProjectSettingsEditor::singleton = nullptr;
@@ -238,7 +239,7 @@ void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) {
handled = true;
}
- if (k->get_keycode_with_modifiers() == (KeyModifierMask::CMD | Key::F)) {
+ if (k->is_match(InputEventKey::create_reference(KeyModifierMask::CMD_OR_CTRL | Key::F))) {
search_box->grab_focus();
search_box->select_all();
handled = true;
@@ -520,7 +521,7 @@ void ProjectSettingsEditor::_update_action_map_editor() {
void ProjectSettingsEditor::_update_theme() {
search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
restart_close_button->set_icon(get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
- restart_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ restart_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
restart_icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
restart_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
@@ -566,7 +567,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
set_title(TTR("Project Settings (project.godot)"));
ps = ProjectSettings::get_singleton();
- undo_redo = &p_data->get_undo_redo();
+ undo_redo = p_data->get_undo_redo();
data = p_data;
tab_container = memnew(TabContainer);
@@ -625,7 +626,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
custom_properties->add_child(del_button);
general_settings_inspector = memnew(SectionedInspector);
- general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo());
+ general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_undo_redo());
general_settings_inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL);
general_settings_inspector->register_search_box(search_box);
general_settings_inspector->get_inspector()->set_use_filter(true);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index c2d2c2d8f4..040d992e40 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -32,7 +32,6 @@
#define PROJECT_SETTINGS_EDITOR_H
#include "core/config/project_settings.h"
-#include "core/object/undo_redo.h"
#include "editor/action_map_editor.h"
#include "editor/editor_autoload_settings.h"
#include "editor/editor_data.h"
@@ -43,6 +42,7 @@
#include "editor/shader_globals_editor.h"
#include "scene/gui/tab_container.h"
+class EditorUndoRedoManager;
class FileSystemDock;
class ProjectSettingsEditor : public AcceptDialog {
@@ -77,7 +77,7 @@ class ProjectSettingsEditor : public AcceptDialog {
ImportDefaultsEditor *import_defaults_editor = nullptr;
EditorData *data = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _advanced_toggled(bool p_button_pressed);
void _update_advanced(bool p_is_advanced);
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 665aca6a37..300a3d0f05 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_themes.h"
+#include "editor/editor_undo_redo_manager.h"
#include "modules/regex/regex.h"
#include "plugins/script_editor_plugin.h"
#include "scene/gui/control.h"
@@ -45,7 +46,7 @@
#include "scene/gui/separator.h"
#include "scene/gui/tab_container.h"
-RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo) {
+RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo) {
scene_tree_editor = p_scene_tree_editor;
undo_redo = p_undo_redo;
preview_node = nullptr;
@@ -138,7 +139,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_name = memnew(Button);
but_insert_name->set_text("NAME");
- but_insert_name->set_tooltip(String("${NAME}\n") + TTR("Node name."));
+ but_insert_name->set_tooltip_text(String("${NAME}\n") + TTR("Node name."));
but_insert_name->set_focus_mode(Control::FOCUS_NONE);
but_insert_name->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${NAME}"));
but_insert_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -148,7 +149,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_parent = memnew(Button);
but_insert_parent->set_text("PARENT");
- but_insert_parent->set_tooltip(String("${PARENT}\n") + TTR("Node's parent name, if available."));
+ but_insert_parent->set_tooltip_text(String("${PARENT}\n") + TTR("Node's parent name, if available."));
but_insert_parent->set_focus_mode(Control::FOCUS_NONE);
but_insert_parent->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${PARENT}"));
but_insert_parent->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -158,7 +159,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_type = memnew(Button);
but_insert_type->set_text("TYPE");
- but_insert_type->set_tooltip(String("${TYPE}\n") + TTR("Node type."));
+ but_insert_type->set_tooltip_text(String("${TYPE}\n") + TTR("Node type."));
but_insert_type->set_focus_mode(Control::FOCUS_NONE);
but_insert_type->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${TYPE}"));
but_insert_type->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -168,7 +169,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_scene = memnew(Button);
but_insert_scene->set_text("SCENE");
- but_insert_scene->set_tooltip(String("${SCENE}\n") + TTR("Current scene name."));
+ but_insert_scene->set_tooltip_text(String("${SCENE}\n") + TTR("Current scene name."));
but_insert_scene->set_focus_mode(Control::FOCUS_NONE);
but_insert_scene->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${SCENE}"));
but_insert_scene->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -178,7 +179,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_root = memnew(Button);
but_insert_root->set_text("ROOT");
- but_insert_root->set_tooltip(String("${ROOT}\n") + TTR("Root node name."));
+ but_insert_root->set_tooltip_text(String("${ROOT}\n") + TTR("Root node name."));
but_insert_root->set_focus_mode(Control::FOCUS_NONE);
but_insert_root->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${ROOT}"));
but_insert_root->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -188,7 +189,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_count = memnew(Button);
but_insert_count->set_text("COUNTER");
- but_insert_count->set_tooltip(String("${COUNTER}\n") + TTR("Sequential integer counter.\nCompare counter options."));
+ but_insert_count->set_tooltip_text(String("${COUNTER}\n") + TTR("Sequential integer counter.\nCompare counter options."));
but_insert_count->set_focus_mode(Control::FOCUS_NONE);
but_insert_count->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${COUNTER}"));
but_insert_count->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -196,7 +197,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
chk_per_level_counter = memnew(CheckBox);
chk_per_level_counter->set_text(TTR("Per-level Counter"));
- chk_per_level_counter->set_tooltip(TTR("If set, the counter restarts for each group of child nodes."));
+ chk_per_level_counter->set_tooltip_text(TTR("If set, the counter restarts for each group of child nodes."));
vbc_substitute->add_child(chk_per_level_counter);
HBoxContainer *hbc_count_options = memnew(HBoxContainer);
@@ -204,32 +205,32 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
Label *lbl_count_start = memnew(Label);
lbl_count_start->set_text(TTR("Start"));
- lbl_count_start->set_tooltip(TTR("Initial value for the counter."));
+ lbl_count_start->set_tooltip_text(TTR("Initial value for the counter."));
hbc_count_options->add_child(lbl_count_start);
spn_count_start = memnew(SpinBox);
- spn_count_start->set_tooltip(TTR("Initial value for the counter."));
+ spn_count_start->set_tooltip_text(TTR("Initial value for the counter."));
spn_count_start->set_step(1);
spn_count_start->set_min(0);
hbc_count_options->add_child(spn_count_start);
Label *lbl_count_step = memnew(Label);
lbl_count_step->set_text(TTR("Step"));
- lbl_count_step->set_tooltip(TTR("Amount by which counter is incremented for each node."));
+ lbl_count_step->set_tooltip_text(TTR("Amount by which counter is incremented for each node."));
hbc_count_options->add_child(lbl_count_step);
spn_count_step = memnew(SpinBox);
- spn_count_step->set_tooltip(TTR("Amount by which counter is incremented for each node."));
+ spn_count_step->set_tooltip_text(TTR("Amount by which counter is incremented for each node."));
spn_count_step->set_step(1);
hbc_count_options->add_child(spn_count_step);
Label *lbl_count_padding = memnew(Label);
lbl_count_padding->set_text(TTR("Padding"));
- lbl_count_padding->set_tooltip(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
+ lbl_count_padding->set_tooltip_text(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
hbc_count_options->add_child(lbl_count_padding);
spn_count_padding = memnew(SpinBox);
- spn_count_padding->set_tooltip(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
+ spn_count_padding->set_tooltip_text(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
spn_count_padding->set_step(1);
hbc_count_options->add_child(spn_count_padding);
@@ -499,7 +500,7 @@ String RenameDialog::_postprocess(const String &subject) {
if (style_id == 1) {
// PascalCase to snake_case
- result = result.camelcase_to_underscore(true);
+ result = result.to_snake_case();
result = _regex("_+", result, "_");
} else if (style_id == 2) {
@@ -520,7 +521,7 @@ String RenameDialog::_postprocess(const String &subject) {
end = start + 1;
}
buffer += result.substr(end, result.size() - (end + 1));
- result = buffer.replace("_", "").capitalize();
+ result = buffer.to_pascal_case();
}
}
@@ -581,7 +582,7 @@ void RenameDialog::rename() {
// Forward recursive as opposed to the actual renaming.
_iterate_scene(root_node, selected_node_list, &global_count);
- if (undo_redo && !to_rename.is_empty()) {
+ if (undo_redo.is_valid() && !to_rename.is_empty()) {
undo_redo->create_action(TTR("Batch Rename"));
// Make sure to iterate reversed so that child nodes will find parents.
diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h
index f3a850045e..dac73b13b8 100644
--- a/editor/rename_dialog.h
+++ b/editor/rename_dialog.h
@@ -34,7 +34,6 @@
#include "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED
-#include "core/object/undo_redo.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/check_box.h"
#include "scene/gui/check_button.h"
@@ -43,6 +42,8 @@
#include "scene/gui/spin_box.h"
#include "scene/gui/tab_container.h"
+class EditorUndoRedoManager;
+
class RenameDialog : public ConfirmationDialog {
GDCLASS(RenameDialog, ConfirmationDialog);
@@ -63,7 +64,7 @@ class RenameDialog : public ConfirmationDialog {
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type);
SceneTreeEditor *scene_tree_editor = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
int global_count = 0;
LineEdit *lne_search = nullptr;
@@ -109,7 +110,7 @@ public:
void reset();
void rename();
- RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo = nullptr);
+ RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo = Ref<EditorUndoRedoManager>());
~RenameDialog() {}
};
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 94a5c07709..573e57ca04 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -53,7 +53,7 @@ void SceneCreateDialog::_notification(int p_what) {
node_type_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
node_type_gui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
node_type_other->add_theme_icon_override(SNAME("icon"), get_theme_icon(SNAME("Node"), SNAME("EditorIcons")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
}
}
@@ -111,7 +111,7 @@ void SceneCreateDialog::update_dialog() {
}
if (is_valid) {
- scene_name = directory.plus_file(scene_name);
+ scene_name = directory.path_join(scene_name);
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (da->file_exists(scene_name)) {
update_error(file_error_label, MSG_ERROR, TTR("File already exists."));
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index d19a40599f..488a651c29 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -222,28 +222,28 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
return;
}
- editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)"));
+ editor_data->get_undo_redo()->create_action(TTR("Instance Scene(s)"));
for (int i = 0; i < instances.size(); i++) {
Node *instantiated_scene = instances[i];
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true);
+ editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true);
if (p_pos >= 0) {
- editor_data->get_undo_redo().add_do_method(parent, "move_child", instantiated_scene, p_pos + i);
+ editor_data->get_undo_redo()->add_do_method(parent, "move_child", instantiated_scene, p_pos + i);
}
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene);
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", instantiated_scene);
- editor_data->get_undo_redo().add_do_reference(instantiated_scene);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", edited_scene);
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "clear");
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", instantiated_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", edited_scene->get_path_to(parent), p_files[i], new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name)));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(new_name)));
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
_push_item(instances[instances.size() - 1]);
for (int i = 0; i < instances.size(); i++) {
emit_signal(SNAME("node_created"), instances[i]);
@@ -265,7 +265,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Replace with Branch Scene"));
Node *parent = base->get_parent();
@@ -510,9 +510,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
if (selected) {
- create_dialog->popup_create(false, true, selected->get_class());
+ create_dialog->popup_create(false, true, selected->get_class(), selected->get_name());
}
-
} break;
case TOOL_EXTEND_SCRIPT: {
attach_script_to_selected(true);
@@ -531,23 +530,23 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- editor_data->get_undo_redo().create_action(TTR("Detach Script"));
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr);
+ editor_data->get_undo_redo()->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr);
for (int i = 0; i < selection.size(); i++) {
Node *n = Object::cast_to<Node>(selection[i]);
Ref<Script> existing = n->get_script();
Ref<Script> empty = EditorNode::get_singleton()->get_object_custom_type_base(n);
if (existing != empty) {
- editor_data->get_undo_redo().add_do_method(n, "set_script", empty);
- editor_data->get_undo_redo().add_undo_method(n, "set_script", existing);
+ editor_data->get_undo_redo()->add_do_method(n, "set_script", empty);
+ editor_data->get_undo_redo()->add_undo_method(n, "set_script", existing);
}
}
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
} break;
case TOOL_MOVE_UP:
case TOOL_MOVE_DOWN: {
@@ -602,10 +601,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
if (selection.size() == 1) {
- editor_data->get_undo_redo().create_action(TTR("Move Node In Parent"));
+ editor_data->get_undo_redo()->create_action(TTR("Move Node In Parent"));
}
if (selection.size() > 1) {
- editor_data->get_undo_redo().create_action(TTR("Move Nodes In Parent"));
+ editor_data->get_undo_redo()->create_action(TTR("Move Nodes In Parent"));
}
for (int i = 0; i < selection.size(); i++) {
@@ -618,11 +617,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
int bottom_node_pos = bottom_node->get_index();
int top_node_pos_next = top_node->get_index() + (MOVING_DOWN ? 1 : -1);
- editor_data->get_undo_redo().add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
- editor_data->get_undo_redo().add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
+ editor_data->get_undo_redo()->add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
+ editor_data->get_undo_redo()->add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
} break;
case TOOL_DUPLICATE: {
@@ -650,8 +649,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- editor_data->get_undo_redo().create_action(TTR("Duplicate Node(s)"));
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
+ editor_data->get_undo_redo()->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "clear");
Node *dupsingle = nullptr;
@@ -676,28 +675,28 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
dup->set_name(parent->validate_child_name(dup));
- editor_data->get_undo_redo().add_do_method(add_below_node, "add_sibling", dup, true);
+ editor_data->get_undo_redo()->add_do_method(add_below_node, "add_sibling", dup, true);
for (Node *F : owned) {
if (!duplimap.has(F)) {
continue;
}
Node *d = duplimap[F];
- editor_data->get_undo_redo().add_do_method(d, "set_owner", node->get_owner());
+ editor_data->get_undo_redo()->add_do_method(d, "set_owner", node->get_owner());
}
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", dup);
- editor_data->get_undo_redo().add_do_reference(dup);
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", dup);
+ editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", dup);
+ editor_data->get_undo_redo()->add_do_reference(dup);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name());
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name())));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name());
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name())));
add_below_node = dup;
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
if (dupsingle) {
_push_item(dupsingle);
@@ -766,29 +765,29 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- editor_data->get_undo_redo().create_action(TTR("Make node as Root"));
- editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node);
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", node);
- editor_data->get_undo_redo().add_do_method(node, "add_child", root, true);
- editor_data->get_undo_redo().add_do_method(node, "set_scene_file_path", root->get_scene_file_path());
- editor_data->get_undo_redo().add_do_method(root, "set_scene_file_path", String());
- editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)nullptr);
- editor_data->get_undo_redo().add_do_method(root, "set_owner", node);
+ editor_data->get_undo_redo()->create_action(TTR("Make node as Root"));
+ editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node);
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node);
+ editor_data->get_undo_redo()->add_do_method(node, "add_child", root, true);
+ editor_data->get_undo_redo()->add_do_method(node, "set_scene_file_path", root->get_scene_file_path());
+ editor_data->get_undo_redo()->add_do_method(root, "set_scene_file_path", String());
+ editor_data->get_undo_redo()->add_do_method(node, "set_owner", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_do_method(root, "set_owner", node);
_node_replace_owner(root, root, node, MODE_DO);
- editor_data->get_undo_redo().add_undo_method(root, "set_scene_file_path", root->get_scene_file_path());
- editor_data->get_undo_redo().add_undo_method(node, "set_scene_file_path", String());
- editor_data->get_undo_redo().add_undo_method(node, "remove_child", root);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root);
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true);
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, node->get_index());
- editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)nullptr);
- editor_data->get_undo_redo().add_undo_method(node, "set_owner", root);
+ editor_data->get_undo_redo()->add_undo_method(root, "set_scene_file_path", root->get_scene_file_path());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_scene_file_path", String());
+ editor_data->get_undo_redo()->add_undo_method(node, "remove_child", root);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, node->get_index());
+ editor_data->get_undo_redo()->add_undo_method(root, "set_owner", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_undo_method(node, "set_owner", root);
_node_replace_owner(root, root, root, MODE_UNDO);
- editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->commit_action();
} break;
case TOOL_MULTI_EDIT: {
if (!profile_allow_editing) {
@@ -1009,7 +1008,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *node = e->get();
if (node) {
Node *root = EditorNode::get_singleton()->get_edited_scene();
- UndoRedo *undo_redo = &editor_data->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo();
if (!root) {
break;
}
@@ -1069,24 +1068,61 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
} break;
case TOOL_TOGGLE_SCENE_UNIQUE_NAME: {
- List<Node *> selection = editor_selection->get_selected_node_list();
- List<Node *>::Element *e = selection.front();
- if (e) {
- UndoRedo *undo_redo = &editor_data->get_undo_redo();
- Node *node = e->get();
- bool enabled = node->is_unique_name_in_owner();
- if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) {
- accept->set_text(TTR("Another node already uses this unique name in the scene."));
+ // Enabling/disabling based on the same node based on which the checkbox in the menu is checked/unchecked.
+ List<Node *>::Element *first_selected = editor_selection->get_selected_node_list().front();
+ if (first_selected == nullptr) {
+ return;
+ }
+ bool enabling = !first_selected->get()->is_unique_name_in_owner();
+
+ List<Node *> full_selection = editor_selection->get_full_selected_node_list();
+ Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo();
+
+ if (enabling) {
+ Vector<Node *> new_unique_nodes;
+ Vector<StringName> new_unique_names;
+ Vector<StringName> cant_be_set_unique_names;
+
+ for (Node *node : full_selection) {
+ if (node->is_unique_name_in_owner()) {
+ continue;
+ }
+ StringName name = node->get_name();
+ if (new_unique_names.find(name) != -1 || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) {
+ cant_be_set_unique_names.push_back(name);
+ } else {
+ new_unique_nodes.push_back(node);
+ new_unique_names.push_back(name);
+ }
+ }
+
+ if (new_unique_nodes.size()) {
+ undo_redo->create_action(TTR("Enable Scene Unique Name(s)"));
+ for (Node *node : new_unique_nodes) {
+ undo_redo->add_do_method(node, "set_unique_name_in_owner", true);
+ undo_redo->add_undo_method(node, "set_unique_name_in_owner", false);
+ }
+ undo_redo->commit_action();
+ }
+
+ if (cant_be_set_unique_names.size()) {
+ String popup_text = TTR("Unique names already used by another node in the scene:");
+ popup_text += "\n";
+ for (StringName name : cant_be_set_unique_names) {
+ popup_text += "\n" + String(name);
+ }
+ accept->set_text(popup_text);
accept->popup_centered();
- return;
}
- if (!enabled) {
- undo_redo->create_action(TTR("Enable Scene Unique Name"));
- } else {
- undo_redo->create_action(TTR("Disable Scene Unique Name"));
+ } else { // Disabling.
+ undo_redo->create_action(TTR("Disable Scene Unique Name(s)"));
+ for (Node *node : full_selection) {
+ if (!node->is_unique_name_in_owner()) {
+ continue;
+ }
+ undo_redo->add_do_method(node, "set_unique_name_in_owner", false);
+ undo_redo->add_undo_method(node, "set_unique_name_in_owner", true);
}
- undo_redo->add_do_method(node, "set_unique_name_in_owner", !enabled);
- undo_redo->add_undo_method(node, "set_unique_name_in_owner", enabled);
undo_redo->commit_action();
}
} break;
@@ -1161,19 +1197,19 @@ void SceneTreeDock::_property_selected(int p_idx) {
}
void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) {
- editor_data->get_undo_redo().create_action(vformat(TTR("Set %s"), p_property));
- editor_data->get_undo_redo().add_do_property(p_node, p_property, p_res);
- editor_data->get_undo_redo().add_undo_property(p_node, p_property, p_node->get(p_property));
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(vformat(TTR("Set %s"), p_property));
+ editor_data->get_undo_redo()->add_do_property(p_node, p_property, p_res);
+ editor_data->get_undo_redo()->add_undo_property(p_node, p_property, p_node->get(p_property));
+ editor_data->get_undo_redo()->commit_action();
}
void SceneTreeDock::add_root_node(Node *p_node) {
- editor_data->get_undo_redo().create_action(TTR("New Scene Root"));
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node);
- editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_do_reference(p_node);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id());
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node);
+ editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_do_reference(p_node);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo()->commit_action();
}
void SceneTreeDock::_node_collapsed(Object *p_obj) {
@@ -1201,7 +1237,7 @@ void SceneTreeDock::_notification(int p_what) {
if (canvas_item_plugin) {
canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree"));
canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree"));
- scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::update));
+ scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::queue_redraw));
}
Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D"));
@@ -1219,19 +1255,17 @@ void SceneTreeDock::_notification(int p_what) {
// create_root_dialog
HBoxContainer *top_row = memnew(HBoxContainer);
- top_row->set_name("NodeShortcutsTopRow");
top_row->set_h_size_flags(SIZE_EXPAND_FILL);
Label *l = memnew(Label(TTR("Create Root Node:")));
l->set_theme_type_variation("HeaderSmall");
top_row->add_child(l);
top_row->add_spacer();
- Button *node_shortcuts_toggle = memnew(Button);
+ node_shortcuts_toggle = memnew(Button);
node_shortcuts_toggle->set_flat(true);
- node_shortcuts_toggle->set_name("NodeShortcutsToggle");
node_shortcuts_toggle->set_icon(get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
node_shortcuts_toggle->set_toggle_mode(true);
- node_shortcuts_toggle->set_tooltip(TTR("Switch to Favorite Nodes"));
+ node_shortcuts_toggle->set_tooltip_text(TTR("Switch to Favorite Nodes"));
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT);
node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
@@ -1240,18 +1274,15 @@ void SceneTreeDock::_notification(int p_what) {
create_root_dialog->add_child(top_row);
ScrollContainer *scroll_container = memnew(ScrollContainer);
- scroll_container->set_name("NodeShortcutsScrollContainer");
create_root_dialog->add_child(scroll_container);
scroll_container->set_v_size_flags(SIZE_EXPAND_FILL);
scroll_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
VBoxContainer *node_shortcuts = memnew(VBoxContainer);
- node_shortcuts->set_name("NodeShortcuts");
scroll_container->add_child(node_shortcuts);
node_shortcuts->set_h_size_flags(SIZE_EXPAND_FILL);
- VBoxContainer *beginner_node_shortcuts = memnew(VBoxContainer);
- beginner_node_shortcuts->set_name("BeginnerNodeShortcuts");
+ beginner_node_shortcuts = memnew(VBoxContainer);
node_shortcuts->add_child(beginner_node_shortcuts);
button_2d = memnew(Button);
@@ -1272,8 +1303,7 @@ void SceneTreeDock::_notification(int p_what) {
button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
button_ui->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_USER_INTERFACE, false));
- VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer);
- favorite_node_shortcuts->set_name("FavoriteNodeShortcuts");
+ favorite_node_shortcuts = memnew(VBoxContainer);
node_shortcuts->add_child(favorite_node_shortcuts);
button_custom = memnew(Button);
@@ -1335,7 +1365,7 @@ void SceneTreeDock::_notification(int p_what) {
void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) {
if (p_node->get_owner() == p_base && p_node != p_root) {
- UndoRedo *undo_redo = &editor_data->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo();
switch (p_mode) {
case MODE_BIDI: {
bool disable_unique = p_node->is_unique_name_in_owner() && p_root->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr;
@@ -1470,7 +1500,7 @@ bool SceneTreeDock::_update_node_path(Node *p_root_node, NodePath &r_node_path,
if (found_root_path) {
NodePath root_path_new = found_root_path->value;
if (!root_path_new.is_empty()) {
- NodePath old_abs_path = NodePath(String(p_root_node->get_path()).plus_file(r_node_path));
+ NodePath old_abs_path = NodePath(String(p_root_node->get_path()).path_join(r_node_path));
old_abs_path.simplify();
r_node_path = root_path_new.rel_path_to(old_abs_path);
}
@@ -1568,8 +1598,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
Variant old_variant = p_base->get(propertyname);
Variant updated_variant = old_variant;
if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
- editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant);
- editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant);
+ editor_data->get_undo_redo()->add_do_property(p_base, propertyname, updated_variant);
+ editor_data->get_undo_redo()->add_undo_property(p_base, propertyname, old_variant);
p_base->set(propertyname, updated_variant);
}
}
@@ -1627,12 +1657,12 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
ERR_FAIL_COND(!EI); //another bug
}
- editor_data->get_undo_redo().add_do_method(anim.ptr(), "remove_track", idx);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
+ editor_data->get_undo_redo()->add_do_method(anim.ptr(), "remove_track", idx);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
for (int j = 0; j < anim->track_get_key_count(i); j++) {
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
}
ran.erase(i); //byebye channel
@@ -1645,8 +1675,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
if (new_path == track_np) {
continue; //bleh
}
- editor_data->get_undo_redo().add_do_method(anim.ptr(), "track_set_path", i, new_path);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", i, track_np);
+ editor_data->get_undo_redo()->add_do_method(anim.ptr(), "track_set_path", i, new_path);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", i, track_np);
}
}
}
@@ -1780,7 +1810,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
// Sort by tree order, so re-adding is easy.
p_nodes.sort_custom<Node::Comparator>();
- editor_data->get_undo_redo().create_action(TTR("Reparent Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Reparent Node"));
HashMap<Node *, NodePath> path_renames;
Vector<StringName> former_names;
@@ -1805,11 +1835,11 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
inc--; // If the child will generate a gap when moved, adjust.
}
- editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node);
- editor_data->get_undo_redo().add_do_method(new_parent, "add_child", node, true);
+ editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node);
+ editor_data->get_undo_redo()->add_do_method(new_parent, "add_child", node, true);
if (p_position_in_parent >= 0) {
- editor_data->get_undo_redo().add_do_method(new_parent, "move_child", node, p_position_in_parent + inc);
+ editor_data->get_undo_redo()->add_do_method(new_parent, "move_child", node, p_position_in_parent + inc);
}
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
@@ -1839,29 +1869,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
}
}
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
if (p_keep_global_xform) {
if (Object::cast_to<Node2D>(node)) {
- editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform());
+ editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform());
}
if (Object::cast_to<Node3D>(node)) {
- editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform());
+ editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform());
}
if (Object::cast_to<Control>(node)) {
- editor_data->get_undo_redo().add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position());
+ editor_data->get_undo_redo()->add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position());
}
}
- editor_data->get_undo_redo().add_do_method(this, "_set_owners", edited_scene, owners);
+ editor_data->get_undo_redo()->add_do_method(this, "_set_owners", edited_scene, owners);
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
- editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
+ editor_data->get_undo_redo()->add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
}
- editor_data->get_undo_redo().add_undo_method(new_parent, "remove_child", node);
- editor_data->get_undo_redo().add_undo_method(node, "set_name", former_names[ni]);
+ editor_data->get_undo_redo()->add_undo_method(new_parent, "remove_child", node);
+ editor_data->get_undo_redo()->add_undo_method(node, "set_name", former_names[ni]);
inc++;
}
@@ -1879,29 +1909,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
int child_pos = node->get_index();
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true);
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, child_pos);
- editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, child_pos);
+ editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners);
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
- editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
+ editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
}
if (p_keep_global_xform) {
if (Object::cast_to<Node2D>(node)) {
- editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform());
}
if (Object::cast_to<Node3D>(node)) {
- editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform());
}
if (Object::cast_to<Control>(node)) {
- editor_data->get_undo_redo().add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position());
}
}
}
perform_node_renames(nullptr, &path_renames);
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
}
bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
@@ -1957,30 +1987,30 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
Node *node = selected.front()->get();
Ref<Script> existing = node->get_script();
- editor_data->get_undo_redo().create_action(TTR("Attach Script"));
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", node);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node);
- editor_data->get_undo_redo().add_do_method(node, "set_script", p_script);
- editor_data->get_undo_redo().add_undo_method(node, "set_script", existing);
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node);
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Attach Script"));
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", node);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node);
+ editor_data->get_undo_redo()->add_do_method(node, "set_script", p_script);
+ editor_data->get_undo_redo()->add_undo_method(node, "set_script", existing);
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node);
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->commit_action();
} else {
- editor_data->get_undo_redo().create_action(TTR("Attach Script"));
- for (List<Node *>::Element *E = selected.front(); E; E = E->next()) {
- Ref<Script> existing = E->get()->get_script();
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", E->get());
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E->get());
- editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script);
- editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E->get());
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E->get());
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->create_action(TTR("Attach Script"));
+ for (Node *E : selected) {
+ Ref<Script> existing = E->get_script();
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E);
+ editor_data->get_undo_redo()->add_do_method(E, "set_script", p_script);
+ editor_data->get_undo_redo()->add_undo_method(E, "set_script", existing);
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E);
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
}
_push_item(p_script.operator->());
@@ -1994,10 +2024,10 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) {
Ref<Shader> existing = selected_shader_material->get_shader();
- editor_data->get_undo_redo().create_action(TTR("Set Shader"));
- editor_data->get_undo_redo().add_do_method(selected_shader_material.ptr(), "set_shader", p_shader);
- editor_data->get_undo_redo().add_undo_method(selected_shader_material.ptr(), "set_shader", existing);
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Set Shader"));
+ editor_data->get_undo_redo()->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader);
+ editor_data->get_undo_redo()->add_undo_method(selected_shader_material.ptr(), "set_shader", existing);
+ editor_data->get_undo_redo()->commit_action();
}
void SceneTreeDock::_script_creation_closed() {
@@ -2063,9 +2093,9 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false);
if (p_cut) {
- editor_data->get_undo_redo().create_action(TTR("Cut Node(s)"));
+ editor_data->get_undo_redo()->create_action(TTR("Cut Node(s)"));
} else {
- editor_data->get_undo_redo().create_action(TTR("Remove Node(s)"));
+ editor_data->get_undo_redo()->create_action(TTR("Remove Node(s)"));
}
bool entire_scene = false;
@@ -2077,11 +2107,11 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
}
if (entire_scene) {
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene);
- editor_data->get_undo_redo().add_undo_method(edited_scene, "set_owner", edited_scene->get_owner());
- editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_undo_reference(edited_scene);
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene);
+ editor_data->get_undo_redo()->add_undo_method(edited_scene, "set_owner", edited_scene->get_owner());
+ editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_undo_reference(edited_scene);
} else {
remove_list.sort_custom<Node::Comparator>(); //sort nodes to keep positions
@@ -2110,25 +2140,25 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
owners.push_back(F);
}
- editor_data->get_undo_redo().add_do_method(n->get_parent(), "remove_child", n);
- editor_data->get_undo_redo().add_undo_method(n->get_parent(), "add_child", n, true);
- editor_data->get_undo_redo().add_undo_method(n->get_parent(), "move_child", n, n->get_index());
+ editor_data->get_undo_redo()->add_do_method(n->get_parent(), "remove_child", n);
+ editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "add_child", n, true);
+ editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "move_child", n, n->get_index());
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == n) {
- editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n);
+ editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n);
}
- editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners);
- editor_data->get_undo_redo().add_undo_reference(n);
+ editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners);
+ editor_data->get_undo_redo()->add_undo_reference(n);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id());
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index());
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id());
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index());
}
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
// hack, force 2d editor viewport to refresh after deletion
if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton()) {
- editor->get_viewport_control()->update();
+ editor->get_viewport_control()->queue_redraw();
}
_push_item(nullptr);
@@ -2190,29 +2220,29 @@ void SceneTreeDock::_do_create(Node *p_parent) {
Node *child = Object::cast_to<Node>(c);
ERR_FAIL_COND(!child);
- editor_data->get_undo_redo().create_action(TTR("Create Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Create Node"));
if (edited_scene) {
- editor_data->get_undo_redo().add_do_method(p_parent, "add_child", child, true);
- editor_data->get_undo_redo().add_do_method(child, "set_owner", edited_scene);
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", child);
- editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(p_parent, "remove_child", child);
+ editor_data->get_undo_redo()->add_do_method(p_parent, "add_child", child, true);
+ editor_data->get_undo_redo()->add_do_method(child, "set_owner", edited_scene);
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "clear");
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", child);
+ editor_data->get_undo_redo()->add_do_reference(child);
+ editor_data->get_undo_redo()->add_undo_method(p_parent, "remove_child", child);
String new_name = p_parent->validate_child_name(child);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name)));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
} else {
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
- editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
+ editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_do_reference(child);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
_push_item(c);
editor_selection->clear();
editor_selection->add_node(child);
@@ -2259,8 +2289,8 @@ void SceneTreeDock::_create() {
List<Node *> selection = editor_selection->get_selected_node_list();
ERR_FAIL_COND(selection.size() <= 0);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change type of node(s)"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
for (Node *n : selection) {
ERR_FAIL_COND(!n);
@@ -2393,7 +2423,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
}
//p_remove_old was added to support undo
if (p_remove_old) {
- editor_data->get_undo_redo().clear_history();
+ editor_data->get_undo_redo()->clear_history();
}
newnode->set_name(newname);
@@ -2607,16 +2637,16 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
Ref<Script> scr = ResourceLoader::load(p_file);
ERR_FAIL_COND(!scr.is_valid());
if (Node *n = get_node(p_to)) {
- editor_data->get_undo_redo().create_action(TTR("Attach Script"));
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", n);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n);
- editor_data->get_undo_redo().add_do_method(n, "set_script", scr);
- editor_data->get_undo_redo().add_undo_method(n, "set_script", n->get_script());
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n);
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Attach Script"));
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", n);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n);
+ editor_data->get_undo_redo()->add_do_method(n, "set_script", scr);
+ editor_data->get_undo_redo()->add_undo_method(n, "set_script", n->get_script());
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n);
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->commit_action();
}
}
@@ -2678,7 +2708,7 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
}
int index = menu_subresources->get_item_count();
menu_subresources->add_icon_item(icon, E.name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
- menu_subresources->set_item_horizontal_offset(index, p_depth * 10 * EDSCALE);
+ menu_subresources->set_item_indent(index, p_depth);
subresources.push_back(obj->get_instance_id());
_add_children_to_popup(obj, p_depth + 1);
@@ -2822,14 +2852,26 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_separator();
menu->add_icon_shortcut(get_theme_icon(SNAME("CopyNodePath"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH);
}
+ }
- if (selection[0]->get_owner() == EditorNode::get_singleton()->get_edited_scene()) {
- // Only for nodes owned by the edited scene root.
+ if (profile_allow_editing) {
+ // Allow multi-toggling scene unique names but only if all selected nodes are owned by the edited scene root.
+ bool all_owned = true;
+ for (Node *node : full_selection) {
+ if (node->get_owner() != EditorNode::get_singleton()->get_edited_scene()) {
+ all_owned = false;
+ break;
+ }
+ }
+ if (all_owned) {
menu->add_separator();
menu->add_icon_check_item(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
+ // Checked based on `selection[0]` because `full_selection` has undesired ordering.
menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner());
}
+ }
+ if (selection.size() == 1) {
bool is_external = (!selection[0]->get_scene_file_path().is_empty());
if (is_external) {
bool is_inherited = selection[0]->get_scene_inherited_state() != nullptr;
@@ -2939,9 +2981,9 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) {
if (path.is_empty()) {
String root_path = editor_data->get_edited_scene_root()->get_scene_file_path();
if (root_path.is_empty()) {
- path = String("res://").plus_file(selected->get_name());
+ path = String("res://").path_join(selected->get_name());
} else {
- path = root_path.get_base_dir().plus_file(selected->get_name());
+ path = root_path.get_base_dir().path_join(selected->get_name());
}
}
@@ -2998,9 +3040,9 @@ void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) {
shader_name = selected_shader_material->get_name();
}
if (root_path.is_empty()) {
- path = String("res://").plus_file(shader_name);
+ path = String("res://").path_join(shader_name);
} else {
- path = root_path.get_base_dir().plus_file(shader_name);
+ path = root_path.get_base_dir().path_join(shader_name);
}
}
@@ -3064,9 +3106,9 @@ List<Node *> SceneTreeDock::paste_nodes() {
owner = paste_parent;
}
- UndoRedo &ur = editor_data->get_undo_redo();
- ur.create_action(TTR("Paste Node(s)"));
- ur.add_do_method(editor_selection, "clear");
+ Ref<EditorUndoRedoManager> &ur = editor_data->get_undo_redo();
+ ur->create_action(TTR("Paste Node(s)"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ ur->add_do_method(editor_selection, "clear");
HashMap<Ref<Resource>, Ref<Resource>> resource_remap;
String target_scene;
@@ -3095,36 +3137,36 @@ List<Node *> SceneTreeDock::paste_nodes() {
if (!paste_parent) {
paste_parent = dup;
owner = dup;
- ur.add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup);
+ ur->add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup);
} else {
- ur.add_do_method(paste_parent, "add_child", dup, true);
+ ur->add_do_method(paste_parent, "add_child", dup, true);
}
for (KeyValue<const Node *, Node *> &E2 : duplimap) {
Node *d = E2.value;
if (d != dup) {
- ur.add_do_method(d, "set_owner", owner);
+ ur->add_do_method(d, "set_owner", owner);
}
}
if (dup != owner) {
- ur.add_do_method(dup, "set_owner", owner);
+ ur->add_do_method(dup, "set_owner", owner);
}
- ur.add_do_method(editor_selection, "add_node", dup);
+ ur->add_do_method(editor_selection, "add_node", dup);
if (dup == paste_parent) {
- ur.add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ ur->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
} else {
- ur.add_undo_method(paste_parent, "remove_child", dup);
+ ur->add_undo_method(paste_parent, "remove_child", dup);
}
- ur.add_do_reference(dup);
+ ur->add_do_reference(dup);
if (node_clipboard.size() == 1) {
- ur.add_do_method(EditorNode::get_singleton(), "push_item", dup);
+ ur->add_do_method(EditorNode::get_singleton(), "push_item", dup);
}
}
- ur.commit_action();
+ ur->commit_action();
return pasted_nodes;
}
@@ -3179,35 +3221,21 @@ void SceneTreeDock::_local_tree_selected() {
}
void SceneTreeDock::_update_create_root_dialog() {
- BaseButton *toggle = Object::cast_to<BaseButton>(create_root_dialog->get_node(String("NodeShortcutsTopRow/NodeShortcutsToggle")));
- Node *node_shortcuts = create_root_dialog->get_node(String("NodeShortcutsScrollContainer/NodeShortcuts"));
-
- if (!toggle || !node_shortcuts) {
- return;
- }
-
- Control *beginner_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("BeginnerNodeShortcuts")));
- Control *favorite_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("FavoriteNodeShortcuts")));
-
- if (!beginner_nodes || !favorite_nodes) {
- return;
- }
-
- EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", toggle->is_pressed());
+ EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", node_shortcuts_toggle->is_pressed());
EditorSettings::get_singleton()->save();
- if (toggle->is_pressed()) {
- for (int i = 0; i < favorite_nodes->get_child_count(); i++) {
- favorite_nodes->get_child(i)->queue_delete();
+ if (node_shortcuts_toggle->is_pressed()) {
+ for (int i = 0; i < favorite_node_shortcuts->get_child_count(); i++) {
+ favorite_node_shortcuts->get_child(i)->queue_delete();
}
- Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ);
+ Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites.Node"), FileAccess::READ);
if (f.is_valid()) {
while (!f->eof_reached()) {
String l = f->get_line().strip_edges();
if (!l.is_empty()) {
Button *button = memnew(Button);
- favorite_nodes->add_child(button);
+ favorite_node_shortcuts->add_child(button);
button->set_text(l);
button->set_clip_text(true);
String name = l.get_slicec(' ', 0);
@@ -3220,14 +3248,14 @@ void SceneTreeDock::_update_create_root_dialog() {
}
}
- if (!favorite_nodes->is_visible_in_tree()) {
- favorite_nodes->show();
- beginner_nodes->hide();
+ if (!favorite_node_shortcuts->is_visible_in_tree()) {
+ favorite_node_shortcuts->show();
+ beginner_node_shortcuts->hide();
}
} else {
- if (!beginner_nodes->is_visible_in_tree()) {
- beginner_nodes->show();
- favorite_nodes->hide();
+ if (!beginner_node_shortcuts->is_visible_in_tree()) {
+ beginner_node_shortcuts->show();
+ favorite_node_shortcuts->hide();
}
button_clipboard->set_visible(!node_clipboard.is_empty());
}
@@ -3374,38 +3402,38 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KeyModifierMask::SHIFT | Key::F2);
ED_SHORTCUT_OVERRIDE("scene_tree/batch_rename", "macos", KeyModifierMask::SHIFT | Key::ENTER);
- ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KeyModifierMask::CMD | Key::A);
- ED_SHORTCUT("scene_tree/instance_scene", TTR("Instantiate Child Scene"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::A);
+ ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KeyModifierMask::CMD_OR_CTRL | Key::A);
+ ED_SHORTCUT("scene_tree/instance_scene", TTR("Instantiate Child Scene"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::A);
ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse Branch"));
- ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KeyModifierMask::CMD | Key::X);
- ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KeyModifierMask::CMD | Key::C);
- ED_SHORTCUT("scene_tree/paste_node", TTR("Paste"), KeyModifierMask::CMD | Key::V);
+ ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KeyModifierMask::CMD_OR_CTRL | Key::X);
+ ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KeyModifierMask::CMD_OR_CTRL | Key::C);
+ ED_SHORTCUT("scene_tree/paste_node", TTR("Paste"), KeyModifierMask::CMD_OR_CTRL | Key::V);
ED_SHORTCUT("scene_tree/change_node_type", TTR("Change Type"));
ED_SHORTCUT("scene_tree/attach_script", TTR("Attach Script"));
ED_SHORTCUT("scene_tree/extend_script", TTR("Extend Script"));
ED_SHORTCUT("scene_tree/detach_script", TTR("Detach Script"));
- ED_SHORTCUT("scene_tree/move_up", TTR("Move Up"), KeyModifierMask::CMD | Key::UP);
- ED_SHORTCUT("scene_tree/move_down", TTR("Move Down"), KeyModifierMask::CMD | Key::DOWN);
- ED_SHORTCUT("scene_tree/duplicate", TTR("Duplicate"), KeyModifierMask::CMD | Key::D);
+ ED_SHORTCUT("scene_tree/move_up", TTR("Move Up"), KeyModifierMask::CMD_OR_CTRL | Key::UP);
+ ED_SHORTCUT("scene_tree/move_down", TTR("Move Down"), KeyModifierMask::CMD_OR_CTRL | Key::DOWN);
+ ED_SHORTCUT("scene_tree/duplicate", TTR("Duplicate"), KeyModifierMask::CMD_OR_CTRL | Key::D);
ED_SHORTCUT("scene_tree/reparent", TTR("Reparent"));
ED_SHORTCUT("scene_tree/reparent_to_new_node", TTR("Reparent to New Node"));
ED_SHORTCUT("scene_tree/make_root", TTR("Make Scene Root"));
ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene"));
- ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::C);
+ ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KeyModifierMask::SHIFT | Key::KEY_DELETE);
ED_SHORTCUT("scene_tree/delete", TTR("Delete"), Key::KEY_DELETE);
button_add = memnew(Button);
button_add->set_flat(true);
button_add->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
- button_add->set_tooltip(TTR("Add/Create a New Node."));
+ button_add->set_tooltip_text(TTR("Add/Create a New Node."));
button_add->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node"));
filter_hbc->add_child(button_add);
button_instance = memnew(Button);
button_instance->set_flat(true);
button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_INSTANTIATE, false));
- button_instance->set_tooltip(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists."));
+ button_instance->set_tooltip_text(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists."));
button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene"));
filter_hbc->add_child(button_instance);
@@ -3420,7 +3448,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_create_script = memnew(Button);
button_create_script->set_flat(true);
button_create_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_ATTACH_SCRIPT, false));
- button_create_script->set_tooltip(TTR("Attach a new or existing script to the selected node."));
+ button_create_script->set_tooltip_text(TTR("Attach a new or existing script to the selected node."));
button_create_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script"));
filter_hbc->add_child(button_create_script);
button_create_script->hide();
@@ -3428,7 +3456,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_detach_script = memnew(Button);
button_detach_script->set_flat(true);
button_detach_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_DETACH_SCRIPT, false));
- button_detach_script->set_tooltip(TTR("Detach the script from the selected node."));
+ button_detach_script->set_tooltip_text(TTR("Detach the script from the selected node."));
button_detach_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/detach_script"));
filter_hbc->add_child(button_detach_script);
button_detach_script->hide();
@@ -3451,7 +3479,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
edit_remote->set_h_size_flags(SIZE_EXPAND_FILL);
edit_remote->set_text(TTR("Remote"));
edit_remote->set_toggle_mode(true);
- edit_remote->set_tooltip(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
+ edit_remote->set_tooltip_text(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
edit_remote->connect("pressed", callable_mp(this, &SceneTreeDock::_remote_tree_selected));
edit_local = memnew(Button);
@@ -3492,7 +3520,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
- scene_tree->set_undo_redo(&editor_data->get_undo_redo());
+ scene_tree->set_undo_redo(editor_data->get_undo_redo());
scene_tree->set_editor_selection(editor_selection);
create_dialog = memnew(CreateDialog);
@@ -3502,7 +3530,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
create_dialog->connect("favorites_updated", callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
#ifdef MODULE_REGEX_ENABLED
- rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo()));
+ rename_dialog = memnew(RenameDialog(scene_tree, editor_data->get_undo_redo()));
add_child(rename_dialog);
#endif // MODULE_REGEX_ENABLED
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index e15865036b..dc228e1c93 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -119,6 +119,10 @@ class SceneTreeDock : public VBoxContainer {
Button *button_detach_script = nullptr;
MenuButton *button_tree_menu = nullptr;
+ Button *node_shortcuts_toggle = nullptr;
+ VBoxContainer *beginner_node_shortcuts = nullptr;
+ VBoxContainer *favorite_node_shortcuts = nullptr;
+
Button *button_2d = nullptr;
Button *button_3d = nullptr;
Button *button_ui = nullptr;
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index ad83db9b60..50bb6496e1 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/node_dock.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
@@ -278,7 +279,19 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
warning_icon = SNAME("NodeWarnings4Plus");
}
- item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + warning);
+ // Improve looks on tooltip, extra spacing on non-bullet point newlines.
+ const String bullet_point = String::utf8("• ");
+ int next_newline = 0;
+ while (next_newline != -1) {
+ next_newline = warning.find("\n", next_newline + 2);
+ if (warning.substr(next_newline + 1, bullet_point.length()) != bullet_point) {
+ warning = warning.insert(next_newline + 1, " ");
+ }
+ }
+
+ String newline = (num_warnings == 1 ? "\n" : "\n\n");
+
+ item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + newline + warning);
}
if (p_node->is_unique_name_in_owner()) {
@@ -341,7 +354,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
tooltip += "\n\n" + p_node->get_editor_description();
}
- item->set_tooltip(0, tooltip);
+ item->set_tooltip_text(0, tooltip);
} else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) {
item->add_button(0, get_theme_icon(SNAME("InstanceOptions"), SNAME("EditorIcons")), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
@@ -350,7 +363,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
tooltip += "\n\n" + p_node->get_editor_description();
}
- item->set_tooltip(0, tooltip);
+ item->set_tooltip_text(0, tooltip);
} else {
StringName type = EditorNode::get_singleton()->get_object_custom_type_name(p_node);
if (type == StringName()) {
@@ -362,10 +375,10 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
tooltip += "\n\n" + p_node->get_editor_description();
}
- item->set_tooltip(0, tooltip);
+ item->set_tooltip_text(0, tooltip);
}
- if (can_open_instance && undo_redo) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
+ if (can_open_instance && undo_redo.is_valid()) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
if (!p_node->is_connected("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed))) {
p_node->connect("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed).bind(p_node));
@@ -373,10 +386,19 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
Ref<Script> script = p_node->get_script();
if (!script.is_null()) {
- item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path());
+ String additional_notes;
+ Color button_color = Color(1, 1, 1);
+ // Can't set tooltip after adding button, need to do it before.
+ if (script->is_tool()) {
+ additional_notes += "\n" + TTR("This script is currently running in the editor.");
+ button_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ }
if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) {
- item->set_button_color(0, item->get_button_count(0) - 1, Color(1, 1, 1, 0.5));
+ additional_notes += "\n" + TTR("This script is a custom type.");
+ button_color.a = 0.5;
}
+ item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path() + additional_notes);
+ item->set_button_color(0, item->get_button_count(0) - 1, button_color);
}
if (p_node->is_class("CanvasItem")) {
@@ -492,7 +514,7 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
if (p_node->is_class("CanvasItem") || p_node->is_class("CanvasLayer") || p_node->is_class("Window")) {
visible = p_node->call("is_visible");
- CanvasItemEditor::get_singleton()->get_viewport_control()->update();
+ CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw();
} else if (p_node->is_class("Node3D")) {
visible = p_node->call("is_visible");
}
@@ -602,7 +624,9 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
}
if (!keep) {
- keep = filter.is_subsequence_ofn(p_parent->get_text(0));
+ StringName node_type = get_node(p_parent->get_metadata(0))->get_class();
+ bool is_kept_by_type = (filter.begins_with("type:") && filter.trim_prefix("type:").is_subsequence_ofn(node_type)) || (filter.begins_with("t:") && filter.trim_prefix("t:").is_subsequence_ofn(node_type));
+ keep = (filter.is_subsequence_ofn(p_parent->get_text(0)) || is_kept_by_type);
}
p_parent->set_visible(keep);
@@ -883,7 +907,7 @@ void SceneTreeEditor::_renamed() {
return;
}
- if (!undo_redo) {
+ if (!undo_redo.is_valid()) {
n->set_name(new_name);
which->set_metadata(0, n->get_path());
emit_signal(SNAME("node_renamed"));
@@ -927,6 +951,10 @@ String SceneTreeEditor::get_filter() const {
return filter;
}
+void SceneTreeEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void SceneTreeEditor::set_display_foreign_nodes(bool p_display) {
display_foreign = p_display;
_update_tree();
@@ -1258,7 +1286,6 @@ void SceneTreeEditor::_bind_methods() {
}
SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_open_instance) {
- undo_redo = nullptr;
selected = nullptr;
can_rename = p_can_rename;
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index 31772e55b5..0c13ad96cd 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -31,13 +31,14 @@
#ifndef SCENE_TREE_EDITOR_H
#define SCENE_TREE_EDITOR_H
-#include "core/object/undo_redo.h"
#include "editor/editor_data.h"
#include "editor/editor_settings.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class SceneTreeEditor : public Control {
GDCLASS(SceneTreeEditor, Control);
@@ -98,7 +99,7 @@ class SceneTreeEditor : public Control {
bool show_enabled_subscene = false;
void _renamed();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
HashSet<Node *> marked;
bool marked_selectable = false;
@@ -139,7 +140,7 @@ public:
void set_filter(const String &p_filter);
String get_filter() const;
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; };
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_display_foreign_nodes(bool p_display);
void set_marked(const HashSet<Node *> &p_marked, bool p_selectable = false, bool p_children_selectable = true);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 77e0321f83..f57dfe4827 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -134,7 +134,7 @@ void ScriptCreateDialog::_notification(int p_what) {
path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
parent_browse_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
parent_search_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
} break;
}
}
@@ -166,6 +166,7 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_
class_name->deselect();
parent_name->set_text(p_base_name);
parent_name->deselect();
+ internal_name->set_text("");
if (!p_base_path.is_empty()) {
initial_bp = p_base_path.get_basename();
@@ -201,7 +202,7 @@ bool ScriptCreateDialog::_validate_parent(const String &p_string) {
}
}
- return ClassDB::class_exists(p_string) || ScriptServer::is_global_class(p_string);
+ return EditorNode::get_editor_data().is_type_recognized(p_string);
}
bool ScriptCreateDialog::_validate_class(const String &p_string) {
@@ -371,7 +372,15 @@ void ScriptCreateDialog::_create_new() {
const ScriptLanguage::ScriptTemplate sinfo = _get_current_template();
- scr = ScriptServer::get_language(language_menu->get_selected())->make_template(sinfo.content, cname_param, parent_name->get_text());
+ String parent_class = parent_name->get_text();
+ if (!ClassDB::class_exists(parent_class) && !ScriptServer::is_global_class(parent_class)) {
+ // If base is a custom type, replace with script path instead.
+ const EditorData::CustomType *type = EditorNode::get_editor_data().get_custom_type_by_name(parent_class);
+ ERR_FAIL_NULL(type);
+ parent_class = "\"" + type->script->get_path() + "\"";
+ }
+
+ scr = ScriptServer::get_language(language_menu->get_selected())->make_template(sinfo.content, cname_param, parent_class);
if (has_named_classes) {
String cname = class_name->get_text();
@@ -823,7 +832,7 @@ Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(c
Vector<ScriptLanguage::ScriptTemplate> user_templates;
String extension = language->get_extension();
- String dir_path = p_dir.plus_file(p_object);
+ String dir_path = p_dir.path_join(p_object);
Ref<DirAccess> d = DirAccess::open(dir_path);
if (d.is_valid()) {
@@ -859,7 +868,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL
// Parse file for meta-information and script content
Error err;
- Ref<FileAccess> file = FileAccess::open(p_path.plus_file(p_filename), FileAccess::READ, &err);
+ Ref<FileAccess> file = FileAccess::open(p_path.path_join(p_filename), FileAccess::READ, &err);
if (!err) {
while (!file->eof_reached()) {
String line = file->get_line();
@@ -897,7 +906,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL
// Get name from file name if no name in meta information
if (script_template.name == String()) {
- script_template.name = p_filename.get_basename().replace("_", " ").capitalize();
+ script_template.name = p_filename.get_basename().capitalize();
}
return script_template;
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index bd1f2529ca..ae533b5b75 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -37,6 +37,13 @@
#include "scene/resources/visual_shader.h"
#include "servers/rendering/shader_types.h"
+enum ShaderType {
+ SHADER_TYPE_TEXT,
+ SHADER_TYPE_VISUAL,
+ SHADER_TYPE_INC,
+ SHADER_TYPE_MAX,
+};
+
void ShaderCreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -82,7 +89,7 @@ void ShaderCreateDialog::_update_theme() {
}
path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
- status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
}
void ShaderCreateDialog::_update_language_info() {
@@ -154,7 +161,7 @@ void ShaderCreateDialog::_create_new() {
shader = text_shader;
StringBuilder code;
- code += vformat("shader_type %s;\n", mode_menu->get_text().replace(" ", "").camelcase_to_underscore());
+ code += vformat("shader_type %s;\n", mode_menu->get_text().to_snake_case());
if (current_template == 0) { // Default template.
code += "\n";
diff --git a/editor/shader_create_dialog.h b/editor/shader_create_dialog.h
index bf031c3601..9ba655369b 100644
--- a/editor/shader_create_dialog.h
+++ b/editor/shader_create_dialog.h
@@ -44,13 +44,6 @@ class EditorFileDialog;
class ShaderCreateDialog : public ConfirmationDialog {
GDCLASS(ShaderCreateDialog, ConfirmationDialog);
- enum ShaderType {
- SHADER_TYPE_TEXT,
- SHADER_TYPE_VISUAL,
- SHADER_TYPE_INC,
- SHADER_TYPE_MAX,
- };
-
struct ShaderTypeData {
List<String> extensions;
String default_extension;
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 1cd1b4ea00..eef0f3eae1 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "servers/rendering/shader_language.h"
static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {
@@ -79,18 +80,18 @@ protected:
}
bool _set(const StringName &p_name, const Variant &p_value) {
- Variant existing = RS::get_singleton()->global_shader_uniform_get(p_name);
+ Variant existing = RS::get_singleton()->global_shader_parameter_get(p_name);
if (existing.get_type() == Variant::NIL) {
return false;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Set Shader Global Variable"));
- undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_set", p_name, p_value);
- undo_redo->add_undo_method(RS::get_singleton(), "global_shader_uniform_set", p_name, existing);
- RS::GlobalShaderUniformType type = RS::get_singleton()->global_shader_uniform_get_type(p_name);
+ undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value);
+ undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_set", p_name, existing);
+ RS::GlobalShaderParameterType type = RS::get_singleton()->global_shader_parameter_get_type(p_name);
Dictionary gv;
gv["type"] = global_var_type_names[type];
if (type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {
@@ -117,17 +118,17 @@ protected:
}
bool _get(const StringName &p_name, Variant &r_ret) const {
- r_ret = RS::get_singleton()->global_shader_uniform_get(p_name);
+ r_ret = RS::get_singleton()->global_shader_parameter_get(p_name);
return r_ret.get_type() != Variant::NIL;
}
void _get_property_list(List<PropertyInfo> *p_list) const {
Vector<StringName> variables;
- variables = RS::get_singleton()->global_shader_uniform_get_list();
+ variables = RS::get_singleton()->global_shader_parameter_get_list();
for (int i = 0; i < variables.size(); i++) {
PropertyInfo pinfo;
pinfo.name = variables[i];
- switch (RS::get_singleton()->global_shader_uniform_get_type(variables[i])) {
+ switch (RS::get_singleton()->global_shader_parameter_get_type(variables[i])) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
pinfo.type = Variant::BOOL;
} break;
@@ -241,7 +242,7 @@ public:
}
};
-static Variant create_var(RS::GlobalShaderUniformType p_type) {
+static Variant create_var(RS::GlobalShaderParameterType p_type) {
switch (p_type) {
case RS::GLOBAL_VAR_TYPE_BOOL: {
return false;
@@ -380,8 +381,8 @@ void ShaderGlobalsEditor::_variable_added() {
return;
}
- if (RenderingServer::get_singleton()->global_shader_uniform_get(var).get_type() != Variant::NIL) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader uniform '%s' already exists'"), var));
+ if (RenderingServer::get_singleton()->global_shader_parameter_get(var).get_type() != Variant::NIL) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists'"), var));
return;
}
@@ -393,13 +394,13 @@ void ShaderGlobalsEditor::_variable_added() {
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
- Variant value = create_var(RS::GlobalShaderUniformType(variable_type->get_selected()));
+ Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected()));
- undo_redo->create_action(TTR("Add Shader Global Uniform"));
- undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_add", var, RS::GlobalShaderUniformType(variable_type->get_selected()), value);
- undo_redo->add_undo_method(RS::get_singleton(), "global_shader_uniform_remove", var);
+ undo_redo->create_action(TTR("Add Shader Global Parameter"));
+ undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_add", var, RS::GlobalShaderParameterType(variable_type->get_selected()), value);
+ undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_remove", var);
Dictionary gv;
gv["type"] = global_var_type_names[variable_type->get_selected()];
gv["value"] = value;
@@ -412,11 +413,11 @@ void ShaderGlobalsEditor::_variable_added() {
}
void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
- undo_redo->create_action(TTR("Add Shader Global Uniform"));
- undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_remove", p_variable);
- undo_redo->add_undo_method(RS::get_singleton(), "global_shader_uniform_add", p_variable, RS::get_singleton()->global_shader_uniform_get_type(p_variable), RS::get_singleton()->global_shader_uniform_get(p_variable));
+ undo_redo->create_action(TTR("Add Shader Global Parameter"));
+ undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable);
+ undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_add", p_variable, RS::get_singleton()->global_shader_parameter_get_type(p_variable), RS::get_singleton()->global_shader_parameter_get(p_variable));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, Variant());
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, ProjectSettings::get_singleton()->get("shader_globals/" + p_variable));
diff --git a/editor/shader_globals_editor.h b/editor/shader_globals_editor.h
index d29052eaee..1e2f1dd828 100644
--- a/editor/shader_globals_editor.h
+++ b/editor/shader_globals_editor.h
@@ -31,7 +31,6 @@
#ifndef SHADER_GLOBALS_EDITOR_H
#define SHADER_GLOBALS_EDITOR_H
-#include "core/object/undo_redo.h"
#include "editor/editor_autoload_settings.h"
#include "editor/editor_data.h"
#include "editor/editor_plugin_settings.h"
diff --git a/editor/translations/extract.py b/editor/translations/extract.py
index 7f3da400e7..07026baee2 100755
--- a/editor/translations/extract.py
+++ b/editor/translations/extract.py
@@ -139,7 +139,7 @@ theme_property_patterns = {
}
-# See String::camelcase_to_underscore().
+# See String::_camelcase_to_underscore().
capitalize_re = re.compile(r"(?<=\D)(?=\d)|(?<=\d)(?=\D([a-z]|\d))")