summaryrefslogtreecommitdiffstats
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/action_map_editor.cpp2
-rw-r--r--editor/add_metadata_dialog.cpp2
-rw-r--r--editor/animation_track_editor.cpp123
-rw-r--r--editor/animation_track_editor.h9
-rw-r--r--editor/code_editor.cpp12
-rw-r--r--editor/connections_dialog.cpp10
-rw-r--r--editor/create_dialog.cpp4
-rw-r--r--editor/debugger/editor_debugger_inspector.h2
-rw-r--r--editor/debugger/editor_debugger_node.cpp16
-rw-r--r--editor/debugger/editor_debugger_node.h8
-rw-r--r--editor/debugger/editor_debugger_tree.cpp38
-rw-r--r--editor/debugger/editor_debugger_tree.h3
-rw-r--r--editor/debugger/editor_profiler.cpp8
-rw-r--r--editor/debugger/editor_visual_profiler.cpp12
-rw-r--r--editor/debugger/script_editor_debugger.cpp121
-rw-r--r--editor/debugger/script_editor_debugger.h2
-rw-r--r--editor/editor_asset_installer.cpp8
-rw-r--r--editor/editor_audio_buses.cpp32
-rw-r--r--editor/editor_autoload_settings.cpp6
-rw-r--r--editor/editor_data.cpp2
-rw-r--r--editor/editor_dock_manager.cpp14
-rw-r--r--editor/editor_feature_profile.cpp4
-rw-r--r--editor/editor_feature_profile.h1
-rw-r--r--editor/editor_file_system.cpp189
-rw-r--r--editor/editor_file_system.h19
-rw-r--r--editor/editor_help.cpp8
-rw-r--r--editor/editor_help_search.cpp8
-rw-r--r--editor/editor_inspector.cpp426
-rw-r--r--editor/editor_inspector.h40
-rw-r--r--editor/editor_interface.cpp26
-rw-r--r--editor/editor_interface.h3
-rw-r--r--editor/editor_log.cpp22
-rw-r--r--editor/editor_main_screen.cpp6
-rw-r--r--editor/editor_main_screen.h1
-rw-r--r--editor/editor_node.cpp27
-rw-r--r--editor/editor_node.h4
-rw-r--r--editor/editor_properties.cpp72
-rw-r--r--editor/editor_properties.h4
-rw-r--r--editor/editor_properties_array_dict.cpp24
-rw-r--r--editor/editor_property_name_processor.cpp3
-rw-r--r--editor/editor_resource_picker.cpp31
-rw-r--r--editor/editor_resource_picker.h5
-rw-r--r--editor/editor_run.cpp5
-rw-r--r--editor/editor_run_native.cpp2
-rw-r--r--editor/editor_settings.cpp53
-rw-r--r--editor/editor_settings.h3
-rw-r--r--editor/editor_settings_dialog.cpp2
-rw-r--r--editor/export/codesign.cpp8
-rw-r--r--editor/export/codesign.h10
-rw-r--r--editor/export/editor_export_platform.cpp111
-rw-r--r--editor/export/editor_export_platform.h8
-rw-r--r--editor/export/editor_export_platform_pc.cpp2
-rw-r--r--editor/export/export_template_manager.cpp2
-rw-r--r--editor/export/project_export.cpp12
-rw-r--r--editor/export/project_export.h2
-rw-r--r--editor/fbx_importer_manager.cpp2
-rw-r--r--editor/filesystem_dock.cpp162
-rw-r--r--editor/filesystem_dock.h5
-rw-r--r--editor/group_settings_editor.cpp2
-rw-r--r--editor/groups_editor.cpp2
-rw-r--r--editor/gui/editor_bottom_panel.cpp44
-rw-r--r--editor/gui/editor_bottom_panel.h7
-rw-r--r--editor/gui/editor_file_dialog.cpp32
-rw-r--r--editor/gui/editor_quick_open_dialog.cpp593
-rw-r--r--editor/gui/editor_quick_open_dialog.h78
-rw-r--r--editor/gui/editor_run_bar.cpp14
-rw-r--r--editor/gui/editor_scene_tabs.cpp2
-rw-r--r--editor/gui/editor_spin_slider.cpp8
-rw-r--r--editor/gui/editor_spin_slider.h2
-rw-r--r--editor/gui/editor_toaster.cpp80
-rw-r--r--editor/gui/editor_toaster.h8
-rw-r--r--editor/gui/editor_zoom_widget.cpp4
-rw-r--r--editor/gui/scene_tree_editor.cpp49
-rw-r--r--editor/gui/scene_tree_editor.h2
-rw-r--r--editor/icons/2DNodes.svg1
-rw-r--r--editor/icons/Camera.svg1
-rw-r--r--editor/icons/FPS.svg1
-rw-r--r--editor/icons/FlipWinding.svg1
-rw-r--r--editor/icons/Game.svg1
-rw-r--r--editor/icons/LookAtModifier3D.svg1
-rw-r--r--editor/icons/MaterialPreviewQuad.svg1
-rw-r--r--editor/icons/NextFrame.svg1
-rw-r--r--editor/icons/Unfavorite.svg1
-rw-r--r--editor/import/3d/collada.h2
-rw-r--r--editor/import/3d/editor_import_collada.cpp2
-rw-r--r--editor/import/3d/resource_importer_obj.cpp85
-rw-r--r--editor/import/3d/resource_importer_obj.h5
-rw-r--r--editor/import/3d/resource_importer_scene.cpp23
-rw-r--r--editor/import/3d/resource_importer_scene.h4
-rw-r--r--editor/import/3d/scene_import_settings.cpp29
-rw-r--r--editor/import/audio_stream_import_settings.cpp22
-rw-r--r--editor/import/dynamic_font_import_settings.cpp2
-rw-r--r--editor/import/editor_import_plugin.cpp2
-rw-r--r--editor/import/editor_import_plugin.h2
-rw-r--r--editor/import/resource_importer_bitmask.cpp2
-rw-r--r--editor/import/resource_importer_bitmask.h4
-rw-r--r--editor/import/resource_importer_bmfont.cpp2
-rw-r--r--editor/import/resource_importer_bmfont.h4
-rw-r--r--editor/import/resource_importer_csv_translation.cpp5
-rw-r--r--editor/import/resource_importer_csv_translation.h4
-rw-r--r--editor/import/resource_importer_dynamic_font.cpp2
-rw-r--r--editor/import/resource_importer_dynamic_font.h4
-rw-r--r--editor/import/resource_importer_image.cpp2
-rw-r--r--editor/import/resource_importer_image.h4
-rw-r--r--editor/import/resource_importer_imagefont.cpp2
-rw-r--r--editor/import/resource_importer_imagefont.h4
-rw-r--r--editor/import/resource_importer_layered_texture.cpp2
-rw-r--r--editor/import/resource_importer_layered_texture.h4
-rw-r--r--editor/import/resource_importer_shader_file.cpp2
-rw-r--r--editor/import/resource_importer_shader_file.h4
-rw-r--r--editor/import/resource_importer_texture.cpp2
-rw-r--r--editor/import/resource_importer_texture.h4
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp2
-rw-r--r--editor/import/resource_importer_texture_atlas.h4
-rw-r--r--editor/import/resource_importer_wav.cpp21
-rw-r--r--editor/import/resource_importer_wav.h4
-rw-r--r--editor/import_dock.cpp17
-rw-r--r--editor/inspector_dock.cpp31
-rw-r--r--editor/inspector_dock.h2
-rw-r--r--editor/node_dock.cpp4
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp6
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp12
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp16
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp45
-rw-r--r--editor/plugins/animation_library_editor.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp42
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp10
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp6
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp12
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp8
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp99
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h4
-rw-r--r--editor/plugins/control_editor_plugin.cpp59
-rw-r--r--editor/plugins/control_editor_plugin.h2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp2
-rw-r--r--editor/plugins/font_config_plugin.cpp12
-rw-r--r--editor/plugins/game_view_plugin.cpp487
-rw-r--r--editor/plugins/game_view_plugin.h152
-rw-r--r--editor/plugins/gdextension_export_plugin.h45
-rw-r--r--editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp72
-rw-r--r--editor/plugins/gizmos/gizmo_3d_helper.cpp95
-rw-r--r--editor/plugins/gizmos/gizmo_3d_helper.h5
-rw-r--r--editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp2
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp2
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp4
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/input_event_editor_plugin.cpp2
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp2
-rw-r--r--editor/plugins/material_editor_plugin.cpp101
-rw-r--r--editor/plugins/material_editor_plugin.h7
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp4
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp46
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.h2
-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_obstacle_3d_editor_plugin.cpp929
-rw-r--r--editor/plugins/navigation_obstacle_3d_editor_plugin.h110
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.cpp8
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp148
-rw-r--r--editor/plugins/node_3d_editor_plugin.h10
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/packed_scene_editor_plugin.cpp2
-rw-r--r--editor/plugins/parallax_background_editor_plugin.cpp2
-rw-r--r--editor/plugins/particle_process_material_editor_plugin.cpp2
-rw-r--r--editor/plugins/particles_editor_plugin.cpp2
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp16
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp66
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h4
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp2
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp6
-rw-r--r--editor/plugins/script_editor_plugin.cpp70
-rw-r--r--editor/plugins/script_editor_plugin.h18
-rw-r--r--editor/plugins/shader_file_editor_plugin.cpp4
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp24
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h8
-rw-r--r--editor/plugins/skeleton_ik_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp58
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp8
-rw-r--r--editor/plugins/theme_editor_plugin.cpp88
-rw-r--r--editor/plugins/theme_editor_preview.cpp4
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp6
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h8
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp25
-rw-r--r--editor/plugins/tiles/tile_data_editors.h6
-rw-r--r--editor/plugins/tiles/tile_map_layer_editor.cpp56
-rw-r--r--editor/plugins/tiles/tile_map_layer_editor.h4
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp16
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h8
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp8
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp4
-rw-r--r--editor/plugins/tool_button_editor_plugin.cpp2
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp20
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp35
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h6
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp18
-rw-r--r--editor/project_manager.cpp36
-rw-r--r--editor/project_manager/project_dialog.cpp6
-rw-r--r--editor/project_manager/project_list.cpp8
-rw-r--r--editor/project_manager/project_tag.cpp2
-rw-r--r--editor/project_settings_editor.cpp6
-rw-r--r--editor/rename_dialog.h2
-rw-r--r--editor/scene_create_dialog.cpp12
-rw-r--r--editor/scene_tree_dock.cpp167
-rw-r--r--editor/scene_tree_dock.h1
-rw-r--r--editor/script_create_dialog.cpp6
-rw-r--r--editor/shader_create_dialog.cpp2
-rw-r--r--editor/shader_globals_editor.cpp2
-rw-r--r--editor/surface_upgrade_tool.h4
-rw-r--r--editor/themes/editor_color_map.cpp2
-rw-r--r--editor/themes/editor_color_map.h4
-rw-r--r--editor/themes/editor_theme_manager.cpp52
-rw-r--r--editor/themes/editor_theme_manager.h1
-rw-r--r--editor/window_wrapper.cpp9
-rw-r--r--editor/window_wrapper.h1
222 files changed, 4436 insertions, 2121 deletions
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 0d89f37dd2..cf5b18ce3c 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -358,7 +358,7 @@ void ActionMapEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
action_list_search->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
if (!actions_cache.is_empty()) {
update_action_list();
}
diff --git a/editor/add_metadata_dialog.cpp b/editor/add_metadata_dialog.cpp
index 0a070e37b6..66a7b820f5 100644
--- a/editor/add_metadata_dialog.cpp
+++ b/editor/add_metadata_dialog.cpp
@@ -64,7 +64,6 @@ AddMetadataDialog::AddMetadataDialog() {
}
void AddMetadataDialog::_complete_init(const StringName &p_title) {
- add_meta_name->grab_focus();
add_meta_name->set_text("");
validation_panel->update();
@@ -90,6 +89,7 @@ void AddMetadataDialog::open(const StringName p_title, List<StringName> &p_exist
this->_existing_metas = p_existing_metas;
_complete_init(p_title);
popup_centered();
+ add_meta_name->grab_focus();
}
StringName AddMetadataDialog::get_meta_name() {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 741d127ea2..076ba6d905 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -63,7 +63,6 @@
constexpr double FPS_DECIMAL = 1.0;
constexpr double SECOND_DECIMAL = 0.0001;
-constexpr double FPS_STEP_FRACTION = 0.0625;
void AnimationTrackKeyEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
@@ -1440,8 +1439,8 @@ void AnimationTimelineEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- add_track->set_icon(get_editor_theme_icon(SNAME("Add")));
- loop->set_icon(get_editor_theme_icon(SNAME("Loop")));
+ add_track->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ loop->set_button_icon(get_editor_theme_icon(SNAME("Loop")));
time_icon->set_texture(get_editor_theme_icon(SNAME("Time")));
add_track->get_popup()->clear();
@@ -1818,15 +1817,15 @@ void AnimationTimelineEdit::update_values() {
switch (animation->get_loop_mode()) {
case Animation::LOOP_NONE: {
- loop->set_icon(get_editor_theme_icon(SNAME("Loop")));
+ loop->set_button_icon(get_editor_theme_icon(SNAME("Loop")));
loop->set_pressed(false);
} break;
case Animation::LOOP_LINEAR: {
- loop->set_icon(get_editor_theme_icon(SNAME("Loop")));
+ loop->set_button_icon(get_editor_theme_icon(SNAME("Loop")));
loop->set_pressed(true);
} break;
case Animation::LOOP_PINGPONG: {
- loop->set_icon(get_editor_theme_icon(SNAME("PingPongLoop")));
+ loop->set_button_icon(get_editor_theme_icon(SNAME("PingPongLoop")));
loop->set_pressed(true);
} break;
default:
@@ -3313,7 +3312,7 @@ Variant AnimationTrackEdit::get_drag_data(const Point2 &p_point) {
Button *tb = memnew(Button);
tb->set_flat(true);
tb->set_text(path_cache);
- tb->set_icon(icon_cache);
+ tb->set_button_icon(icon_cache);
tb->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
tb->add_theme_constant_override("icon_max_width", get_theme_constant("class_icon_size", EditorStringName(Editor)));
set_drag_preview(tb);
@@ -3776,6 +3775,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
step->set_read_only(false);
snap_keys->set_disabled(false);
snap_timeline->set_disabled(false);
+ fps_compat->set_disabled(false);
snap_mode->set_disabled(false);
auto_fit->set_disabled(false);
auto_fit_bezier->set_disabled(false);
@@ -3798,6 +3798,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re
step->set_read_only(true);
snap_keys->set_disabled(true);
snap_timeline->set_disabled(true);
+ fps_compat->set_disabled(true);
snap_mode->set_disabled(true);
bezier_edit_icon->set_disabled(true);
auto_fit->set_disabled(true);
@@ -5029,7 +5030,12 @@ void AnimationTrackEditor::_snap_mode_changed(int p_mode) {
}
marker_edit->set_use_fps(use_fps);
// To ensure that the conversion results are consistent between serialization and load, the value is snapped with 0.0625 to be a rational number when FPS mode is used.
- step->set_step(use_fps ? FPS_STEP_FRACTION : SECOND_DECIMAL);
+ step->set_step(use_fps ? FPS_DECIMAL : SECOND_DECIMAL);
+ if (use_fps) {
+ fps_compat->hide();
+ } else {
+ fps_compat->show();
+ }
_update_step_spinbox();
}
@@ -5045,7 +5051,6 @@ void AnimationTrackEditor::_update_step_spinbox() {
} else {
step->set_value(1.0 / animation->get_step());
}
-
} else {
step->set_value(animation->get_step());
}
@@ -5054,6 +5059,20 @@ void AnimationTrackEditor::_update_step_spinbox() {
_update_snap_unit();
}
+void AnimationTrackEditor::_update_fps_compat_mode(bool p_enabled) {
+ _update_snap_unit();
+}
+
+void AnimationTrackEditor::_update_nearest_fps_label() {
+ bool is_fps_invalid = nearest_fps == 0;
+ if (is_fps_invalid) {
+ nearest_fps_label->hide();
+ } else {
+ nearest_fps_label->show();
+ nearest_fps_label->set_text("Nearest FPS: " + itos(nearest_fps));
+ }
+}
+
void AnimationTrackEditor::_animation_update() {
timeline->queue_redraw();
timeline->update_values();
@@ -5112,18 +5131,19 @@ void AnimationTrackEditor::_notification(int p_what) {
}
case NOTIFICATION_THEME_CHANGED: {
zoom_icon->set_texture(get_editor_theme_icon(SNAME("Zoom")));
- bezier_edit_icon->set_icon(get_editor_theme_icon(SNAME("EditBezier")));
- snap_timeline->set_icon(get_editor_theme_icon(SNAME("SnapTimeline")));
- snap_keys->set_icon(get_editor_theme_icon(SNAME("SnapKeys")));
- view_group->set_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup")));
- selected_filter->set_icon(get_editor_theme_icon(SNAME("AnimationFilter")));
- imported_anim_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
- dummy_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
- inactive_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
+ bezier_edit_icon->set_button_icon(get_editor_theme_icon(SNAME("EditBezier")));
+ snap_timeline->set_button_icon(get_editor_theme_icon(SNAME("SnapTimeline")));
+ snap_keys->set_button_icon(get_editor_theme_icon(SNAME("SnapKeys")));
+ fps_compat->set_button_icon(get_editor_theme_icon(SNAME("FPS")));
+ view_group->set_button_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup")));
+ selected_filter->set_button_icon(get_editor_theme_icon(SNAME("AnimationFilter")));
+ imported_anim_warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
+ dummy_player_warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
+ inactive_player_warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_editor_theme_icon(SNAME("Reload")));
- auto_fit->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFit")));
- auto_fit_bezier->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFitBezier")));
+ auto_fit->set_button_icon(get_editor_theme_icon(SNAME("AnimationAutoFit")));
+ auto_fit_bezier->set_button_icon(get_editor_theme_icon(SNAME("AnimationAutoFitBezier")));
const int timeline_separation = get_theme_constant(SNAME("timeline_v_separation"), SNAME("AnimationTrackEditor"));
timeline_vbox->add_theme_constant_override("separation", timeline_separation);
@@ -5160,9 +5180,8 @@ void AnimationTrackEditor::_update_step(double p_new_step) {
double step_value = p_new_step;
if (timeline->is_using_fps()) {
if (step_value != 0.0) {
- // step_value must also be less than or equal to 1000 to ensure that no error accumulates due to interactions with retrieving values from inner range.
+ // A step_value should be less than or equal to 1000 to ensure that no error accumulates due to interactions with retrieving values from inner range.
step_value = 1.0 / MIN(1000.0, p_new_step);
- ;
}
timeline->queue_redraw();
}
@@ -5297,6 +5316,28 @@ void AnimationTrackEditor::_add_track(int p_type) {
return;
}
adding_track_type = p_type;
+ Vector<StringName> valid_types;
+ switch (adding_track_type) {
+ case Animation::TYPE_BLEND_SHAPE: {
+ // Blend Shape is a property of MeshInstance3D.
+ valid_types.push_back(SNAME("MeshInstance3D"));
+ } break;
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D: {
+ // 3D Properties come from nodes inheriting Node3D.
+ valid_types.push_back(SNAME("Node3D"));
+ } break;
+ case Animation::TYPE_AUDIO: {
+ valid_types.push_back(SNAME("AudioStreamPlayer"));
+ valid_types.push_back(SNAME("AudioStreamPlayer2D"));
+ valid_types.push_back(SNAME("AudioStreamPlayer3D"));
+ } break;
+ case Animation::TYPE_ANIMATION: {
+ valid_types.push_back(SNAME("AnimationPlayer"));
+ } break;
+ }
+ pick_track->set_valid_types(valid_types);
pick_track->popup_scenetree_dialog(nullptr, root_node);
pick_track->get_filter_line_edit()->clear();
pick_track->get_filter_line_edit()->grab_focus();
@@ -6337,8 +6378,9 @@ bool AnimationTrackEditor::_is_track_compatible(int p_target_track_idx, Variant:
}
if (path_valid) {
- if (is_source_bezier)
+ if (is_source_bezier) {
p_source_value_type = Variant::FLOAT;
+ }
return property_type == p_source_value_type;
} else {
if (animation->track_get_key_count(p_target_track_idx) > 0) {
@@ -7279,7 +7321,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
void AnimationTrackEditor::_view_group_toggle() {
_update_tracks();
- view_group->set_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup")));
+ view_group->set_button_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup")));
bezier_edit->set_filtered(selected_filter->is_pressed());
}
@@ -7313,19 +7355,30 @@ void AnimationTrackEditor::_selection_changed() {
}
void AnimationTrackEditor::_update_snap_unit() {
+ nearest_fps = 0;
+
if (step->get_value() <= 0) {
snap_unit = 0;
+ _update_nearest_fps_label();
return; // Avoid zero div.
}
if (timeline->is_using_fps()) {
+ _clear_selection(true); // Needs to recreate a spinbox of the KeyEdit.
snap_unit = 1.0 / step->get_value();
} else {
- double integer;
- double fraction = Math::modf(step->get_value(), &integer);
- fraction = 1.0 / Math::round(1.0 / fraction);
- snap_unit = integer + fraction;
+ if (fps_compat->is_pressed()) {
+ snap_unit = CLAMP(step->get_value(), 0.0, 1.0);
+ if (!Math::is_zero_approx(snap_unit)) {
+ real_t fps = Math::round(1.0 / snap_unit);
+ nearest_fps = int(fps);
+ snap_unit = 1.0 / fps;
+ }
+ } else {
+ snap_unit = step->get_value();
+ }
}
+ _update_nearest_fps_label();
}
float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
@@ -7346,6 +7399,10 @@ float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
return p_value;
}
+float AnimationTrackEditor::get_snap_unit() {
+ return snap_unit;
+}
+
void AnimationTrackEditor::_show_imported_anim_warning() {
// It looks terrible on a single line but the TTR extractor doesn't support line breaks yet.
EditorNode::get_singleton()->show_warning(
@@ -7599,6 +7656,18 @@ AnimationTrackEditor::AnimationTrackEditor() {
snap_keys->set_pressed(true);
snap_keys->set_tooltip_text(TTR("Apply snapping to selected key(s)."));
+ fps_compat = memnew(Button);
+ fps_compat->set_flat(true);
+ bottom_hb->add_child(fps_compat);
+ fps_compat->set_disabled(true);
+ fps_compat->set_toggle_mode(true);
+ fps_compat->set_pressed(true);
+ fps_compat->set_tooltip_text(TTR("Apply snapping to the nearest integer FPS."));
+ fps_compat->connect(SceneStringName(toggled), callable_mp(this, &AnimationTrackEditor::_update_fps_compat_mode));
+
+ nearest_fps_label = memnew(Label);
+ bottom_hb->add_child(nearest_fps_label);
+
step = memnew(EditorSpinSlider);
step->set_min(0);
step->set_max(1000000);
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 0da474afd4..e7271f1941 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -600,6 +600,8 @@ class AnimationTrackEditor : public VBoxContainer {
AnimationMarkerEdit *marker_edit = nullptr;
HSlider *zoom = nullptr;
EditorSpinSlider *step = nullptr;
+ Button *fps_compat = nullptr;
+ Label *nearest_fps_label = nullptr;
TextureRect *zoom_icon = nullptr;
Button *snap_keys = nullptr;
Button *snap_timeline = nullptr;
@@ -637,6 +639,8 @@ class AnimationTrackEditor : public VBoxContainer {
void _track_grab_focus(int p_track);
void _update_scroll(double);
+ void _update_nearest_fps_label();
+ void _update_fps_compat_mode(bool p_enabled);
void _update_step(double p_new_step);
void _update_length(double p_new_len);
void _dropped_track(int p_from_track, int p_to_track);
@@ -716,7 +720,7 @@ class AnimationTrackEditor : public VBoxContainer {
struct SelectedKey {
int track = 0;
int key = 0;
- bool operator<(const SelectedKey &p_key) const { return track == p_key.track ? key < p_key.key : track < p_key.track; };
+ bool operator<(const SelectedKey &p_key) const { return track == p_key.track ? key < p_key.key : track < p_key.track; }
};
struct KeyInfo {
@@ -853,6 +857,8 @@ class AnimationTrackEditor : public VBoxContainer {
void _pick_track_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates);
double snap_unit;
+ bool fps_compatible = true;
+ int nearest_fps = 0;
void _update_snap_unit();
protected:
@@ -935,6 +941,7 @@ public:
bool can_add_reset_key() const;
float get_moving_selection_offset() const;
float snap_time(float p_value, bool p_relative = false);
+ float get_snap_unit();
bool is_grouping_tracks();
PackedStringArray get_selected_section() const;
bool is_marker_selected(const StringName &p_marker) const;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 88a32b1a6d..05eeef4fc9 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -104,8 +104,8 @@ void FindReplaceBar::_notification(int p_what) {
[[fallthrough]];
}
case NOTIFICATION_READY: {
- find_prev->set_icon(get_editor_theme_icon(SNAME("MoveUp")));
- find_next->set_icon(get_editor_theme_icon(SNAME("MoveDown")));
+ find_prev->set_button_icon(get_editor_theme_icon(SNAME("MoveUp")));
+ find_next->set_button_icon(get_editor_theme_icon(SNAME("MoveDown")));
hide_button->set_texture_normal(get_editor_theme_icon(SNAME("Close")));
hide_button->set_texture_hover(get_editor_theme_icon(SNAME("Close")));
hide_button->set_texture_pressed(get_editor_theme_icon(SNAME("Close")));
@@ -549,7 +549,7 @@ void FindReplaceBar::_update_toggle_replace_button(bool p_replace_visible) {
String shortcut = ED_GET_SHORTCUT(p_replace_visible ? "script_text_editor/find" : "script_text_editor/replace")->get_as_text();
toggle_replace_button->set_tooltip_text(vformat("%s (%s)", tooltip, shortcut));
StringName rtl_compliant_arrow = is_layout_rtl() ? SNAME("GuiTreeArrowLeft") : SNAME("GuiTreeArrowRight");
- toggle_replace_button->set_icon(get_editor_theme_icon(p_replace_visible ? SNAME("GuiTreeArrowDown") : rtl_compliant_arrow));
+ toggle_replace_button->set_button_icon(get_editor_theme_icon(p_replace_visible ? SNAME("GuiTreeArrowDown") : rtl_compliant_arrow));
}
void FindReplaceBar::_show_search(bool p_with_replace, bool p_show_only) {
@@ -1493,8 +1493,8 @@ void CodeTextEditor::goto_error() {
void CodeTextEditor::_update_text_editor_theme() {
emit_signal(SNAME("load_theme_settings"));
- error_button->set_icon(get_editor_theme_icon(SNAME("StatusError")));
- warning_button->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
+ error_button->set_button_icon(get_editor_theme_icon(SNAME("StatusError")));
+ warning_button->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
Ref<Font> status_bar_font = get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts));
int status_bar_font_size = get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts));
@@ -1771,7 +1771,7 @@ void CodeTextEditor::show_toggle_scripts_button() {
void CodeTextEditor::update_toggle_scripts_button() {
ERR_FAIL_NULL(toggle_scripts_list);
bool forward = toggle_scripts_list->is_visible() == is_layout_rtl();
- toggle_scripts_button->set_icon(get_editor_theme_icon(forward ? SNAME("Forward") : SNAME("Back")));
+ toggle_scripts_button->set_button_icon(get_editor_theme_icon(forward ? SNAME("Forward") : SNAME("Back")));
toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
}
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 1c269a62c5..b114977c3b 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -488,7 +488,7 @@ void ConnectDialog::_notification(int p_what) {
}
method_search->set_right_icon(get_editor_theme_icon("Search"));
- open_method_tree->set_icon(get_editor_theme_icon("Edit"));
+ open_method_tree->set_button_icon(get_editor_theme_icon("Edit"));
} break;
}
}
@@ -1079,17 +1079,17 @@ void ConnectionsDock::_tree_item_selected() {
TreeItem *item = tree->get_selected();
if (item && _get_item_type(*item) == TREE_ITEM_TYPE_SIGNAL) {
connect_button->set_text(TTR("Connect..."));
- connect_button->set_icon(get_editor_theme_icon(SNAME("Instance")));
+ connect_button->set_button_icon(get_editor_theme_icon(SNAME("Instance")));
connect_button->set_disabled(false);
} else if (item && _get_item_type(*item) == TREE_ITEM_TYPE_CONNECTION) {
connect_button->set_text(TTR("Disconnect"));
- connect_button->set_icon(get_editor_theme_icon(SNAME("Unlinked")));
+ connect_button->set_button_icon(get_editor_theme_icon(SNAME("Unlinked")));
Object::Connection connection = item->get_metadata(0);
connect_button->set_disabled(_is_connection_inherited(connection));
} else {
connect_button->set_text(TTR("Connect..."));
- connect_button->set_icon(get_editor_theme_icon(SNAME("Instance")));
+ connect_button->set_button_icon(get_editor_theme_icon(SNAME("Instance")));
connect_button->set_disabled(true);
}
}
@@ -1586,7 +1586,7 @@ void ConnectionsDock::update_tree() {
}
connect_button->set_text(TTR("Connect..."));
- connect_button->set_icon(get_editor_theme_icon(SNAME("Instance")));
+ connect_button->set_button_icon(get_editor_theme_icon(SNAME("Instance")));
connect_button->set_disabled(true);
}
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 330ac3b437..78dc772d9e 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -468,7 +468,7 @@ void CreateDialog::_notification(int p_what) {
recent->set_fixed_icon_size(Size2(icon_width, icon_width));
search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- favorite->set_icon(get_editor_theme_icon(SNAME("Favorites")));
+ favorite->set_button_icon(get_editor_theme_icon(SNAME("Favorites")));
} break;
}
}
@@ -613,7 +613,7 @@ Variant CreateDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
Button *tb = memnew(Button);
tb->set_flat(true);
- tb->set_icon(ti->get_icon(0));
+ tb->set_button_icon(ti->get_icon(0));
tb->set_text(ti->get_text(0));
tb->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
favorites->set_drag_preview(tb);
diff --git a/editor/debugger/editor_debugger_inspector.h b/editor/debugger/editor_debugger_inspector.h
index fac9525943..860c2bf582 100644
--- a/editor/debugger/editor_debugger_inspector.h
+++ b/editor/debugger/editor_debugger_inspector.h
@@ -48,7 +48,7 @@ public:
List<PropertyInfo> prop_list;
HashMap<StringName, Variant> prop_values;
- ObjectID get_remote_object_id() { return remote_object_id; };
+ ObjectID get_remote_object_id() { return remote_object_id; }
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 b4265f9fc0..0f948b4ed5 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -105,6 +105,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id));
node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked).bind(id));
+ node->connect("remote_tree_select_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_select_requested).bind(id));
node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id));
node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated).bind(id));
node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id));
@@ -417,18 +418,18 @@ void EditorDebuggerNode::_update_errors() {
if (error_count == 0 && warning_count == 0) {
debugger_button->set_text(TTR("Debugger"));
debugger_button->remove_theme_color_override(SceneStringName(font_color));
- debugger_button->set_icon(Ref<Texture2D>());
+ debugger_button->set_button_icon(Ref<Texture2D>());
} else {
debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count + warning_count) + ")");
if (error_count >= 1 && warning_count >= 1) {
- debugger_button->set_icon(get_editor_theme_icon(SNAME("ErrorWarning")));
+ debugger_button->set_button_icon(get_editor_theme_icon(SNAME("ErrorWarning")));
// Use error color to represent the highest level of severity reported.
debugger_button->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
} else if (error_count >= 1) {
- debugger_button->set_icon(get_editor_theme_icon(SNAME("Error")));
+ debugger_button->set_button_icon(get_editor_theme_icon(SNAME("Error")));
debugger_button->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
} else {
- debugger_button->set_icon(get_editor_theme_icon(SNAME("Warning")));
+ debugger_button->set_button_icon(get_editor_theme_icon(SNAME("Warning")));
debugger_button->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
}
}
@@ -637,6 +638,13 @@ void EditorDebuggerNode::request_remote_tree() {
get_current_debugger()->request_remote_tree();
}
+void EditorDebuggerNode::_remote_tree_select_requested(ObjectID p_id, int p_debugger) {
+ if (p_debugger != tabs->get_current_tab()) {
+ return;
+ }
+ remote_scene_tree->select_node(p_id);
+}
+
void EditorDebuggerNode::_remote_tree_updated(int p_debugger) {
if (p_debugger != tabs->get_current_tab()) {
return;
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index 12e097f652..12c0d30c42 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -51,11 +51,8 @@ class EditorDebuggerNode : public MarginContainer {
public:
enum CameraOverride {
OVERRIDE_NONE,
- OVERRIDE_2D,
- OVERRIDE_3D_1, // 3D Viewport 1
- OVERRIDE_3D_2, // 3D Viewport 2
- OVERRIDE_3D_3, // 3D Viewport 3
- OVERRIDE_3D_4 // 3D Viewport 4
+ OVERRIDE_INGAME,
+ OVERRIDE_EDITORS,
};
private:
@@ -132,6 +129,7 @@ protected:
void _debugger_stopped(int p_id);
void _debugger_wants_stop(int p_id);
void _debugger_changed(int p_tab);
+ void _remote_tree_select_requested(ObjectID p_id, int p_debugger);
void _remote_tree_updated(int p_debugger);
void _remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _remote_object_updated(ObjectID p_id, int p_debugger);
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index a900842651..4d67800e6e 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -30,6 +30,7 @@
#include "editor_debugger_tree.h"
+#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
#include "editor/gui/editor_file_dialog.h"
@@ -148,7 +149,8 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
updating_scene_tree = true;
const String last_path = get_selected_path();
const String filter = SceneTreeDock::get_singleton()->get_filter();
- bool filter_changed = filter != last_filter;
+ bool should_scroll = scrolling_to_item || filter != last_filter;
+ scrolling_to_item = false;
TreeItem *scroll_item = nullptr;
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
@@ -185,8 +187,18 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
// Select previously selected node.
if (debugger_id == p_debugger) { // Can use remote id.
if (node.id == inspected_object_id) {
+ if (selection_uncollapse_all) {
+ selection_uncollapse_all = false;
+
+ // Temporarily set to `false`, to allow caching the unfolds.
+ updating_scene_tree = false;
+ item->uncollapse_tree();
+ updating_scene_tree = true;
+ }
+
item->select(0);
- if (filter_changed) {
+
+ if (should_scroll) {
scroll_item = item;
}
}
@@ -194,7 +206,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
if (last_path == _get_path(item)) {
updating_scene_tree = false; // Force emission of new selection.
item->select(0);
- if (filter_changed) {
+ if (should_scroll) {
scroll_item = item;
}
updating_scene_tree = true;
@@ -258,14 +270,30 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
}
}
}
- debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree
+
+ debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
if (scroll_item) {
- callable_mp((Tree *)this, &Tree::scroll_to_item).call_deferred(scroll_item, false);
+ scroll_to_item(scroll_item, false);
}
last_filter = filter;
updating_scene_tree = false;
}
+void EditorDebuggerTree::select_node(ObjectID p_id) {
+ // Manually select, as the tree control may be out-of-date for some reason (e.g. not shown yet).
+ selection_uncollapse_all = true;
+ inspected_object_id = uint64_t(p_id);
+ scrolling_to_item = true;
+ emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
+
+ if (!updating_scene_tree) {
+ // Request a tree refresh.
+ EditorDebuggerNode::get_singleton()->request_remote_tree();
+ }
+ // Set the value immediately, so no update flooding happens and causes a crash.
+ updating_scene_tree = true;
+}
+
Variant EditorDebuggerTree::get_drag_data(const Point2 &p_point) {
if (get_button_id_at_position(p_point) != -1) {
return Variant();
diff --git a/editor/debugger/editor_debugger_tree.h b/editor/debugger/editor_debugger_tree.h
index 705df17baf..d048688cad 100644
--- a/editor/debugger/editor_debugger_tree.h
+++ b/editor/debugger/editor_debugger_tree.h
@@ -49,6 +49,8 @@ private:
ObjectID inspected_object_id;
int debugger_id = 0;
bool updating_scene_tree = false;
+ bool scrolling_to_item = false;
+ bool selection_uncollapse_all = false;
HashSet<ObjectID> unfold_cache;
PopupMenu *item_menu = nullptr;
EditorFileDialog *file_dialog = nullptr;
@@ -78,6 +80,7 @@ public:
ObjectID get_selected_object();
int get_current_debugger(); // Would love to have one tree for every debugger.
void update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger);
+ void select_node(ObjectID p_id);
EditorDebuggerTree();
};
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 8b253f36e4..33fa208f70 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -390,10 +390,10 @@ void EditorProfiler::_update_frame() {
void EditorProfiler::_update_button_text() {
if (activate->is_pressed()) {
- activate->set_icon(get_editor_theme_icon(SNAME("Stop")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
activate->set_text(TTR("Stop"));
} else {
- activate->set_icon(get_editor_theme_icon(SNAME("Play")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Play")));
activate->set_text(TTR("Start"));
}
}
@@ -428,8 +428,8 @@ void EditorProfiler::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
- activate->set_icon(get_editor_theme_icon(SNAME("Play")));
- clear_button->set_icon(get_editor_theme_icon(SNAME("Clear")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Play")));
+ clear_button->set_button_icon(get_editor_theme_icon(SNAME("Clear")));
theme_cache.seek_line_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor));
theme_cache.seek_line_color.a = 0.8;
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index b949df4518..9a83277e99 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -411,12 +411,12 @@ void EditorVisualProfiler::_update_frame(bool p_focus_selected) {
void EditorVisualProfiler::_activate_pressed() {
if (activate->is_pressed()) {
- activate->set_icon(get_editor_theme_icon(SNAME("Stop")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
activate->set_text(TTR("Stop"));
_clear_pressed(); //always clear on start
clear_button->set_disabled(false);
} else {
- activate->set_icon(get_editor_theme_icon(SNAME("Play")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Play")));
activate->set_text(TTR("Start"));
}
emit_signal(SNAME("enable_profiling"), activate->is_pressed());
@@ -438,8 +438,8 @@ void EditorVisualProfiler::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
- activate->set_icon(get_editor_theme_icon(SNAME("Play")));
- clear_button->set_icon(get_editor_theme_icon(SNAME("Clear")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Play")));
+ clear_button->set_button_icon(get_editor_theme_icon(SNAME("Clear")));
} break;
}
}
@@ -657,10 +657,10 @@ void EditorVisualProfiler::_bind_methods() {
void EditorVisualProfiler::_update_button_text() {
if (activate->is_pressed()) {
- activate->set_icon(get_editor_theme_icon(SNAME("Stop")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
activate->set_text(TTR("Stop"));
} else {
- activate->set_icon(get_editor_theme_icon(SNAME("Play")));
+ activate->set_button_icon(get_editor_theme_icon(SNAME("Play")));
activate->set_text(TTR("Start"));
}
}
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index cbe7910518..da59450dd0 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -95,9 +95,9 @@ void ScriptEditorDebugger::debug_copy() {
void ScriptEditorDebugger::debug_skip_breakpoints() {
skip_breakpoints_value = !skip_breakpoints_value;
if (skip_breakpoints_value) {
- skip_breakpoints->set_icon(get_editor_theme_icon(SNAME("DebugSkipBreakpointsOn")));
+ skip_breakpoints->set_button_icon(get_editor_theme_icon(SNAME("DebugSkipBreakpointsOn")));
} else {
- skip_breakpoints->set_icon(get_editor_theme_icon(SNAME("DebugSkipBreakpointsOff")));
+ skip_breakpoints->set_button_icon(get_editor_theme_icon(SNAME("DebugSkipBreakpointsOff")));
}
Array msg;
@@ -806,6 +806,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
} else if (p_msg == "request_quit") {
emit_signal(SNAME("stop_requested"));
_stop_and_notify();
+ } else if (p_msg == "remote_node_clicked") {
+ if (!p_data.is_empty()) {
+ emit_signal(SNAME("remote_tree_select_requested"), p_data[0]);
+ }
} else if (p_msg == "performance:profile_names") {
Vector<StringName> monitors;
monitors.resize(p_data.size());
@@ -827,7 +831,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
bool parsed = EditorDebuggerNode::get_singleton()->plugins_capture(this, p_msg, p_data);
if (!parsed) {
- WARN_PRINT("unknown message " + p_msg);
+ WARN_PRINT("Unknown message: " + p_msg);
}
}
}
@@ -870,14 +874,14 @@ void ScriptEditorDebugger::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
tabs->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles)));
- skip_breakpoints->set_icon(get_editor_theme_icon(skip_breakpoints_value ? SNAME("DebugSkipBreakpointsOn") : SNAME("DebugSkipBreakpointsOff")));
- copy->set_icon(get_editor_theme_icon(SNAME("ActionCopy")));
- step->set_icon(get_editor_theme_icon(SNAME("DebugStep")));
- next->set_icon(get_editor_theme_icon(SNAME("DebugNext")));
- dobreak->set_icon(get_editor_theme_icon(SNAME("Pause")));
- docontinue->set_icon(get_editor_theme_icon(SNAME("DebugContinue")));
- vmem_refresh->set_icon(get_editor_theme_icon(SNAME("Reload")));
- vmem_export->set_icon(get_editor_theme_icon(SNAME("Save")));
+ skip_breakpoints->set_button_icon(get_editor_theme_icon(skip_breakpoints_value ? SNAME("DebugSkipBreakpointsOn") : SNAME("DebugSkipBreakpointsOff")));
+ copy->set_button_icon(get_editor_theme_icon(SNAME("ActionCopy")));
+ step->set_button_icon(get_editor_theme_icon(SNAME("DebugStep")));
+ next->set_button_icon(get_editor_theme_icon(SNAME("DebugNext")));
+ dobreak->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
+ docontinue->set_button_icon(get_editor_theme_icon(SNAME("DebugContinue")));
+ vmem_refresh->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
+ vmem_export->set_button_icon(get_editor_theme_icon(SNAME("Save")));
search->set_right_icon(get_editor_theme_icon(SNAME("Search")));
reason->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
@@ -905,37 +909,42 @@ void ScriptEditorDebugger::_notification(int p_what) {
if (is_session_active()) {
peer->poll();
- if (camera_override == CameraOverride::OVERRIDE_2D) {
- Dictionary state = CanvasItemEditor::get_singleton()->get_state();
- float zoom = state["zoom"];
- Point2 offset = state["ofs"];
- Transform2D transform;
-
- transform.scale_basis(Size2(zoom, zoom));
- transform.columns[2] = -offset * zoom;
-
- Array msg;
- msg.push_back(transform);
- _put_msg("scene:override_camera_2D:transform", msg);
-
- } else if (camera_override >= CameraOverride::OVERRIDE_3D_1) {
- int viewport_idx = camera_override - CameraOverride::OVERRIDE_3D_1;
- Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(viewport_idx);
- Camera3D *const cam = viewport->get_camera_3d();
-
- Array msg;
- msg.push_back(cam->get_camera_transform());
- if (cam->get_projection() == Camera3D::PROJECTION_ORTHOGONAL) {
- msg.push_back(false);
- msg.push_back(cam->get_size());
- } else {
- msg.push_back(true);
- msg.push_back(cam->get_fov());
+ if (camera_override == CameraOverride::OVERRIDE_EDITORS) {
+ // CanvasItem Editor
+ {
+ Dictionary state = CanvasItemEditor::get_singleton()->get_state();
+ float zoom = state["zoom"];
+ Point2 offset = state["ofs"];
+ Transform2D transform;
+
+ transform.scale_basis(Size2(zoom, zoom));
+ transform.columns[2] = -offset * zoom;
+
+ Array msg;
+ msg.push_back(transform);
+ _put_msg("scene:transform_camera_2d", msg);
+ }
+
+ // Node3D Editor
+ {
+ Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_last_used_viewport();
+ const Camera3D *cam = viewport->get_camera_3d();
+
+ Array msg;
+ msg.push_back(cam->get_camera_transform());
+ if (cam->get_projection() == Camera3D::PROJECTION_ORTHOGONAL) {
+ msg.push_back(false);
+ msg.push_back(cam->get_size());
+ } else {
+ msg.push_back(true);
+ msg.push_back(cam->get_fov());
+ }
+ msg.push_back(cam->get_near());
+ msg.push_back(cam->get_far());
+ _put_msg("scene:transform_camera_3d", msg);
}
- msg.push_back(cam->get_near());
- msg.push_back(cam->get_far());
- _put_msg("scene:override_camera_3D:transform", msg);
}
+
if (is_breaked() && can_request_idle_draw) {
_put_msg("servers:draw", Array());
can_request_idle_draw = false;
@@ -1024,6 +1033,9 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
_update_buttons_state();
emit_signal(SNAME("started"));
+ Array quit_keys = DebuggerMarshalls::serialize_key_shortcut(ED_GET_SHORTCUT("editor/stop_running_project"));
+ _put_msg("scene:setup_scene", quit_keys);
+
if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_profiler", false)) {
profiler->set_profiling(true);
}
@@ -1161,6 +1173,12 @@ String ScriptEditorDebugger::get_var_value(const String &p_var) const {
return inspector->get_stack_variable(p_var);
}
+void ScriptEditorDebugger::_resources_reimported(const PackedStringArray &p_resources) {
+ Array msg;
+ msg.push_back(p_resources);
+ _put_msg("scene:reload_cached_files", msg);
+}
+
int ScriptEditorDebugger::_get_node_path_cache(const NodePath &p_path) {
const int *r = node_path_cache.getptr(p_path);
if (r) {
@@ -1469,23 +1487,10 @@ CameraOverride ScriptEditorDebugger::get_camera_override() const {
}
void ScriptEditorDebugger::set_camera_override(CameraOverride p_override) {
- if (p_override == CameraOverride::OVERRIDE_2D && camera_override != CameraOverride::OVERRIDE_2D) {
- Array msg;
- msg.push_back(true);
- _put_msg("scene:override_camera_2D:set", msg);
- } else if (p_override != CameraOverride::OVERRIDE_2D && camera_override == CameraOverride::OVERRIDE_2D) {
- Array msg;
- msg.push_back(false);
- _put_msg("scene:override_camera_2D:set", msg);
- } else if (p_override >= CameraOverride::OVERRIDE_3D_1 && camera_override < CameraOverride::OVERRIDE_3D_1) {
- Array msg;
- msg.push_back(true);
- _put_msg("scene:override_camera_3D:set", msg);
- } else if (p_override < CameraOverride::OVERRIDE_3D_1 && camera_override >= CameraOverride::OVERRIDE_3D_1) {
- Array msg;
- msg.push_back(false);
- _put_msg("scene:override_camera_3D:set", msg);
- }
+ Array msg;
+ msg.push_back(p_override != CameraOverride::OVERRIDE_NONE);
+ msg.push_back(p_override == CameraOverride::OVERRIDE_EDITORS);
+ _put_msg("scene:override_cameras", msg);
camera_override = p_override;
}
@@ -1776,6 +1781,7 @@ void ScriptEditorDebugger::_bind_methods() {
ADD_SIGNAL(MethodInfo("remote_object_updated", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("remote_object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
ADD_SIGNAL(MethodInfo("remote_tree_updated"));
+ ADD_SIGNAL(MethodInfo("remote_tree_select_requested", PropertyInfo(Variant::NODE_PATH, "path")));
ADD_SIGNAL(MethodInfo("output", PropertyInfo(Variant::STRING, "msg"), PropertyInfo(Variant::INT, "level")));
ADD_SIGNAL(MethodInfo("stack_dump", PropertyInfo(Variant::ARRAY, "stack_dump")));
ADD_SIGNAL(MethodInfo("stack_frame_vars", PropertyInfo(Variant::INT, "num_vars")));
@@ -1821,6 +1827,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
tabs->connect("tab_changed", callable_mp(this, &ScriptEditorDebugger::_tab_changed));
InspectorDock::get_inspector_singleton()->connect("object_id_selected", callable_mp(this, &ScriptEditorDebugger::_remote_object_selected));
+ EditorFileSystem::get_singleton()->connect("resources_reimported", callable_mp(this, &ScriptEditorDebugger::_resources_reimported));
{ //debugger
VBoxContainer *vbc = memnew(VBoxContainer);
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index 1908b1e5a7..06a968e141 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -198,6 +198,8 @@ private:
void _video_mem_request();
void _video_mem_export();
+ void _resources_reimported(const PackedStringArray &p_resources);
+
int _get_node_path_cache(const NodePath &p_path);
int _get_res_path_cache(const String &p_path);
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index 1e44a9bdc9..bce0c87452 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -411,9 +411,9 @@ void EditorAssetInstaller::_toggle_source_tree(bool p_visible, bool p_scroll_to_
show_source_files_button->set_pressed_no_signal(p_visible); // To keep in sync if triggered by something else.
if (p_visible) {
- show_source_files_button->set_icon(get_editor_theme_icon(SNAME("Back")));
+ show_source_files_button->set_button_icon(get_editor_theme_icon(SNAME("Back")));
} else {
- show_source_files_button->set_icon(get_editor_theme_icon(SNAME("Forward")));
+ show_source_files_button->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
}
if (p_visible && p_scroll_to_error && first_file_conflict) {
@@ -597,9 +597,9 @@ void EditorAssetInstaller::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
if (show_source_files_button->is_pressed()) {
- show_source_files_button->set_icon(get_editor_theme_icon(SNAME("Back")));
+ show_source_files_button->set_button_icon(get_editor_theme_icon(SNAME("Back")));
} else {
- show_source_files_button->set_icon(get_editor_theme_icon(SNAME("Forward")));
+ show_source_files_button->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
}
asset_conflicts_link->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 24fc7a9c2b..0649272216 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -91,19 +91,28 @@ void EditorAudioBus::_notification(int p_what) {
Color mute_color = EditorThemeManager::is_dark_theme() ? Color(1.0, 0.16, 0.16) : Color(2.35, 1.03, 1.03);
Color bypass_color = EditorThemeManager::is_dark_theme() ? Color(0.13, 0.8, 1.0) : Color(1.03, 2.04, 2.35);
float darkening_factor = EditorThemeManager::is_dark_theme() ? 0.15 : 0.65;
-
- Ref<StyleBoxFlat>(solo->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(solo_color.darkened(darkening_factor));
- Ref<StyleBoxFlat>(mute->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(mute_color.darkened(darkening_factor));
- Ref<StyleBoxFlat>(bypass->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(bypass_color.darkened(darkening_factor));
-
- solo->set_icon(get_editor_theme_icon(SNAME("AudioBusSolo")));
+ Color solo_color_darkened = solo_color.darkened(darkening_factor);
+ Color mute_color_darkened = mute_color.darkened(darkening_factor);
+ Color bypass_color_darkened = bypass_color.darkened(darkening_factor);
+
+ Ref<StyleBoxFlat>(solo->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(solo_color_darkened);
+ Ref<StyleBoxFlat>(mute->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(mute_color_darkened);
+ Ref<StyleBoxFlat>(bypass->get_theme_stylebox(SceneStringName(pressed)))->set_border_color(bypass_color_darkened);
+ Ref<StyleBoxFlat>(solo->get_theme_stylebox("hover_pressed"))->set_border_color(solo_color_darkened);
+ Ref<StyleBoxFlat>(mute->get_theme_stylebox("hover_pressed"))->set_border_color(mute_color_darkened);
+ Ref<StyleBoxFlat>(bypass->get_theme_stylebox("hover_pressed"))->set_border_color(bypass_color_darkened);
+
+ solo->set_button_icon(get_editor_theme_icon(SNAME("AudioBusSolo")));
solo->add_theme_color_override("icon_pressed_color", solo_color);
- mute->set_icon(get_editor_theme_icon(SNAME("AudioBusMute")));
+ solo->add_theme_color_override("icon_hover_pressed_color", solo_color_darkened);
+ mute->set_button_icon(get_editor_theme_icon(SNAME("AudioBusMute")));
mute->add_theme_color_override("icon_pressed_color", mute_color);
- bypass->set_icon(get_editor_theme_icon(SNAME("AudioBusBypass")));
+ mute->add_theme_color_override("icon_hover_pressed_color", mute_color_darkened);
+ bypass->set_button_icon(get_editor_theme_icon(SNAME("AudioBusBypass")));
bypass->add_theme_color_override("icon_pressed_color", bypass_color);
+ bypass->add_theme_color_override("icon_hover_pressed_color", bypass_color_darkened);
- bus_options->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ bus_options->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
audio_value_preview_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SceneStringName(font_color), SNAME("TooltipLabel")));
audio_value_preview_label->add_theme_color_override("font_shadow_color", get_theme_color(SNAME("font_shadow_color"), SNAME("TooltipLabel")));
@@ -841,13 +850,18 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
child->begin_bulk_theme_override();
child->add_theme_style_override(CoreStringName(normal), sbempty);
child->add_theme_style_override("hover", sbempty);
+ child->add_theme_style_override("hover_mirrored", sbempty);
child->add_theme_style_override("focus", sbempty);
+ child->add_theme_style_override("focus_mirrored", sbempty);
Ref<StyleBoxFlat> sbflat = memnew(StyleBoxFlat);
sbflat->set_content_margin_all(0);
sbflat->set_bg_color(Color(1, 1, 1, 0));
sbflat->set_border_width(Side::SIDE_BOTTOM, Math::round(3 * EDSCALE));
child->add_theme_style_override(SceneStringName(pressed), sbflat);
+ child->add_theme_style_override("pressed_mirrored", sbflat);
+ child->add_theme_style_override("hover_pressed", sbflat);
+ child->add_theme_style_override("hover_pressed_mirrored", sbflat);
child->end_bulk_theme_override();
}
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 1613d1d62f..23a2f5b13c 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -55,12 +55,12 @@ void EditorAutoloadSettings::_notification(int p_what) {
file_dialog->add_filter("*." + E);
}
- browse_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
+ browse_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));
} break;
case NOTIFICATION_THEME_CHANGED: {
- browse_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
- add_autoload->set_icon(get_editor_theme_icon(SNAME("Add")));
+ browse_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));
+ add_autoload->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index ee16c61c89..bb02172b1a 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -547,6 +547,7 @@ Variant EditorData::instantiate_custom_type(const String &p_type, const String &
if (n) {
n->set_name(p_type);
}
+ n->set_meta(SceneStringName(_custom_type_script), script);
((Object *)ob)->set_script(script);
return ob;
}
@@ -1008,6 +1009,7 @@ Variant EditorData::script_class_instance(const String &p_class) {
// Store in a variant to initialize the refcount if needed.
Variant obj = ClassDB::instantiate(script->get_instance_base_type());
if (obj) {
+ Object::cast_to<Object>(obj)->set_meta(SceneStringName(_custom_type_script), script);
obj.operator Object *()->set_script(script);
}
return obj;
diff --git a/editor/editor_dock_manager.cpp b/editor/editor_dock_manager.cpp
index 0bdda41f26..1db073ec81 100644
--- a/editor/editor_dock_manager.cpp
+++ b/editor/editor_dock_manager.cpp
@@ -852,21 +852,21 @@ void DockContextPopup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
if (make_float_button) {
- make_float_button->set_icon(get_editor_theme_icon(SNAME("MakeFloating")));
+ make_float_button->set_button_icon(get_editor_theme_icon(SNAME("MakeFloating")));
}
if (is_layout_rtl()) {
- tab_move_left_button->set_icon(get_editor_theme_icon(SNAME("Forward")));
- tab_move_right_button->set_icon(get_editor_theme_icon(SNAME("Back")));
+ tab_move_left_button->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
+ tab_move_right_button->set_button_icon(get_editor_theme_icon(SNAME("Back")));
tab_move_left_button->set_tooltip_text(TTR("Move this dock right one tab."));
tab_move_right_button->set_tooltip_text(TTR("Move this dock left one tab."));
} else {
- tab_move_left_button->set_icon(get_editor_theme_icon(SNAME("Back")));
- tab_move_right_button->set_icon(get_editor_theme_icon(SNAME("Forward")));
+ tab_move_left_button->set_button_icon(get_editor_theme_icon(SNAME("Back")));
+ tab_move_right_button->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
tab_move_left_button->set_tooltip_text(TTR("Move this dock left one tab."));
tab_move_right_button->set_tooltip_text(TTR("Move this dock right one tab."));
}
- dock_to_bottom_button->set_icon(get_editor_theme_icon(SNAME("ControlAlignBottomWide")));
- close_button->set_icon(get_editor_theme_icon(SNAME("Close")));
+ dock_to_bottom_button->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignBottomWide")));
+ close_button->set_button_icon(get_editor_theme_icon(SNAME("Close")));
} break;
}
}
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 44fc9e3702..9cf10c0ecb 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -49,6 +49,7 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = {
TTRC("FileSystem Dock"),
TTRC("Import Dock"),
TTRC("History Dock"),
+ TTRC("Game View"),
};
const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = {
@@ -60,6 +61,7 @@ const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = {
TTRC("Allows to browse the local file system via a dedicated dock."),
TTRC("Allows to configure import settings for individual assets. Requires the FileSystem dock to function."),
TTRC("Provides an overview of the editor's and each scene's undo history."),
+ TTRC("Provides tools for selecting and debugging nodes at runtime."),
};
const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
@@ -71,6 +73,7 @@ const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
"filesystem_dock",
"import_dock",
"history_dock",
+ "game",
};
void EditorFeatureProfile::set_disable_class(const StringName &p_class, bool p_disabled) {
@@ -307,6 +310,7 @@ void EditorFeatureProfile::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_FILESYSTEM_DOCK);
BIND_ENUM_CONSTANT(FEATURE_IMPORT_DOCK);
BIND_ENUM_CONSTANT(FEATURE_HISTORY_DOCK);
+ BIND_ENUM_CONSTANT(FEATURE_GAME);
BIND_ENUM_CONSTANT(FEATURE_MAX);
}
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index 7458a04e19..e84936dd34 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -55,6 +55,7 @@ public:
FEATURE_FILESYSTEM_DOCK,
FEATURE_IMPORT_DOCK,
FEATURE_HISTORY_DOCK,
+ FEATURE_GAME,
FEATURE_MAX
};
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index c6ed310a9a..cc81001efb 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1027,7 +1027,9 @@ void EditorFileSystem::scan() {
void EditorFileSystem::ScanProgress::increment() {
current++;
float ratio = current / MAX(hi, 1.0f);
- progress->step(ratio * 1000.0f);
+ if (progress) {
+ progress->step(ratio * 1000.0f);
+ }
EditorFileSystem::singleton->scan_total = ratio;
}
@@ -1257,6 +1259,15 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir,
}
}
}
+
+ if (fi->uid == ResourceUID::INVALID_ID && ResourceLoader::exists(path) && !ResourceLoader::has_custom_uid_support(path) && !FileAccess::exists(path + ".uid")) {
+ // Create a UID.
+ Ref<FileAccess> f = FileAccess::open(path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ fi->uid = ResourceUID::get_singleton()->create_id();
+ f->store_line(ResourceUID::get_singleton()->id_to_text(fi->uid));
+ }
+ }
}
if (fi->uid != ResourceUID::INVALID_ID) {
@@ -1293,7 +1304,7 @@ void EditorFileSystem::_process_removed_files(const HashSet<String> &p_processed
}
}
-void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress) {
+void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, bool p_recursive) {
uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path());
bool updated_dir = false;
@@ -1487,7 +1498,9 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanPr
scan_actions.push_back(ia);
continue;
}
- _scan_fs_changes(p_dir->get_subdir(i), p_progress);
+ if (p_recursive) {
+ _scan_fs_changes(p_dir->get_subdir(i), p_progress);
+ }
}
nb_files_total = MAX(nb_files_total + diff_nb_files, 0);
@@ -2372,10 +2385,18 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
if (!is_scanning()) {
_process_update_pending();
}
- call_deferred(SNAME("emit_signal"), "filesystem_changed"); // Update later
+ if (!filesystem_changed_queued) {
+ filesystem_changed_queued = true;
+ callable_mp(this, &EditorFileSystem::_notify_filesystem_changed).call_deferred();
+ }
}
}
+void EditorFileSystem::_notify_filesystem_changed() {
+ emit_signal("filesystem_changed");
+ filesystem_changed_queued = false;
+}
+
HashSet<String> EditorFileSystem::get_valid_extensions() const {
return valid_extensions;
}
@@ -2569,7 +2590,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
bool found = _find_file(file, &fs, cpos);
- ERR_FAIL_COND_V_MSG(!found, ERR_UNCONFIGURED, "Can't find file '" + file + "'.");
+ ERR_FAIL_COND_V_MSG(!found, ERR_UNCONFIGURED, vformat("Can't find file '%s' during group reimport.", file));
//update modified times, to avoid reimport
fs->files[cpos]->modified_time = FileAccess::get_modified_time(file);
@@ -2619,7 +2640,7 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
int cpos = -1;
if (p_update_file_system) {
bool found = _find_file(p_file, &fs, cpos);
- ERR_FAIL_COND_V_MSG(!found, ERR_FILE_NOT_FOUND, "Can't find file '" + p_file + "'.");
+ ERR_FAIL_COND_V_MSG(!found, ERR_FILE_NOT_FOUND, vformat("Can't find file '%s' during file reimport.", p_file));
}
//try to obtain existing params
@@ -2728,13 +2749,17 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
}
}
+ if (uid == ResourceUID::INVALID_ID) {
+ uid = ResourceUID::get_singleton()->create_id();
+ }
+
//finally, perform import!!
String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(p_file);
List<String> import_variants;
List<String> gen_files;
Variant meta;
- Error err = importer->import(p_file, base_path, params, &import_variants, &gen_files, &meta);
+ Error err = importer->import(uid, p_file, base_path, params, &import_variants, &gen_files, &meta);
// As import is complete, save the .import file.
@@ -2755,10 +2780,6 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
f->store_line("type=\"" + importer->get_resource_type() + "\"");
}
- if (uid == ResourceUID::INVALID_ID) {
- uid = ResourceUID::get_singleton()->create_id();
- }
-
f->store_line("uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\""); // Store in readable format.
if (err == OK) {
@@ -2912,6 +2933,96 @@ void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file
emit_signal(SNAME("resources_reimported"), reloads);
}
+Error EditorFileSystem::_copy_file(const String &p_from, const String &p_to) {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (FileAccess::exists(p_from + ".import")) {
+ Error err = da->copy(p_from, p_to);
+ if (err != OK) {
+ return err;
+ }
+
+ // Remove uid from .import file to avoid conflict.
+ Ref<ConfigFile> cfg;
+ cfg.instantiate();
+ cfg->load(p_from + ".import");
+ cfg->erase_section_key("remap", "uid");
+ err = cfg->save(p_to + ".import");
+ if (err != OK) {
+ return err;
+ }
+ } else if (ResourceLoader::get_resource_uid(p_from) == ResourceUID::INVALID_ID) {
+ // Files which do not use an uid can just be copied.
+ Error err = da->copy(p_from, p_to);
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ // Load the resource and save it again in the new location (this generates a new UID).
+ Error err;
+ Ref<Resource> res = ResourceLoader::load(p_from, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
+ if (err == OK && res.is_valid()) {
+ err = ResourceSaver::save(res, p_to, ResourceSaver::FLAG_COMPRESS);
+ if (err != OK) {
+ return err;
+ }
+ } else if (err != OK) {
+ // When loading files like text files the error is OK but the resource is still null.
+ // We can ignore such files.
+ return err;
+ }
+ }
+ return OK;
+}
+
+bool EditorFileSystem::_copy_directory(const String &p_from, const String &p_to, List<CopiedFile> *p_files) {
+ Ref<DirAccess> old_dir = DirAccess::open(p_from);
+ ERR_FAIL_COND_V(old_dir.is_null(), false);
+
+ Error err = make_dir_recursive(p_to);
+ if (err != OK && err != ERR_ALREADY_EXISTS) {
+ return false;
+ }
+
+ bool success = true;
+ old_dir->set_include_navigational(false);
+ old_dir->list_dir_begin();
+
+ for (String F = old_dir->_get_next(); !F.is_empty(); F = old_dir->_get_next()) {
+ if (old_dir->current_is_dir()) {
+ success = _copy_directory(p_from.path_join(F), p_to.path_join(F), p_files) && success;
+ } else if (F.get_extension() != "import") {
+ CopiedFile copy;
+ copy.from = p_from.path_join(F);
+ copy.to = p_to.path_join(F);
+ p_files->push_back(copy);
+ }
+ }
+ return success;
+}
+
+void EditorFileSystem::_queue_refresh_filesystem() {
+ if (refresh_queued) {
+ return;
+ }
+ refresh_queued = true;
+ get_tree()->connect(SNAME("process_frame"), callable_mp(this, &EditorFileSystem::_refresh_filesystem), CONNECT_ONE_SHOT);
+}
+
+void EditorFileSystem::_refresh_filesystem() {
+ for (const ObjectID &id : folders_to_sort) {
+ EditorFileSystemDirectory *dir = Object::cast_to<EditorFileSystemDirectory>(ObjectDB::get_instance(id));
+ if (dir) {
+ dir->subdirs.sort_custom<DirectoryComparator>();
+ }
+ }
+ folders_to_sort.clear();
+
+ _update_scan_actions();
+
+ emit_signal(SNAME("filesystem_changed"));
+ refresh_queued = false;
+}
+
void EditorFileSystem::_reimport_thread(uint32_t p_index, ImportThreadData *p_import_data) {
int current_max = p_import_data->reimport_from + int(p_index);
p_import_data->max_index.exchange_if_greater(current_max);
@@ -3235,10 +3346,9 @@ Error EditorFileSystem::make_dir_recursive(const String &p_path, const String &p
const String path = da->get_current_dir();
EditorFileSystemDirectory *parent = get_filesystem_path(path);
ERR_FAIL_NULL_V(parent, ERR_FILE_NOT_FOUND);
+ folders_to_sort.insert(parent->get_instance_id());
const PackedStringArray folders = p_path.trim_prefix(path).trim_suffix("/").split("/");
- bool first = true;
-
for (const String &folder : folders) {
const int current = parent->find_dir_index(folder);
if (current > -1) {
@@ -3250,18 +3360,59 @@ Error EditorFileSystem::make_dir_recursive(const String &p_path, const String &p
efd->parent = parent;
efd->name = folder;
parent->subdirs.push_back(efd);
-
- if (first) {
- parent->subdirs.sort_custom<DirectoryComparator>();
- first = false;
- }
parent = efd;
}
- emit_signal(SNAME("filesystem_changed"));
+ _queue_refresh_filesystem();
return OK;
}
+Error EditorFileSystem::copy_file(const String &p_from, const String &p_to) {
+ _copy_file(p_from, p_to);
+
+ EditorFileSystemDirectory *parent = get_filesystem_path(p_to.get_base_dir());
+ ERR_FAIL_NULL_V(parent, ERR_FILE_NOT_FOUND);
+
+ ScanProgress sp;
+ _scan_fs_changes(parent, sp, false);
+
+ _queue_refresh_filesystem();
+ return OK;
+}
+
+Error EditorFileSystem::copy_directory(const String &p_from, const String &p_to) {
+ List<CopiedFile> files;
+ bool success = _copy_directory(p_from, p_to, &files);
+
+ EditorProgress *ep = nullptr;
+ if (files.size() > 10) {
+ ep = memnew(EditorProgress("_copy_files", TTR("Copying files..."), files.size()));
+ }
+
+ int i = 0;
+ for (const CopiedFile &F : files) {
+ if (_copy_file(F.from, F.to) != OK) {
+ success = false;
+ }
+ if (ep) {
+ ep->step(F.from.get_file(), i++, false);
+ }
+ }
+ memdelete_notnull(ep);
+
+ EditorFileSystemDirectory *efd = get_filesystem_path(p_to);
+ ERR_FAIL_NULL_V(efd, FAILED);
+ ERR_FAIL_NULL_V(efd->get_parent(), FAILED);
+
+ folders_to_sort.insert(efd->get_parent()->get_instance_id());
+
+ ScanProgress sp;
+ _scan_fs_changes(efd, sp);
+
+ _queue_refresh_filesystem();
+ return success ? OK : FAILED;
+}
+
ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate) {
if (!p_path.is_resource_file() || p_path.begins_with(ProjectSettings::get_singleton()->get_project_data_path())) {
// Saved externally (configuration file) or internal file, do not assign an ID.
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 7120a68b39..11573ef0d7 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -180,6 +180,7 @@ class EditorFileSystem : public Node {
EditorFileSystemDirectory *new_filesystem = nullptr;
ScannedDirectory *first_scan_root_dir = nullptr;
+ bool filesystem_changed_queued = false;
bool scanning = false;
bool importing = false;
bool first_scan = true;
@@ -189,6 +190,7 @@ class EditorFileSystem : public Node {
bool revalidate_import_files = false;
int nb_files_total = 0;
+ void _notify_filesystem_changed();
void _scan_filesystem();
void _first_scan_filesystem();
void _first_scan_process_scripts(const ScannedDirectory *p_scan_dir, List<String> &p_gdextension_extensions, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions);
@@ -239,7 +241,7 @@ class EditorFileSystem : public Node {
bool _find_file(const String &p_file, EditorFileSystemDirectory **r_d, int &r_file_pos) const;
- void _scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress);
+ void _scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, bool p_recursive = true);
void _delete_internal_files(const String &p_file);
int _insert_actions_delete_files_directory(EditorFileSystemDirectory *p_dir);
@@ -324,6 +326,19 @@ class EditorFileSystem : public Node {
HashSet<String> group_file_cache;
HashMap<String, String> file_icon_cache;
+ struct CopiedFile {
+ String from;
+ String to;
+ };
+
+ bool refresh_queued = false;
+ HashSet<ObjectID> folders_to_sort;
+
+ Error _copy_file(const String &p_from, const String &p_to);
+ bool _copy_directory(const String &p_from, const String &p_to, List<CopiedFile> *p_files);
+ void _queue_refresh_filesystem();
+ void _refresh_filesystem();
+
struct ImportThreadData {
const ImportFile *reimport_files;
int reimport_from;
@@ -378,6 +393,8 @@ public:
void move_group_file(const String &p_path, const String &p_new_path);
Error make_dir_recursive(const String &p_path, const String &p_base_path = String());
+ Error copy_file(const String &p_from, const String &p_to);
+ Error copy_directory(const String &p_from, const String &p_to);
static bool _should_skip_directory(const String &p_path);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index cfe257fcfc..0ca1ed2d50 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -3109,9 +3109,9 @@ void EditorHelp::set_scroll(int p_scroll) {
void EditorHelp::update_toggle_scripts_button() {
if (is_layout_rtl()) {
- toggle_scripts_button->set_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Forward") : SNAME("Back")));
+ toggle_scripts_button->set_button_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Forward") : SNAME("Back")));
} else {
- toggle_scripts_button->set_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward")));
+ toggle_scripts_button->set_button_icon(get_editor_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward")));
}
toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
}
@@ -4153,8 +4153,8 @@ void FindBar::popup_search() {
void FindBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- find_prev->set_icon(get_editor_theme_icon(SNAME("MoveUp")));
- find_next->set_icon(get_editor_theme_icon(SNAME("MoveDown")));
+ find_prev->set_button_icon(get_editor_theme_icon(SNAME("MoveUp")));
+ find_next->set_button_icon(get_editor_theme_icon(SNAME("MoveDown")));
hide_button->set_texture_normal(get_editor_theme_icon(SNAME("Close")));
hide_button->set_texture_hover(get_editor_theme_icon(SNAME("Close")));
hide_button->set_texture_pressed(get_editor_theme_icon(SNAME("Close")));
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 47f16f219f..b0c06475f8 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -151,7 +151,7 @@ void EditorHelpSearch::_update_results() {
search_flags |= SEARCH_SHOW_HIERARCHY;
}
- search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags)));
+ search.instantiate(results_tree, results_tree, &tree_cache, term, search_flags);
// Clear old search flags to force rebuild on short term.
old_search_flags = 0;
@@ -162,7 +162,7 @@ void EditorHelpSearch::_update_results() {
hierarchy_button->set_disabled(true);
// Always show hierarchy for short searches.
- search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags | SEARCH_SHOW_HIERARCHY)));
+ search.instantiate(results_tree, results_tree, &tree_cache, term, search_flags | SEARCH_SHOW_HIERARCHY);
old_search_flags = search_flags;
set_process(true);
@@ -244,8 +244,8 @@ void EditorHelpSearch::_notification(int p_what) {
search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
search_box->add_theme_icon_override("right_icon", get_editor_theme_icon(SNAME("Search")));
- case_sensitive_button->set_icon(get_editor_theme_icon(SNAME("MatchCase")));
- hierarchy_button->set_icon(get_editor_theme_icon(SNAME("ClassList")));
+ case_sensitive_button->set_button_icon(get_editor_theme_icon(SNAME("MatchCase")));
+ hierarchy_button->set_button_icon(get_editor_theme_icon(SNAME("ClassList")));
if (is_visible()) {
_update_results();
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 21f67772ea..1c23ce8ede 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -931,10 +931,19 @@ float EditorProperty::get_name_split_ratio() const {
return split_ratio;
}
+void EditorProperty::set_favoritable(bool p_favoritable) {
+ can_favorite = p_favoritable;
+}
+
+bool EditorProperty::is_favoritable() const {
+ return can_favorite;
+}
+
void EditorProperty::set_object_and_property(Object *p_object, const StringName &p_property) {
object = p_object;
property = p_property;
- _update_pin_flags();
+
+ _update_flags();
}
static bool _is_value_potential_override(Node *p_node, const String &p_property) {
@@ -953,12 +962,14 @@ static bool _is_value_potential_override(Node *p_node, const String &p_property)
}
}
-void EditorProperty::_update_pin_flags() {
+void EditorProperty::_update_flags() {
can_pin = false;
pin_hidden = true;
+
if (read_only) {
return;
}
+
if (Node *node = Object::cast_to<Node>(object)) {
// Avoid errors down the road by ignoring nodes which are not part of a scene
if (!node->get_owner()) {
@@ -1034,6 +1045,10 @@ void EditorProperty::menu_option(int p_option) {
case MENU_COPY_PROPERTY_PATH: {
DisplayServer::get_singleton()->clipboard_set(property_path);
} break;
+ case MENU_FAVORITE_PROPERTY: {
+ emit_signal(SNAME("property_favorited"), property, !favorited);
+ queue_redraw();
+ } break;
case MENU_PIN_VALUE: {
emit_signal(SNAME("property_pinned"), property, !pinned);
queue_redraw();
@@ -1091,6 +1106,7 @@ void EditorProperty::_bind_methods() {
ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING_NAME, "property")));
ADD_SIGNAL(MethodInfo("property_keyed_with_value", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "checked")));
+ ADD_SIGNAL(MethodInfo("property_favorited", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "favorited")));
ADD_SIGNAL(MethodInfo("property_pinned", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "pinned")));
ADD_SIGNAL(MethodInfo("property_can_revert_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "can_revert")));
ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
@@ -1129,8 +1145,21 @@ void EditorProperty::_update_popup() {
menu->set_item_disabled(MENU_PASTE_VALUE, is_read_only());
menu->set_item_disabled(MENU_COPY_PROPERTY_PATH, internal);
- if (!pin_hidden) {
+ if (can_favorite || !pin_hidden) {
menu->add_separator();
+ }
+
+ if (can_favorite) {
+ if (favorited) {
+ menu->add_icon_item(get_editor_theme_icon(SNAME("Unfavorite")), TTR("Unfavorite Property"), MENU_FAVORITE_PROPERTY);
+ menu->set_item_tooltip(menu->get_item_index(MENU_FAVORITE_PROPERTY), TTR("Make this property be put back at its original place."));
+ } else {
+ menu->add_icon_item(get_editor_theme_icon(SNAME("Favorites")), TTR("Favorite Property"), MENU_FAVORITE_PROPERTY);
+ menu->set_item_tooltip(menu->get_item_index(MENU_FAVORITE_PROPERTY), TTR("Make this property be placed at the top for all objects of this class."));
+ }
+ }
+
+ if (!pin_hidden) {
if (can_pin) {
menu->add_icon_check_item(get_editor_theme_icon(SNAME("Pin")), TTR("Pin Value"), MENU_PIN_VALUE);
menu->set_item_checked(menu->get_item_index(MENU_PIN_VALUE), pinned);
@@ -1219,9 +1248,14 @@ void EditorInspectorPlugin::_bind_methods() {
void EditorInspectorCategory::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- menu->set_item_icon(menu->get_item_index(MENU_OPEN_DOCS), get_editor_theme_icon(SNAME("Help")));
+ if (menu) {
+ if (is_favorite) {
+ menu->set_item_icon(menu->get_item_index(EditorInspector::MENU_UNFAVORITE_ALL), get_editor_theme_icon(SNAME("Unfavorite")));
+ } else {
+ menu->set_item_icon(menu->get_item_index(MENU_OPEN_DOCS), get_editor_theme_icon(SNAME("Help")));
+ }
+ }
} break;
case NOTIFICATION_DRAW: {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
@@ -1278,6 +1312,15 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
return memnew(Control); // Make the standard tooltip invisible.
}
+void EditorInspectorCategory::set_as_favorite(EditorInspector *p_for_inspector) {
+ is_favorite = true;
+
+ menu = memnew(PopupMenu);
+ menu->add_item(TTR("Unfavorite All"), EditorInspector::MENU_UNFAVORITE_ALL);
+ add_child(menu);
+ menu->connect(SceneStringName(id_pressed), callable_mp(p_for_inspector, &EditorInspector::_handle_menu_option));
+}
+
Size2 EditorInspectorCategory::get_minimum_size() const {
Ref<Font> font = get_theme_font(SNAME("bold"), EditorStringName(EditorFonts));
int font_size = get_theme_font_size(SNAME("bold_size"), EditorStringName(EditorFonts));
@@ -1306,7 +1349,7 @@ void EditorInspectorCategory::_handle_menu_option(int p_option) {
}
void EditorInspectorCategory::gui_input(const Ref<InputEvent> &p_event) {
- if (doc_class_name.is_empty()) {
+ if (!is_favorite && doc_class_name.is_empty()) {
return;
}
@@ -1315,20 +1358,21 @@ void EditorInspectorCategory::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- menu->set_item_disabled(menu->get_item_index(MENU_OPEN_DOCS), !EditorHelp::get_doc_data()->class_list.has(doc_class_name));
+ if (!is_favorite) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ menu->add_icon_item(get_editor_theme_icon(SNAME("Help")), TTR("Open Documentation"), MENU_OPEN_DOCS);
+ add_child(menu);
+ menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorInspectorCategory::_handle_menu_option));
+ }
+ menu->set_item_disabled(menu->get_item_index(MENU_OPEN_DOCS), !EditorHelp::get_doc_data()->class_list.has(doc_class_name));
+ }
menu->set_position(get_screen_position() + mb_event->get_position());
menu->reset_size();
menu->popup();
}
-EditorInspectorCategory::EditorInspectorCategory() {
- menu = memnew(PopupMenu);
- menu->connect(SceneStringName(id_pressed), callable_mp(this, &EditorInspectorCategory::_handle_menu_option));
- menu->add_item(TTR("Open Documentation"), MENU_OPEN_DOCS);
- add_child(menu);
-}
-
////////////////////////////////////////////////
////////////////////////////////////////////////
@@ -1622,6 +1666,10 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
}
}
+String EditorInspectorSection::get_section() const {
+ return section;
+}
+
VBoxContainer *EditorInspectorSection::get_vbox() {
return vbox;
}
@@ -2234,7 +2282,7 @@ void EditorInspectorArray::_setup() {
if (element_position > 0) {
ae.move_up = memnew(Button);
- ae.move_up->set_icon(get_editor_theme_icon(SNAME("MoveUp")));
+ ae.move_up->set_button_icon(get_editor_theme_icon(SNAME("MoveUp")));
ae.move_up->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_move_element).bind(element_position, element_position - 1));
move_vbox->add_child(ae.move_up);
}
@@ -2250,7 +2298,7 @@ void EditorInspectorArray::_setup() {
if (element_position < count - 1) {
ae.move_down = memnew(Button);
- ae.move_down->set_icon(get_editor_theme_icon(SNAME("MoveDown")));
+ ae.move_down->set_button_icon(get_editor_theme_icon(SNAME("MoveDown")));
ae.move_down->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_move_element).bind(element_position, element_position + 2));
move_vbox->add_child(ae.move_down);
}
@@ -2273,7 +2321,7 @@ void EditorInspectorArray::_setup() {
ae.hbox->add_child(ae.vbox);
ae.erase = memnew(Button);
- ae.erase->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ ae.erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
ae.erase->set_v_size_flags(SIZE_SHRINK_CENTER);
ae.erase->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_remove_item).bind(element_position));
ae.hbox->add_child(ae.erase);
@@ -2355,10 +2403,10 @@ void EditorInspectorArray::_notification(int p_what) {
ae.move_texture_rect->set_texture(get_editor_theme_icon(SNAME("TripleBar")));
}
if (ae.move_up) {
- ae.move_up->set_icon(get_editor_theme_icon(SNAME("MoveUp")));
+ ae.move_up->set_button_icon(get_editor_theme_icon(SNAME("MoveUp")));
}
if (ae.move_down) {
- ae.move_down->set_icon(get_editor_theme_icon(SNAME("MoveDown")));
+ ae.move_down->set_button_icon(get_editor_theme_icon(SNAME("MoveDown")));
}
Size2 min_size = get_theme_stylebox(SNAME("Focus"), EditorStringName(EditorStyles))->get_minimum_size();
ae.margin->begin_bulk_theme_override();
@@ -2369,11 +2417,11 @@ void EditorInspectorArray::_notification(int p_what) {
ae.margin->end_bulk_theme_override();
if (ae.erase) {
- ae.erase->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ ae.erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
}
}
- add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
update_minimum_size();
} break;
@@ -2542,10 +2590,10 @@ void EditorPaginator::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- first_page_button->set_icon(get_editor_theme_icon(SNAME("PageFirst")));
- prev_page_button->set_icon(get_editor_theme_icon(SNAME("PagePrevious")));
- next_page_button->set_icon(get_editor_theme_icon(SNAME("PageNext")));
- last_page_button->set_icon(get_editor_theme_icon(SNAME("PageLast")));
+ first_page_button->set_button_icon(get_editor_theme_icon(SNAME("PageFirst")));
+ prev_page_button->set_button_icon(get_editor_theme_icon(SNAME("PagePrevious")));
+ next_page_button->set_button_icon(get_editor_theme_icon(SNAME("PageNext")));
+ last_page_button->set_button_icon(get_editor_theme_icon(SNAME("PageLast")));
} break;
}
}
@@ -2675,7 +2723,13 @@ String EditorInspector::get_selected_path() const {
void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorInspectorSection *p_section, Ref<EditorInspectorPlugin> ped) {
for (const EditorInspectorPlugin::AddedEditor &F : ped->added_editors) {
EditorProperty *ep = Object::cast_to<EditorProperty>(F.property_editor);
- current_vbox->add_child(F.property_editor);
+
+ if (ep && current_favorites.has(F.properties[0])) {
+ ep->favorited = true;
+ favorites_vbox->add_child(F.property_editor);
+ } else {
+ current_vbox->add_child(F.property_editor);
+ }
if (ep) {
ep->object = object;
@@ -2684,6 +2738,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
ep->connect("property_deleted", callable_mp(this, &EditorInspector::_property_deleted), CONNECT_DEFERRED);
ep->connect("property_keyed_with_value", callable_mp(this, &EditorInspector::_property_keyed_with_value));
ep->connect("property_checked", callable_mp(this, &EditorInspector::_property_checked));
+ ep->connect("property_favorited", callable_mp(this, &EditorInspector::_set_property_favorited), CONNECT_DEFERRED);
ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned));
ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected));
ep->connect("multiple_properties_changed", callable_mp(this, &EditorInspector::_multiple_properties_changed));
@@ -2727,7 +2782,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
ep->set_read_only(read_only);
ep->update_property();
- ep->_update_pin_flags();
+ ep->_update_flags();
ep->update_editor_property_status();
ep->set_deletable(deletable_properties);
ep->update_cache();
@@ -2837,6 +2892,7 @@ void EditorInspector::update_tree() {
String subgroup;
String subgroup_base;
int section_depth = 0;
+ bool disable_favorite = false;
VBoxContainer *category_vbox = nullptr;
List<PropertyInfo> plist;
@@ -2844,13 +2900,17 @@ void EditorInspector::update_tree() {
HashMap<VBoxContainer *, HashMap<String, VBoxContainer *>> vbox_per_path;
HashMap<String, EditorInspectorArray *> editor_inspector_array_per_prefix;
+ HashMap<String, HashMap<String, LocalVector<EditorProperty *>>> favorites_to_add;
Color sscolor = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
// Get the lists of editors to add the beginning.
for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
ped->parse_begin(object);
- _parse_added_editors(main_vbox, nullptr, ped);
+ _parse_added_editors(begin_vbox, nullptr, ped);
+ }
+ if (begin_vbox->get_child_count()) {
+ begin_vbox->show();
}
StringName doc_name;
@@ -2897,6 +2957,7 @@ void EditorInspector::update_tree() {
subgroup = "";
subgroup_base = "";
section_depth = 0;
+ disable_favorite = false;
vbox_per_path.clear();
editor_inspector_array_per_prefix.clear();
@@ -2960,6 +3021,11 @@ void EditorInspector::update_tree() {
} else {
category_icon = EditorNode::get_singleton()->get_object_icon(scr.ptr(), "Object");
}
+
+ // Property favorites aren't compatible with built-in scripts.
+ if (scr->is_built_in()) {
+ disable_favorite = true;
+ }
}
}
@@ -3058,6 +3124,11 @@ void EditorInspector::update_tree() {
}
}
+ // Don't allow to favorite array items.
+ if (!disable_favorite) {
+ disable_favorite = !array_prefix.is_empty();
+ }
+
if (!array_prefix.is_empty()) {
path = path.trim_prefix(array_prefix);
int char_index = path.find("/");
@@ -3449,6 +3520,7 @@ void EditorInspector::update_tree() {
ep->set_draw_warning(draw_warning);
ep->set_use_folding(use_folding);
+ ep->set_favoritable(can_favorite && !disable_favorite);
ep->set_checkable(checkable);
ep->set_checked(checked);
ep->set_keying(keying);
@@ -3456,7 +3528,12 @@ void EditorInspector::update_tree() {
ep->set_deletable(deletable_properties || p.name.begins_with("metadata/"));
}
- current_vbox->add_child(editors[i].property_editor);
+ if (ep && ep->is_favoritable() && current_favorites.has(p.name)) {
+ ep->favorited = true;
+ favorites_to_add[group][subgroup].push_back(ep);
+ } else {
+ current_vbox->add_child(editors[i].property_editor);
+ }
if (ep) {
// Eventually, set other properties/signals after the property editor got added to the tree.
@@ -3465,6 +3542,7 @@ void EditorInspector::update_tree() {
ep->connect("property_keyed", callable_mp(this, &EditorInspector::_property_keyed));
ep->connect("property_deleted", callable_mp(this, &EditorInspector::_property_deleted), CONNECT_DEFERRED);
ep->connect("property_keyed_with_value", callable_mp(this, &EditorInspector::_property_keyed_with_value));
+ ep->connect("property_favorited", callable_mp(this, &EditorInspector::_set_property_favorited), CONNECT_DEFERRED);
ep->connect("property_checked", callable_mp(this, &EditorInspector::_property_checked));
ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned));
ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected));
@@ -3495,7 +3573,7 @@ void EditorInspector::update_tree() {
ep->set_internal(p.usage & PROPERTY_USAGE_INTERNAL);
ep->update_property();
- ep->_update_pin_flags();
+ ep->_update_flags();
ep->update_editor_property_status();
ep->update_cache();
@@ -3506,6 +3584,79 @@ void EditorInspector::update_tree() {
}
}
+ if (!current_favorites.is_empty()) {
+ favorites_section->show();
+
+ // Organize the favorited properties in their sections, to keep context and differentiate from others with the same name.
+ bool is_localized = property_name_style == EditorPropertyNameProcessor::STYLE_LOCALIZED;
+ for (const KeyValue<String, HashMap<String, LocalVector<EditorProperty *>>> &KV : favorites_to_add) {
+ String section_name = KV.key;
+ String label;
+ String tooltip;
+ VBoxContainer *parent_vbox = favorites_vbox;
+ if (!section_name.is_empty()) {
+ if (is_localized) {
+ label = EditorPropertyNameProcessor::get_singleton()->translate_group_name(section_name);
+ tooltip = section_name;
+ } else {
+ label = section_name;
+ tooltip = EditorPropertyNameProcessor::get_singleton()->translate_group_name(section_name);
+ }
+
+ EditorInspectorSection *section = memnew(EditorInspectorSection);
+ favorites_groups_vbox->add_child(section);
+ parent_vbox = section->get_vbox();
+ section->setup("", section_name, object, sscolor, false);
+ section->set_tooltip_text(tooltip);
+ }
+
+ for (const KeyValue<String, LocalVector<EditorProperty *>> &KV2 : KV.value) {
+ section_name = KV2.key;
+ VBoxContainer *vbox = parent_vbox;
+ if (!section_name.is_empty()) {
+ if (is_localized) {
+ label = EditorPropertyNameProcessor::get_singleton()->translate_group_name(section_name);
+ tooltip = section_name;
+ } else {
+ label = section_name;
+ tooltip = EditorPropertyNameProcessor::get_singleton()->translate_group_name(section_name);
+ }
+
+ EditorInspectorSection *section = memnew(EditorInspectorSection);
+ vbox->add_child(section);
+ vbox = section->get_vbox();
+ section->setup("", section_name, object, sscolor, false);
+ section->set_tooltip_text(tooltip);
+ }
+
+ for (EditorProperty *ep : KV2.value) {
+ vbox->add_child(ep);
+ }
+ }
+ }
+
+ // Show a separator if there's no category to clearly divide the properties.
+ favorites_separator->hide();
+ if (main_vbox->get_child_count() > 0) {
+ EditorInspectorCategory *category = Object::cast_to<EditorInspectorCategory>(main_vbox->get_child(0));
+ if (!category) {
+ favorites_separator->show();
+ }
+ }
+
+ // Clean up empty sections.
+ for (List<EditorInspectorSection *>::Element *I = sections.back(); I; I = I->prev()) {
+ EditorInspectorSection *section = I->get();
+ if (section->get_vbox()->get_child_count() == 0) {
+ I = I->prev();
+
+ sections.erase(section);
+ vbox_per_path[main_vbox].erase(section->get_section());
+ memdelete(section);
+ }
+ }
+ }
+
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);
@@ -3513,7 +3664,7 @@ void EditorInspector::update_tree() {
main_vbox->add_child(spacer);
Button *add_md = EditorInspector::create_inspector_action_button(TTR("Add Metadata"));
- add_md->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_md->set_button_icon(get_editor_theme_icon(SNAME("Add")));
add_md->connect(SceneStringName(pressed), callable_mp(this, &EditorInspector::_show_add_meta_dialog));
main_vbox->add_child(add_md);
if (all_read_only) {
@@ -3548,6 +3699,19 @@ void EditorInspector::update_property(const String &p_prop) {
}
void EditorInspector::_clear(bool p_hide_plugins) {
+ begin_vbox->hide();
+ while (begin_vbox->get_child_count()) {
+ memdelete(begin_vbox->get_child(0));
+ }
+
+ favorites_section->hide();
+ while (favorites_vbox->get_child_count()) {
+ memdelete(favorites_vbox->get_child(0));
+ }
+ while (favorites_groups_vbox->get_child_count()) {
+ memdelete(favorites_groups_vbox->get_child(0));
+ }
+
while (main_vbox->get_child_count()) {
memdelete(main_vbox->get_child(0));
}
@@ -3594,6 +3758,10 @@ void EditorInspector::edit(Object *p_object) {
update_scroll_request = scroll_cache[object->get_instance_id()]; //done this way because wait until full size is accommodated
}
object->connect(CoreStringName(property_list_changed), callable_mp(this, &EditorInspector::_changed_callback));
+
+ can_favorite = Object::cast_to<Node>(object) || Object::cast_to<Resource>(object);
+ _update_current_favorites();
+
update_tree();
}
@@ -4088,10 +4256,164 @@ void EditorInspector::_node_removed(Node *p_node) {
}
}
+void EditorInspector::_update_current_favorites() {
+ current_favorites.clear();
+ if (!can_favorite) {
+ return;
+ }
+
+ HashMap<String, PackedStringArray> favorites = EditorSettings::get_singleton()->get_favorite_properties();
+
+ // Fetch script properties.
+ Ref<Script> scr = object->get_script();
+ if (scr.is_valid()) {
+ List<PropertyInfo> plist;
+ // FIXME: Only properties from a saved script will be available, unsaved ones will be ignored.
+ // Can cause a little wonkiness, while nothing serious, would be nice to find a way to get
+ // unsaved ones without needing to get the entire property list of an object.
+ scr->get_script_property_list(&plist);
+
+ String path;
+ HashMap<String, LocalVector<String>> props;
+
+ for (PropertyInfo &p : plist) {
+ if (p.usage & PROPERTY_USAGE_CATEGORY) {
+ path = favorites.has(p.hint_string) ? p.hint_string : String();
+ } else if (p.usage & PROPERTY_USAGE_SCRIPT_VARIABLE && !path.is_empty()) {
+ props[path].push_back(p.name);
+ }
+ }
+
+ // Add favorited properties while removing invalid ones.
+ bool invalid_props = false;
+ for (const KeyValue<String, LocalVector<String>> &KV : props) {
+ path = KV.key;
+ for (int i = 0; i < favorites[path].size(); i++) {
+ String prop = favorites[path][i];
+ if (KV.value.has(prop)) {
+ current_favorites.append(prop);
+ } else {
+ invalid_props = true;
+ favorites[path].erase(prop);
+ i--;
+ }
+ }
+
+ if (favorites[path].is_empty()) {
+ favorites.erase(path);
+ }
+ }
+
+ if (invalid_props) {
+ EditorSettings::get_singleton()->set_favorite_properties(favorites);
+ }
+ }
+
+ // Fetch built-in properties.
+ StringName class_name = object->get_class_name();
+ for (const KeyValue<String, PackedStringArray> &KV : favorites) {
+ if (ClassDB::is_parent_class(class_name, KV.key)) {
+ current_favorites.append_array(KV.value);
+ }
+ }
+}
+
+void EditorInspector::_set_property_favorited(const String &p_path, bool p_favorited) {
+ if (!object) {
+ return;
+ }
+
+ StringName class_name = object->get_class_name();
+ while (!class_name.is_empty()) {
+ bool has_prop = ClassDB::has_property(class_name, p_path, true);
+ if (has_prop) {
+ break;
+ }
+
+ class_name = ClassDB::get_parent_class_nocheck(class_name);
+ }
+
+ if (class_name.is_empty()) {
+ Ref<Script> scr = object->get_script();
+ if (scr.is_valid()) {
+ List<PropertyInfo> plist;
+ scr->get_script_property_list(&plist);
+
+ String path;
+ for (PropertyInfo &p : plist) {
+ if (p.usage & PROPERTY_USAGE_CATEGORY) {
+ path = p.hint_string;
+ } else if (p.usage & PROPERTY_USAGE_SCRIPT_VARIABLE && p.name == p_path) {
+ class_name = path;
+ break;
+ }
+ }
+ }
+
+ ERR_FAIL_COND_MSG(class_name.is_empty(), "Can't favorite invalid property. If said property was from a script and recently renamed, try saving it first.");
+ }
+
+ HashMap<String, PackedStringArray> favorites = EditorSettings::get_singleton()->get_favorite_properties();
+ if (p_favorited) {
+ current_favorites.append(p_path);
+ favorites[class_name].append(p_path);
+ } else {
+ current_favorites.erase(p_path);
+
+ if (favorites.has(class_name) && favorites[class_name].has(p_path)) {
+ if (favorites[class_name].size() > 1) {
+ favorites[class_name].erase(p_path);
+ } else {
+ favorites.erase(class_name);
+ }
+ }
+ }
+ EditorSettings::get_singleton()->set_favorite_properties(favorites);
+
+ update_tree();
+}
+
+void EditorInspector::_clear_current_favorites() {
+ current_favorites.clear();
+
+ HashMap<String, PackedStringArray> favorites = EditorSettings::get_singleton()->get_favorite_properties();
+
+ Ref<Script> scr = object->get_script();
+ if (scr.is_valid()) {
+ List<PropertyInfo> plist;
+ scr->get_script_property_list(&plist);
+
+ for (PropertyInfo &p : plist) {
+ if (p.usage & PROPERTY_USAGE_CATEGORY && favorites.has(p.hint_string)) {
+ favorites.erase(p.hint_string);
+ }
+ }
+ }
+
+ StringName class_name = object->get_class_name();
+ while (class_name) {
+ if (favorites.has(class_name)) {
+ favorites.erase(class_name);
+ }
+
+ class_name = ClassDB::get_parent_class(class_name);
+ }
+
+ EditorSettings::get_singleton()->set_favorite_properties(favorites);
+ update_tree();
+}
+
void EditorInspector::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- main_vbox->add_theme_constant_override("separation", get_theme_constant(SNAME("v_separation"), SNAME("EditorInspector")));
+ favorites_category->icon = get_editor_theme_icon(SNAME("Favorites"));
+
+ int separation = get_theme_constant(SNAME("v_separation"), SNAME("EditorInspector"));
+ base_vbox->add_theme_constant_override("separation", separation);
+ begin_vbox->add_theme_constant_override("separation", separation);
+ favorites_section->add_theme_constant_override("separation", separation);
+ favorites_groups_vbox->add_theme_constant_override("separation", separation);
+ main_vbox->add_theme_constant_override("separation", separation);
} break;
case NOTIFICATION_READY: {
@@ -4189,6 +4511,7 @@ void EditorInspector::_notification(int p_what) {
void EditorInspector::_changed_callback() {
//this is called when property change is notified via notify_property_list_changed()
if (object != nullptr) {
+ _update_current_favorites();
_edit_request_change(object, String());
}
}
@@ -4278,6 +4601,14 @@ void EditorInspector::_add_meta_confirm() {
undo_redo->commit_action();
}
+void EditorInspector::_handle_menu_option(int p_option) {
+ switch (p_option) {
+ case MENU_UNFAVORITE_ALL:
+ _clear_current_favorites();
+ break;
+ }
+}
+
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
ClassDB::bind_method("get_selected_path", &EditorInspector::get_selected_path);
@@ -4296,9 +4627,36 @@ void EditorInspector::_bind_methods() {
EditorInspector::EditorInspector() {
object = nullptr;
+
+ base_vbox = memnew(VBoxContainer);
+ base_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(base_vbox);
+
+ begin_vbox = memnew(VBoxContainer);
+ base_vbox->add_child(begin_vbox);
+ begin_vbox->hide();
+
+ favorites_section = memnew(VBoxContainer);
+ base_vbox->add_child(favorites_section);
+ favorites_section->hide();
+
+ favorites_category = memnew(EditorInspectorCategory);
+ favorites_category->set_as_favorite(this);
+ favorites_section->add_child(favorites_category);
+ favorites_category->label = TTR("Favorites");
+
+ favorites_vbox = memnew(VBoxContainer);
+ favorites_section->add_child(favorites_vbox);
+ favorites_groups_vbox = memnew(VBoxContainer);
+ favorites_section->add_child(favorites_groups_vbox);
+
+ favorites_separator = memnew(HSeparator);
+ favorites_section->add_child(favorites_separator);
+ favorites_separator->hide();
+
main_vbox = memnew(VBoxContainer);
- main_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
- add_child(main_vbox);
+ base_vbox->add_child(main_vbox);
+
set_horizontal_scroll_mode(SCROLL_MODE_DISABLED);
set_follow_focus(true);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 0309213b76..2e4633ccea 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -41,6 +41,7 @@ class Button;
class ConfirmationDialog;
class EditorInspector;
class EditorValidationPanel;
+class HSeparator;
class LineEdit;
class MarginContainer;
class OptionButton;
@@ -64,6 +65,7 @@ public:
MENU_COPY_VALUE,
MENU_PASTE_VALUE,
MENU_COPY_PROPERTY_PATH,
+ MENU_FAVORITE_PROPERTY,
MENU_PIN_VALUE,
MENU_OPEN_DOCUMENTATION,
};
@@ -112,6 +114,9 @@ private:
bool pin_hidden = false;
bool pinned = false;
+ bool can_favorite = false;
+ bool favorited = false;
+
bool use_folding = false;
bool draw_top_bg = true;
@@ -134,7 +139,7 @@ private:
GDVIRTUAL0(_update_property)
GDVIRTUAL1(_set_read_only, bool)
- void _update_pin_flags();
+ void _update_flags();
protected:
bool has_borders = false;
@@ -218,6 +223,9 @@ public:
void set_name_split_ratio(float p_ratio);
float get_name_split_ratio() const;
+ void set_favoritable(bool p_favoritable);
+ bool is_favoritable() const;
+
void set_object_and_property(Object *p_object, const StringName &p_property);
virtual Control *make_custom_tooltip(const String &p_text) const override;
@@ -285,6 +293,7 @@ class EditorInspectorCategory : public Control {
String label;
String doc_class_name;
PopupMenu *menu = nullptr;
+ bool is_favorite = false;
void _handle_menu_option(int p_option);
@@ -293,10 +302,10 @@ protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
public:
+ void set_as_favorite(EditorInspector *p_for_inspector);
+
virtual Size2 get_minimum_size() const override;
virtual Control *make_custom_tooltip(const String &p_text) const override;
-
- EditorInspectorCategory();
};
class EditorInspectorSection : public Container {
@@ -331,6 +340,7 @@ public:
virtual Size2 get_minimum_size() const override;
void setup(const String &p_section, const String &p_label, Object *p_object, const Color &p_bg_color, bool p_foldable, int p_indent_depth = 0, int p_level = 1);
+ String get_section() const;
VBoxContainer *get_vbox();
void unfold();
void fold();
@@ -480,13 +490,31 @@ public:
class EditorInspector : public ScrollContainer {
GDCLASS(EditorInspector, ScrollContainer);
+ friend class EditorInspectorCategory;
+
enum {
MAX_PLUGINS = 1024
};
static Ref<EditorInspectorPlugin> inspector_plugins[MAX_PLUGINS];
static int inspector_plugin_count;
+ // Right-click context menu options.
+ enum ClassMenuOption {
+ MENU_UNFAVORITE_ALL,
+ };
+
+ bool can_favorite = false;
+ PackedStringArray current_favorites;
+ VBoxContainer *favorites_section = nullptr;
+ EditorInspectorCategory *favorites_category = nullptr;
+ VBoxContainer *favorites_vbox = nullptr;
+ VBoxContainer *favorites_groups_vbox = nullptr;
+ HSeparator *favorites_separator = nullptr;
+
EditorInspector *root_inspector = nullptr;
+
+ VBoxContainer *base_vbox = nullptr;
+ VBoxContainer *begin_vbox = nullptr;
VBoxContainer *main_vbox = nullptr;
// Map used to cache the instantiated editors.
@@ -557,6 +585,10 @@ class EditorInspector : public ScrollContainer {
void _property_selected(const String &p_path, int p_focusable);
void _object_id_selected(const String &p_path, ObjectID p_id);
+ void _update_current_favorites();
+ void _set_property_favorited(const String &p_path, bool p_favorited);
+ void _clear_current_favorites();
+
void _node_removed(Node *p_node);
HashMap<StringName, int> per_array_page;
@@ -584,6 +616,8 @@ class EditorInspector : public ScrollContainer {
void _add_meta_confirm();
void _show_add_meta_dialog();
+ void _handle_menu_option(int p_option);
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp
index 264c80dcbf..304b9d4b8c 100644
--- a/editor/editor_interface.cpp
+++ b/editor/editor_interface.cpp
@@ -337,6 +337,19 @@ void EditorInterface::popup_property_selector(Object *p_object, const Callable &
property_selector->connect(SNAME("canceled"), canceled_callback, CONNECT_DEFERRED);
}
+void EditorInterface::popup_method_selector(Object *p_object, const Callable &p_callback, const String &p_current_value) {
+ if (!method_selector) {
+ method_selector = memnew(PropertySelector);
+ get_base_control()->add_child(method_selector);
+ }
+
+ method_selector->select_method_from_instance(p_object, p_current_value);
+
+ const Callable callback = callable_mp(this, &EditorInterface::_method_selected);
+ method_selector->connect(SNAME("selected"), callback.bind(p_callback), CONNECT_DEFERRED);
+ method_selector->connect(SNAME("canceled"), callback.bind(String(), p_callback), CONNECT_DEFERRED);
+}
+
void EditorInterface::popup_quick_open(const Callable &p_callback, const TypedArray<StringName> &p_base_types) {
StringName required_type = SNAME("Resource");
Vector<StringName> base_types;
@@ -372,6 +385,18 @@ void EditorInterface::_property_selection_canceled(const Callable &p_callback) {
_call_dialog_callback(p_callback, NodePath(), "property selection canceled");
}
+void EditorInterface::_method_selected(const String &p_method_name, const Callable &p_callback) {
+ const Callable callback = callable_mp(this, &EditorInterface::_method_selected);
+ method_selector->disconnect(SNAME("selected"), callback);
+ method_selector->disconnect(SNAME("canceled"), callback);
+
+ if (p_method_name.is_empty()) {
+ _call_dialog_callback(p_callback, p_method_name, "method selection canceled");
+ } else {
+ _call_dialog_callback(p_callback, p_method_name, "method selected");
+ }
+}
+
void EditorInterface::_quick_open(const String &p_file_path, const Callable &p_callback) {
EditorQuickOpenDialog *quick_open = EditorNode::get_singleton()->get_quick_open_dialog();
quick_open->disconnect(SNAME("canceled"), callable_mp(this, &EditorInterface::_quick_open));
@@ -593,6 +618,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("popup_node_selector", "callback", "valid_types", "current_value"), &EditorInterface::popup_node_selector, DEFVAL(TypedArray<StringName>()), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("popup_property_selector", "object", "callback", "type_filter", "current_value"), &EditorInterface::popup_property_selector, DEFVAL(PackedInt32Array()), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("popup_method_selector", "object", "callback", "current_value"), &EditorInterface::popup_method_selector, DEFVAL(String()));
ClassDB::bind_method(D_METHOD("popup_quick_open", "callback", "base_types"), &EditorInterface::popup_quick_open, DEFVAL(TypedArray<StringName>()));
// Editor docks.
diff --git a/editor/editor_interface.h b/editor/editor_interface.h
index 4877444dac..c1032bf9b6 100644
--- a/editor/editor_interface.h
+++ b/editor/editor_interface.h
@@ -66,12 +66,14 @@ class EditorInterface : public Object {
// Editor dialogs.
PropertySelector *property_selector = nullptr;
+ PropertySelector *method_selector = nullptr;
SceneTreeDialog *node_selector = nullptr;
void _node_selected(const NodePath &p_node_paths, const Callable &p_callback);
void _node_selection_canceled(const Callable &p_callback);
void _property_selected(const String &p_property_name, const Callable &p_callback);
void _property_selection_canceled(const Callable &p_callback);
+ void _method_selected(const String &p_property_name, const Callable &p_callback);
void _quick_open(const String &p_file_path, const Callable &p_callback);
void _call_dialog_callback(const Callable &p_callback, const Variant &p_selected, const String &p_context);
@@ -139,6 +141,7 @@ public:
void popup_node_selector(const Callable &p_callback, const TypedArray<StringName> &p_valid_types = TypedArray<StringName>(), Node *p_current_value = nullptr);
// Must use Vector<int> because exposing Vector<Variant::Type> is not supported.
void popup_property_selector(Object *p_object, const Callable &p_callback, const PackedInt32Array &p_type_filter = PackedInt32Array(), const String &p_current_value = String());
+ void popup_method_selector(Object *p_object, const Callable &p_callback, const String &p_current_value = String());
void popup_quick_open(const Callable &p_callback, const TypedArray<StringName> &p_base_types = TypedArray<StringName>());
// Editor docks.
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index aec374929e..db26a75cb8 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -100,20 +100,20 @@ void EditorLog::_update_theme() {
log->add_theme_font_size_override("mono_font_size", font_size);
log->end_bulk_theme_override();
- type_filter_map[MSG_TYPE_STD]->toggle_button->set_icon(get_editor_theme_icon(SNAME("Popup")));
- type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_icon(get_editor_theme_icon(SNAME("StatusError")));
- type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_icon(get_editor_theme_icon(SNAME("StatusWarning")));
- type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ type_filter_map[MSG_TYPE_STD]->toggle_button->set_button_icon(get_editor_theme_icon(SNAME("Popup")));
+ type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_button_icon(get_editor_theme_icon(SNAME("StatusError")));
+ type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_button_icon(get_editor_theme_icon(SNAME("StatusWarning")));
+ type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
type_filter_map[MSG_TYPE_STD]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_theme_type_variation("EditorLogFilterButton");
- clear_button->set_icon(get_editor_theme_icon(SNAME("Clear")));
- copy_button->set_icon(get_editor_theme_icon(SNAME("ActionCopy")));
- collapse_button->set_icon(get_editor_theme_icon(SNAME("CombineLines")));
- show_search_button->set_icon(get_editor_theme_icon(SNAME("Search")));
+ clear_button->set_button_icon(get_editor_theme_icon(SNAME("Clear")));
+ copy_button->set_button_icon(get_editor_theme_icon(SNAME("ActionCopy")));
+ collapse_button->set_button_icon(get_editor_theme_icon(SNAME("CombineLines")));
+ show_search_button->set_button_icon(get_editor_theme_icon(SNAME("Search")));
search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
theme_cache.error_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
@@ -204,7 +204,7 @@ void EditorLog::_clear_request() {
log->clear();
messages.clear();
_reset_message_counts();
- tool_button->set_icon(Ref<Texture2D>());
+ tool_button->set_button_icon(Ref<Texture2D>());
}
void EditorLog::_copy_request() {
@@ -359,14 +359,14 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
Ref<Texture2D> icon = theme_cache.error_icon;
log->add_image(icon);
log->add_text(" ");
- tool_button->set_icon(icon);
+ tool_button->set_button_icon(icon);
} break;
case MSG_TYPE_WARNING: {
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);
+ tool_button->set_button_icon(icon);
} break;
case MSG_TYPE_EDITOR: {
// Distinguish editor messages from messages printed by the project
diff --git a/editor/editor_main_screen.cpp b/editor/editor_main_screen.cpp
index 77bbee5a7f..6da2bce60e 100644
--- a/editor/editor_main_screen.cpp
+++ b/editor/editor_main_screen.cpp
@@ -66,9 +66,9 @@ void EditorMainScreen::_notification(int p_what) {
Ref<Texture2D> icon = p_editor->get_icon();
if (icon.is_valid()) {
- tb->set_icon(icon);
+ tb->set_button_icon(icon);
} else if (has_theme_icon(p_editor->get_name(), EditorStringName(EditorIcons))) {
- tb->set_icon(get_theme_icon(p_editor->get_name(), EditorStringName(EditorIcons)));
+ tb->set_button_icon(get_theme_icon(p_editor->get_name(), EditorStringName(EditorIcons)));
}
}
} break;
@@ -244,7 +244,7 @@ void EditorMainScreen::add_main_plugin(EditorPlugin *p_editor) {
icon = get_editor_theme_icon(p_editor->get_name());
}
if (icon.is_valid()) {
- tb->set_icon(icon);
+ tb->set_button_icon(icon);
// Make sure the control is updated if the icon is reimported.
icon->connect_changed(callable_mp((Control *)tb, &Control::update_minimum_size));
}
diff --git a/editor/editor_main_screen.h b/editor/editor_main_screen.h
index 153a182bc2..ca78ceaa88 100644
--- a/editor/editor_main_screen.h
+++ b/editor/editor_main_screen.h
@@ -47,6 +47,7 @@ public:
EDITOR_2D = 0,
EDITOR_3D,
EDITOR_SCRIPT,
+ EDITOR_GAME,
EDITOR_ASSETLIB,
};
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index f328b9fc91..f8e23ecc9d 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -145,6 +145,7 @@
#include "editor/plugins/editor_plugin.h"
#include "editor/plugins/editor_preview_plugins.h"
#include "editor/plugins/editor_resource_conversion_plugin.h"
+#include "editor/plugins/game_view_plugin.h"
#include "editor/plugins/gdextension_export_plugin.h"
#include "editor/plugins/material_editor_plugin.h"
#include "editor/plugins/mesh_library_editor_plugin.h"
@@ -357,6 +358,8 @@ void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) {
editor_main_screen->select(EditorMainScreen::EDITOR_3D);
} else if (ED_IS_SHORTCUT("editor/editor_script", p_event)) {
editor_main_screen->select(EditorMainScreen::EDITOR_SCRIPT);
+ } else if (ED_IS_SHORTCUT("editor/editor_game", p_event)) {
+ editor_main_screen->select(EditorMainScreen::EDITOR_GAME);
} else if (ED_IS_SHORTCUT("editor/editor_help", p_event)) {
emit_signal(SNAME("request_help_search"), "");
} else if (ED_IS_SHORTCUT("editor/editor_assetlib", p_event) && AssetLibraryEditorPlugin::is_available()) {
@@ -532,7 +535,7 @@ void EditorNode::_update_theme(bool p_skip_creation) {
editor_main_screen->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles)));
bottom_panel->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
- distraction_free->set_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons)));
+ distraction_free->set_button_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons)));
distraction_free->add_theme_style_override(SceneStringName(pressed), theme->get_stylebox(CoreStringName(normal), "FlatMenuButton"));
help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), theme->get_icon(SNAME("HelpSearch"), EditorStringName(EditorIcons)));
@@ -621,7 +624,7 @@ void EditorNode::_notification(int p_what) {
// Update the icon itself only when the spinner is visible.
if (_should_display_update_spinner()) {
- update_spinner->set_icon(theme->get_icon("Progress" + itos(update_spinner_step + 1), EditorStringName(EditorIcons)));
+ update_spinner->set_button_icon(theme->get_icon("Progress" + itos(update_spinner_step + 1), EditorStringName(EditorIcons)));
}
}
@@ -2150,7 +2153,7 @@ void EditorNode::_dialog_action(String p_file) {
}
if (ml.is_null()) {
- ml = Ref<MeshLibrary>(memnew(MeshLibrary));
+ ml.instantiate();
}
MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, merge_with_existing_library, apply_mesh_instance_transforms);
@@ -3379,6 +3382,8 @@ void EditorNode::unload_editor_addons() {
remove_editor_plugin(E.value, false);
memdelete(E.value);
}
+
+ addon_name_to_plugin.clear();
}
void EditorNode::_discard_changes(const String &p_str) {
@@ -4673,6 +4678,11 @@ void EditorNode::stop_child_process(OS::ProcessID p_pid) {
Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) const {
ERR_FAIL_NULL_V(p_object, nullptr);
+ const Node *node = Object::cast_to<const Node>(p_object);
+ if (node && node->has_meta(SceneStringName(_custom_type_script))) {
+ return node->get_meta(SceneStringName(_custom_type_script));
+ }
+
Ref<Script> scr = p_object->get_script();
if (scr.is_valid()) {
@@ -6570,6 +6580,7 @@ void EditorNode::_feature_profile_changed() {
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_3D, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_SCRIPT, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT));
+ editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_GAME, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_GAME));
if (AssetLibraryEditorPlugin::is_available()) {
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_ASSETLIB, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB));
}
@@ -6580,6 +6591,7 @@ void EditorNode::_feature_profile_changed() {
editor_dock_manager->set_dock_enabled(history_dock, true);
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_3D, true);
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_SCRIPT, true);
+ editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_GAME, true);
if (AssetLibraryEditorPlugin::is_available()) {
editor_main_screen->set_button_enabled(EditorMainScreen::EDITOR_ASSETLIB, true);
}
@@ -7490,7 +7502,7 @@ EditorNode::EditorNode() {
update_spinner = memnew(MenuButton);
right_menu_hb->add_child(update_spinner);
- update_spinner->set_icon(theme->get_icon(SNAME("Progress1"), EditorStringName(EditorIcons)));
+ update_spinner->set_button_icon(theme->get_icon(SNAME("Progress1"), EditorStringName(EditorIcons)));
update_spinner->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option));
PopupMenu *p = update_spinner->get_popup();
p->add_radio_check_item(TTR("Update Continuously"), SETTINGS_UPDATE_CONTINUOUSLY);
@@ -7707,6 +7719,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(CanvasItemEditorPlugin));
add_editor_plugin(memnew(Node3DEditorPlugin));
add_editor_plugin(memnew(ScriptEditorPlugin));
+ add_editor_plugin(memnew(GameViewPlugin));
EditorAudioBuses *audio_bus_editor = EditorAudioBuses::register_editor();
@@ -7889,12 +7902,14 @@ EditorNode::EditorNode() {
ED_SHORTCUT_AND_COMMAND("editor/editor_2d", TTR("Open 2D Editor"), KeyModifierMask::CTRL | Key::F1);
ED_SHORTCUT_AND_COMMAND("editor/editor_3d", TTR("Open 3D Editor"), KeyModifierMask::CTRL | Key::F2);
ED_SHORTCUT_AND_COMMAND("editor/editor_script", TTR("Open Script Editor"), KeyModifierMask::CTRL | Key::F3);
- ED_SHORTCUT_AND_COMMAND("editor/editor_assetlib", TTR("Open Asset Library"), KeyModifierMask::CTRL | Key::F4);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_game", TTR("Open Game View"), KeyModifierMask::CTRL | Key::F4);
+ ED_SHORTCUT_AND_COMMAND("editor/editor_assetlib", TTR("Open Asset Library"), KeyModifierMask::CTRL | Key::F5);
ED_SHORTCUT_OVERRIDE("editor/editor_2d", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_1);
ED_SHORTCUT_OVERRIDE("editor/editor_3d", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_2);
ED_SHORTCUT_OVERRIDE("editor/editor_script", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_3);
- ED_SHORTCUT_OVERRIDE("editor/editor_assetlib", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_4);
+ ED_SHORTCUT_OVERRIDE("editor/editor_game", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_4);
+ ED_SHORTCUT_OVERRIDE("editor/editor_assetlib", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::KEY_5);
ED_SHORTCUT_AND_COMMAND("editor/editor_next", TTR("Open the next Editor"));
ED_SHORTCUT_AND_COMMAND("editor/editor_prev", TTR("Open the previous Editor"));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 696caf857c..49c1699c28 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -789,7 +789,7 @@ public:
struct AdditiveNodeEntry {
Node *node = nullptr;
- NodePath parent = NodePath();
+ NodePath parent;
Node *owner = nullptr;
int index = 0;
// Used if the original parent node is lost
@@ -932,7 +932,7 @@ public:
void dim_editor(bool p_dimming);
bool is_editor_dimmed() const;
- void edit_current() { _edit_current(); };
+ void edit_current() { _edit_current(); }
bool has_scenes_in_session();
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index c5a35e466c..bdb5ed2ed9 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -192,7 +192,7 @@ void EditorPropertyMultilineText::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
Ref<Texture2D> df = get_editor_theme_icon(SNAME("DistractionFree"));
- open_big_text->set_icon(df);
+ open_big_text->set_button_icon(df);
Ref<Font> font;
int font_size;
@@ -340,9 +340,9 @@ void EditorPropertyTextEnum::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- edit_button->set_icon(get_editor_theme_icon(SNAME("Edit")));
- accept_button->set_icon(get_editor_theme_icon(SNAME("ImportCheck")));
- cancel_button->set_icon(get_editor_theme_icon(SNAME("ImportFail")));
+ edit_button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
+ accept_button->set_button_icon(get_editor_theme_icon(SNAME("ImportCheck")));
+ cancel_button->set_button_icon(get_editor_theme_icon(SNAME("ImportFail")));
} break;
}
}
@@ -428,7 +428,7 @@ void EditorPropertyLocale::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- locale_edit->set_icon(get_editor_theme_icon(SNAME("Translation")));
+ locale_edit->set_button_icon(get_editor_theme_icon(SNAME("Translation")));
} break;
}
}
@@ -462,10 +462,26 @@ void EditorPropertyPath::_set_read_only(bool p_read_only) {
}
void EditorPropertyPath::_path_selected(const String &p_path) {
- emit_changed(get_edited_property(), p_path);
+ String full_path = p_path;
+ ResourceUID::ID id = ResourceLoader::get_resource_uid(full_path);
+
+ if (id != ResourceUID::INVALID_ID) {
+ full_path = ResourceUID::get_singleton()->id_to_text(id);
+ }
+
+ emit_changed(get_edited_property(), full_path);
update_property();
}
+String EditorPropertyPath::_get_path_text() {
+ String full_path = get_edited_property_value();
+ if (full_path.begins_with("uid://")) {
+ full_path = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(full_path));
+ }
+
+ return full_path;
+}
+
void EditorPropertyPath::_path_pressed() {
if (!dialog) {
dialog = memnew(EditorFileDialog);
@@ -474,7 +490,7 @@ void EditorPropertyPath::_path_pressed() {
add_child(dialog);
}
- String full_path = get_edited_property_value();
+ String full_path = _get_path_text();
dialog->clear_filters();
@@ -502,7 +518,7 @@ void EditorPropertyPath::_path_pressed() {
}
void EditorPropertyPath::update_property() {
- String full_path = get_edited_property_value();
+ String full_path = _get_path_text();
path->set_text(full_path);
path->set_tooltip_text(full_path);
}
@@ -522,9 +538,9 @@ void EditorPropertyPath::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (folder) {
- path_edit->set_icon(get_editor_theme_icon(SNAME("FolderBrowse")));
+ path_edit->set_button_icon(get_editor_theme_icon(SNAME("FolderBrowse")));
} else {
- path_edit->set_icon(get_editor_theme_icon(SNAME("FileBrowse")));
+ path_edit->set_button_icon(get_editor_theme_icon(SNAME("FileBrowse")));
}
} break;
}
@@ -547,8 +563,7 @@ void EditorPropertyPath::_drop_data_fw(const Point2 &p_point, const Variant &p_d
return;
}
- emit_changed(get_edited_property(), filesPaths[0]);
- update_property();
+ _path_selected(filesPaths[0]);
}
bool EditorPropertyPath::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
@@ -1343,12 +1358,12 @@ void EditorPropertyObjectID::update_property() {
edit->set_text(type + " ID: " + uitos(id));
edit->set_tooltip_text(type + " ID: " + uitos(id));
edit->set_disabled(false);
- edit->set_icon(EditorNode::get_singleton()->get_class_icon(type));
+ edit->set_button_icon(EditorNode::get_singleton()->get_class_icon(type));
} else {
edit->set_text(TTR("<empty>"));
edit->set_tooltip_text("");
edit->set_disabled(true);
- edit->set_icon(Ref<Texture2D>());
+ edit->set_button_icon(Ref<Texture2D>());
}
}
@@ -1378,7 +1393,7 @@ void EditorPropertySignal::update_property() {
edit->set_text("Signal: " + signal.get_name());
edit->set_disabled(false);
- edit->set_icon(get_editor_theme_icon(SNAME("Signals")));
+ edit->set_button_icon(get_editor_theme_icon(SNAME("Signals")));
}
EditorPropertySignal::EditorPropertySignal() {
@@ -1397,7 +1412,7 @@ void EditorPropertyCallable::update_property() {
edit->set_text("Callable");
edit->set_disabled(true);
- edit->set_icon(get_editor_theme_icon(SNAME("Callable")));
+ edit->set_button_icon(get_editor_theme_icon(SNAME("Callable")));
}
EditorPropertyCallable::EditorPropertyCallable() {
@@ -2024,9 +2039,9 @@ void EditorPropertyQuaternion::_notification(int p_what) {
for (int i = 0; i < 3; i++) {
euler[i]->add_theme_color_override("label_color", colors[i]);
}
- edit_button->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ edit_button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
euler_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("property_color"), SNAME("EditorProperty")));
- warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
+ warning->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
warning->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
} break;
}
@@ -2638,7 +2653,7 @@ EditorPropertyColor::EditorPropertyColor() {
void EditorPropertyNodePath::_set_read_only(bool p_read_only) {
assign->set_disabled(p_read_only);
menu->set_disabled(p_read_only);
-};
+}
Variant EditorPropertyNodePath::_get_cache_value(const StringName &p_prop, bool &r_valid) const {
if (p_prop == get_edited_property()) {
@@ -2648,7 +2663,7 @@ Variant EditorPropertyNodePath::_get_cache_value(const StringName &p_prop, bool
return Variant();
}
-void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
+void EditorPropertyNodePath::_node_selected(const NodePath &p_path, bool p_absolute) {
NodePath path = p_path;
Node *base_node = get_base_node();
@@ -2658,7 +2673,7 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
path = get_tree()->get_edited_scene_root()->get_path_to(to_node);
}
- if (base_node) { // for AnimationTrackKeyEdit
+ if (p_absolute && base_node) { // for AnimationTrackKeyEdit
path = base_node->get_path().rel_path_to(p_path);
}
@@ -2680,7 +2695,7 @@ void EditorPropertyNodePath::_node_assign() {
scene_tree->get_scene_tree()->set_show_enabled_subscene(true);
scene_tree->set_valid_types(valid_types);
add_child(scene_tree);
- scene_tree->connect("selected", callable_mp(this, &EditorPropertyNodePath::_node_selected));
+ scene_tree->connect("selected", callable_mp(this, &EditorPropertyNodePath::_node_selected).bind(true));
}
Variant val = get_edited_property_value();
@@ -2748,7 +2763,7 @@ void EditorPropertyNodePath::_accept_text() {
void EditorPropertyNodePath::_text_submitted(const String &p_text) {
NodePath np = p_text;
- emit_changed(get_edited_property(), np);
+ _node_selected(np, false);
edit->hide();
assign->show();
menu->show();
@@ -2829,7 +2844,7 @@ void EditorPropertyNodePath::update_property() {
assign->set_tooltip_text(p);
if (p.is_empty()) {
- assign->set_icon(Ref<Texture2D>());
+ assign->set_button_icon(Ref<Texture2D>());
assign->set_text(TTR("Assign..."));
assign->set_flat(false);
return;
@@ -2837,7 +2852,7 @@ void EditorPropertyNodePath::update_property() {
assign->set_flat(true);
if (!base_node || !base_node->has_node(p)) {
- assign->set_icon(Ref<Texture2D>());
+ assign->set_button_icon(Ref<Texture2D>());
assign->set_text(p);
return;
}
@@ -2846,13 +2861,13 @@ void EditorPropertyNodePath::update_property() {
ERR_FAIL_NULL(target_node);
if (String(target_node->get_name()).contains("@")) {
- assign->set_icon(Ref<Texture2D>());
+ assign->set_button_icon(Ref<Texture2D>());
assign->set_text(p);
return;
}
assign->set_text(target_node->get_name());
- assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node"));
+ assign->set_button_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node"));
}
void EditorPropertyNodePath::setup(const Vector<StringName> &p_valid_types, bool p_use_path_from_scene_root, bool p_editing_node) {
@@ -2865,7 +2880,7 @@ void EditorPropertyNodePath::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
menu->get_popup()->set_item_icon(ACTION_CLEAR, get_editor_theme_icon(SNAME("Clear")));
menu->get_popup()->set_item_icon(ACTION_COPY, get_editor_theme_icon(SNAME("ActionCopy")));
menu->get_popup()->set_item_icon(ACTION_EDIT, get_editor_theme_icon(SNAME("Edit")));
@@ -3221,6 +3236,7 @@ void EditorPropertyResource::setup(Object *p_object, const String &p_path, const
}
resource_picker->set_base_type(p_base_type);
+ resource_picker->set_resource_owner(p_object);
resource_picker->set_editable(true);
resource_picker->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(resource_picker);
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index 004630da3e..ae9c454195 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -142,6 +142,8 @@ class EditorPropertyPath : public EditorProperty {
LineEdit *path = nullptr;
Button *path_edit = nullptr;
+ String _get_path_text();
+
void _path_selected(const String &p_path);
void _path_pressed();
void _path_focus_exited();
@@ -628,7 +630,7 @@ class EditorPropertyNodePath : public EditorProperty {
bool editing_node = false;
Vector<StringName> valid_types;
- void _node_selected(const NodePath &p_path);
+ void _node_selected(const NodePath &p_path, bool p_absolute = true);
void _node_assign();
Node *get_base_node();
void _update_menu();
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index f03eef4d4d..ba6b42f8f5 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -283,7 +283,7 @@ void EditorPropertyArray::_create_new_property_slot() {
HBoxContainer *hbox = memnew(HBoxContainer);
Button *reorder_button = memnew(Button);
- reorder_button->set_icon(get_editor_theme_icon(SNAME("TripleBar")));
+ reorder_button->set_button_icon(get_editor_theme_icon(SNAME("TripleBar")));
reorder_button->set_default_cursor_shape(Control::CURSOR_MOVE);
reorder_button->set_disabled(is_read_only());
reorder_button->connect(SceneStringName(gui_input), callable_mp(this, &EditorPropertyArray::_reorder_button_gui_input));
@@ -298,13 +298,13 @@ void EditorPropertyArray::_create_new_property_slot() {
if (is_untyped_array) {
Button *edit_btn = memnew(Button);
- edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ edit_btn->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
edit_btn->set_disabled(is_read_only());
edit_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_change_type).bind(edit_btn, idx));
hbox->add_child(edit_btn);
} else {
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ remove_btn->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
remove_btn->set_disabled(is_read_only());
remove_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(idx));
hbox->add_child(remove_btn);
@@ -395,7 +395,7 @@ void EditorPropertyArray::update_property() {
vbox->add_child(property_vbox);
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element"));
- button_add_item->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add")));
button_add_item->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyArray::_add_element));
button_add_item->set_disabled(is_read_only());
vbox->add_child(button_add_item);
@@ -657,7 +657,7 @@ void EditorPropertyArray::_notification(int p_what) {
}
if (button_add_item) {
- button_add_item->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add")));
}
} break;
@@ -939,13 +939,13 @@ void EditorPropertyDictionary::_create_new_property_slot(int p_idx) {
if (is_untyped_dict) {
Button *edit_btn = memnew(Button);
- edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ edit_btn->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
edit_btn->set_disabled(is_read_only());
edit_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit_btn, slots.size()));
hbox->add_child(edit_btn);
} else if (p_idx >= 0) {
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ remove_btn->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
remove_btn->set_disabled(is_read_only());
remove_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyDictionary::_remove_pressed).bind(slots.size()));
hbox->add_child(remove_btn);
@@ -1122,7 +1122,7 @@ void EditorPropertyDictionary::update_property() {
_create_new_property_slot(EditorPropertyDictionaryObject::NEW_VALUE_INDEX);
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair"));
- button_add_item->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
+ button_add_item->set_button_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
button_add_item->set_disabled(is_read_only());
button_add_item->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyDictionary::_add_key_value));
add_vbox->add_child(button_add_item);
@@ -1227,7 +1227,7 @@ void EditorPropertyDictionary::_notification(int p_what) {
}
if (button_add_item) {
- button_add_item->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add")));
add_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("DictionaryAddItem")));
}
} break;
@@ -1424,7 +1424,7 @@ void EditorPropertyLocalizableString::update_property() {
hbox->add_child(prop);
prop->set_h_size_flags(SIZE_EXPAND_FILL);
Button *edit_btn = memnew(Button);
- edit_btn->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ edit_btn->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
hbox->add_child(edit_btn);
edit_btn->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyLocalizableString::_remove_item).bind(edit_btn, remove_index));
@@ -1433,7 +1433,7 @@ void EditorPropertyLocalizableString::update_property() {
if (page_index == max_page) {
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Translation"));
- button_add_item->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add")));
button_add_item->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyLocalizableString::_add_locale_popup));
property_vbox->add_child(button_add_item);
}
@@ -1459,7 +1459,7 @@ void EditorPropertyLocalizableString::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
if (button_add_item) {
- button_add_item->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add_item->set_button_icon(get_editor_theme_icon(SNAME("Add")));
}
} break;
}
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index e38ab456cb..ca8854f797 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -198,6 +198,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["gi"] = "GI";
capitalize_string_remaps["gl"] = "GL";
capitalize_string_remaps["glb"] = "GLB";
+ capitalize_string_remaps["gles"] = "GLES";
capitalize_string_remaps["gles2"] = "GLES2";
capitalize_string_remaps["gles3"] = "GLES3";
capitalize_string_remaps["gltf"] = "glTF";
@@ -231,6 +232,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["kb"] = "(KB)"; // Unit.
capitalize_string_remaps["lcd"] = "LCD";
capitalize_string_remaps["ldr"] = "LDR";
+ capitalize_string_remaps["linuxbsd"] = "Linux/*BSD";
capitalize_string_remaps["lod"] = "LOD";
capitalize_string_remaps["lods"] = "LODs";
capitalize_string_remaps["lowpass"] = "Low-pass";
@@ -248,6 +250,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["oidn"] = "OIDN";
capitalize_string_remaps["ok"] = "OK";
capitalize_string_remaps["opengl"] = "OpenGL";
+ capitalize_string_remaps["opengl3"] = "OpenGL 3";
capitalize_string_remaps["opentype"] = "OpenType";
capitalize_string_remaps["openxr"] = "OpenXR";
capitalize_string_remaps["osslsigncode"] = "osslsigncode";
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 0f0287718c..4c3fc7f8c2 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -61,11 +61,11 @@ void EditorResourcePicker::_update_resource() {
assign_button->set_custom_minimum_size(assign_button_min_size);
if (edited_resource == Ref<Resource>()) {
- assign_button->set_icon(Ref<Texture2D>());
+ assign_button->set_button_icon(Ref<Texture2D>());
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->(), SNAME("Object")));
+ assign_button->set_button_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), SNAME("Object")));
if (!edited_resource->get_name().is_empty()) {
assign_button->set_text(edited_resource->get_name());
@@ -103,7 +103,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const
}
if (p_preview.is_valid()) {
- preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox(CoreStringName(normal))->get_content_margin(SIDE_LEFT) + get_theme_constant(SNAME("h_separation"), SNAME("Button")));
+ preview_rect->set_offset(SIDE_LEFT, assign_button->get_button_icon()->get_width() + assign_button->get_theme_stylebox(CoreStringName(normal))->get_content_margin(SIDE_LEFT) + get_theme_constant(SNAME("h_separation"), SNAME("Button")));
// Resource-specific stretching.
if (Ref<GradientTexture1D>(edited_resource).is_valid() || Ref<Gradient>(edited_resource).is_valid()) {
@@ -224,7 +224,9 @@ void EditorResourcePicker::_update_menu_items() {
}
if (is_editable()) {
- edit_menu->add_icon_item(get_editor_theme_icon(SNAME("Clear")), TTR("Clear"), OBJ_MENU_CLEAR);
+ if (!_is_custom_type_script()) {
+ edit_menu->add_icon_item(get_editor_theme_icon(SNAME("Clear")), TTR("Clear"), OBJ_MENU_CLEAR);
+ }
edit_menu->add_icon_item(get_editor_theme_icon(SNAME("Duplicate")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
// Check whether the resource has subresources.
@@ -694,6 +696,16 @@ bool EditorResourcePicker::_is_type_valid(const String &p_type_name, const HashS
return false;
}
+bool EditorResourcePicker::_is_custom_type_script() const {
+ Ref<Script> resource_as_script = edited_resource;
+
+ if (resource_as_script.is_valid() && resource_owner && resource_owner->has_meta(SceneStringName(_custom_type_script))) {
+ return true;
+ }
+
+ return false;
+}
+
Variant EditorResourcePicker::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
if (edited_resource.is_valid()) {
Dictionary drag_data = EditorNode::get_singleton()->drag_resource(edited_resource, p_from);
@@ -819,7 +831,7 @@ void EditorResourcePicker::_notification(int p_what) {
edit_menu->add_theme_constant_override("icon_max_width", icon_width);
}
- edit_button->set_icon(get_theme_icon(SNAME("select_arrow"), SNAME("Tree")));
+ edit_button->set_button_icon(get_theme_icon(SNAME("select_arrow"), SNAME("Tree")));
} break;
case NOTIFICATION_DRAW: {
@@ -953,6 +965,10 @@ bool EditorResourcePicker::is_toggle_pressed() const {
return assign_button->is_pressed();
}
+void EditorResourcePicker::set_resource_owner(Object *p_object) {
+ resource_owner = p_object;
+}
+
void EditorResourcePicker::set_editable(bool p_editable) {
editable = p_editable;
assign_button->set_disabled(!editable && !edited_resource.is_valid());
@@ -1098,7 +1114,10 @@ void EditorScriptPicker::set_create_options(Object *p_menu_node) {
return;
}
- menu_node->add_icon_item(get_editor_theme_icon(SNAME("ScriptCreate")), TTR("New Script..."), OBJ_MENU_NEW_SCRIPT);
+ if (!(script_owner && script_owner->has_meta(SceneStringName(_custom_type_script)))) {
+ menu_node->add_icon_item(get_editor_theme_icon(SNAME("ScriptCreate")), TTR("New Script..."), OBJ_MENU_NEW_SCRIPT);
+ }
+
if (script_owner) {
Ref<Script> scr = script_owner->get_script();
if (scr.is_valid()) {
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index 0a32dea3ed..8fb774a2cb 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -81,6 +81,8 @@ class EditorResourcePicker : public HBoxContainer {
CONVERT_BASE_ID = 1000,
};
+ Object *resource_owner = nullptr;
+
PopupMenu *edit_menu = nullptr;
void _update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj);
@@ -102,6 +104,7 @@ class EditorResourcePicker : public HBoxContainer {
void _ensure_allowed_types() const;
bool _is_drop_valid(const Dictionary &p_drag_data) const;
bool _is_type_valid(const String &p_type_name, const HashSet<StringName> &p_allowed_types) const;
+ bool _is_custom_type_script() const;
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;
@@ -137,6 +140,8 @@ public:
void set_toggle_pressed(bool p_pressed);
bool is_toggle_pressed() const;
+ void set_resource_owner(Object *p_object);
+
void set_editable(bool p_editable);
bool is_editable() const;
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index d5135f4198..caed02ae58 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -223,11 +223,6 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
args.push_back(p_scene);
}
- // Pass the debugger stop shortcut to the running instance(s).
- String shortcut;
- VariantWriter::write_to_string(ED_GET_SHORTCUT("editor/stop_running_project"), shortcut);
- OS::get_singleton()->set_environment("__GODOT_EDITOR_STOP_SHORTCUT__", shortcut);
-
String exec = OS::get_singleton()->get_executable_path();
int instance_count = RunInstancesDialog::get_singleton()->get_instance_count();
for (int i = 0; i < instance_count; i++) {
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index e0e1ef6d19..3e7c8466a2 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -39,7 +39,7 @@
void EditorRunNative::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- remote_debug->set_icon(get_editor_theme_icon(SNAME("PlayRemote")));
+ remote_debug->set_button_icon(get_editor_theme_icon(SNAME("PlayRemote")));
} break;
case NOTIFICATION_PROCESS: {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 12a7c3a2ff..b0d1c3e6bb 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -602,6 +602,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/file_dialog/thumbnail_size", 64, "32,128,16")
// Quick Open dialog
+ EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/quick_open_dialog/max_results", 100, "0,10000,1", PROPERTY_USAGE_DEFAULT)
+ _initial_set("filesystem/quick_open_dialog/show_search_highlight", true);
+ _initial_set("filesystem/quick_open_dialog/enable_fuzzy_matching", true);
+ EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/quick_open_dialog/max_fuzzy_misses", 2, "0,10,1", PROPERTY_USAGE_DEFAULT)
_initial_set("filesystem/quick_open_dialog/include_addons", false);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "filesystem/quick_open_dialog/default_display_mode", 0, "Adaptive,Last Used")
@@ -711,6 +715,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/script_list/sort_members_outline_alphabetically", false, true);
_initial_set("text_editor/script_list/script_temperature_enabled", true);
_initial_set("text_editor/script_list/script_temperature_history_size", 15);
+ _initial_set("text_editor/script_list/highlight_scene_scripts", true);
_initial_set("text_editor/script_list/group_help_pages", true);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/sort_scripts_by", 0, "Name,Path,None");
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/list_script_names_as", 0, "Name,Parent Directory And Name,Full Path");
@@ -1225,7 +1230,7 @@ fail:
extra_config->set_value("init_projects", "list", list);
}
- singleton = Ref<EditorSettings>(memnew(EditorSettings));
+ singleton.instantiate();
singleton->set_path(config_file_path, true);
singleton->save_changed_setting = true;
singleton->_load_defaults(extra_config);
@@ -1492,10 +1497,26 @@ void EditorSettings::set_favorites(const Vector<String> &p_favorites) {
}
}
+void EditorSettings::set_favorite_properties(const HashMap<String, PackedStringArray> &p_favorite_properties) {
+ favorite_properties = p_favorite_properties;
+ String favorite_properties_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorite_properties");
+
+ Ref<ConfigFile> cf;
+ cf.instantiate();
+ for (const KeyValue<String, PackedStringArray> &kv : p_favorite_properties) {
+ cf->set_value(kv.key, "properties", kv.value);
+ }
+ cf->save(favorite_properties_file);
+}
+
Vector<String> EditorSettings::get_favorites() const {
return favorites;
}
+HashMap<String, PackedStringArray> EditorSettings::get_favorite_properties() const {
+ return favorite_properties;
+}
+
void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) {
recent_dirs = p_recent_dirs;
String recent_dirs_file;
@@ -1518,23 +1539,51 @@ Vector<String> EditorSettings::get_recent_dirs() const {
void EditorSettings::load_favorites_and_recent_dirs() {
String favorites_file;
+ String favorite_properties_file;
String recent_dirs_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");
+ favorite_properties_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_properties");
recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");
} else {
favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");
+ favorite_properties_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorite_properties");
recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");
}
+
+ /// File Favorites
+
Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::READ);
if (f.is_valid()) {
String line = f->get_line().strip_edges();
while (!line.is_empty()) {
- favorites.push_back(line);
+ favorites.append(line);
line = f->get_line().strip_edges();
}
}
+ /// Inspector Favorites
+
+ Ref<ConfigFile> cf;
+ cf.instantiate();
+ if (cf->load(favorite_properties_file) == OK) {
+ List<String> secs;
+ cf->get_sections(&secs);
+
+ for (String &E : secs) {
+ PackedStringArray properties = PackedStringArray(cf->get_value(E, "properties"));
+ if (EditorNode::get_editor_data().is_type_recognized(E) || ResourceLoader::exists(E, "Script")) {
+ for (const String &property : properties) {
+ if (!favorite_properties[E].has(property)) {
+ favorite_properties[E].push_back(property);
+ }
+ }
+ }
+ }
+ }
+
+ /// Recent Directories
+
f = FileAccess::open(recent_dirs_file, FileAccess::READ);
if (f.is_valid()) {
String line = f->get_line().strip_edges();
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index d1ccedfe6c..3c8a4de866 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -102,6 +102,7 @@ private:
HashMap<String, List<Ref<InputEvent>>> builtin_action_overrides;
Vector<String> favorites;
+ HashMap<String, PackedStringArray> favorite_properties;
Vector<String> recent_dirs;
bool save_changed_setting = true;
@@ -176,6 +177,8 @@ public:
void set_favorites(const Vector<String> &p_favorites);
Vector<String> get_favorites() const;
+ void set_favorite_properties(const HashMap<String, PackedStringArray> &p_favorite_properties);
+ HashMap<String, PackedStringArray> get_favorite_properties() const;
void set_recent_dirs(const Vector<String> &p_recent_dirs);
Vector<String> get_recent_dirs() const;
void load_favorites_and_recent_dirs();
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index d07608d852..d6742c9b55 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -285,7 +285,7 @@ void EditorSettingsDialog::_update_icons() {
shortcut_search_box->set_right_icon(shortcuts->get_editor_theme_icon(SNAME("Search")));
shortcut_search_box->set_clear_button_enabled(true);
- restart_close_button->set_icon(shortcuts->get_editor_theme_icon(SNAME("Close")));
+ restart_close_button->set_button_icon(shortcuts->get_editor_theme_icon(SNAME("Close")));
restart_container->add_theme_style_override(SceneStringName(panel), shortcuts->get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
restart_icon->set_texture(shortcuts->get_editor_theme_icon(SNAME("StatusWarning")));
restart_label->add_theme_color_override(SceneStringName(font_color), shortcuts->get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
diff --git a/editor/export/codesign.cpp b/editor/export/codesign.cpp
index 72d496b04d..cc53068d48 100644
--- a/editor/export/codesign.cpp
+++ b/editor/export/codesign.cpp
@@ -1381,14 +1381,14 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
r_error_msg = TTR("Invalid entitlements file.");
ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid entitlements file.");
}
- cet = Ref<CodeSignEntitlementsText>(memnew(CodeSignEntitlementsText(entitlements)));
- ceb = Ref<CodeSignEntitlementsBinary>(memnew(CodeSignEntitlementsBinary(entitlements)));
+ cet.instantiate(entitlements);
+ ceb.instantiate(entitlements);
}
print_verbose("CodeSign: Generating requirements...");
Ref<CodeSignRequirements> rq;
String team_id = "";
- rq = Ref<CodeSignRequirements>(memnew(CodeSignRequirements()));
+ rq.instantiate();
// Sign executables.
for (int i = 0; i < files_to_sign.size(); i++) {
@@ -1487,7 +1487,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
print_verbose("CodeSign: Generating signature...");
Ref<CodeSignSignature> cs;
- cs = Ref<CodeSignSignature>(memnew(CodeSignSignature()));
+ cs.instantiate();
print_verbose("CodeSign: Writing signature superblob...");
// Write signature data to the executable.
diff --git a/editor/export/codesign.h b/editor/export/codesign.h
index 9a858c49ac..92366da0f6 100644
--- a/editor/export/codesign.h
+++ b/editor/export/codesign.h
@@ -166,7 +166,7 @@ public:
virtual int get_size() const override;
- virtual uint32_t get_index_type() const override { return 0x00000002; };
+ virtual uint32_t get_index_type() const override { return 0x00000002; }
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
@@ -188,7 +188,7 @@ public:
virtual int get_size() const override;
- virtual uint32_t get_index_type() const override { return 0x00000005; };
+ virtual uint32_t get_index_type() const override { return 0x00000005; }
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
@@ -210,7 +210,7 @@ public:
virtual int get_size() const override;
- virtual uint32_t get_index_type() const override { return 0x00000007; };
+ virtual uint32_t get_index_type() const override { return 0x00000007; }
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
@@ -311,7 +311,7 @@ public:
virtual PackedByteArray get_hash_sha256() const override;
virtual int get_size() const override;
- virtual uint32_t get_index_type() const override { return 0x00000000; };
+ virtual uint32_t get_index_type() const override { return 0x00000000; }
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
@@ -330,7 +330,7 @@ public:
virtual PackedByteArray get_hash_sha256() const override;
virtual int get_size() const override;
- virtual uint32_t get_index_type() const override { return 0x00010000; };
+ virtual uint32_t get_index_type() const override { return 0x00010000; }
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 50fa49dc52..8b8fafcd32 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -59,6 +59,17 @@ static int _get_pad(int p_alignment, int p_n) {
return pad;
}
+template <typename T>
+static bool _has_pack_path(const T &p_paths, const String &p_path) {
+ for (const String &E : p_paths) {
+ if (E.simplify_path().trim_prefix("res://") == p_path) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
#define PCK_PADDING 16
bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err) {
@@ -210,21 +221,23 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa
PackData *pd = (PackData *)p_userdata;
+ String simplified_path = p_path.simplify_path();
+
SavedData sd;
- sd.path_utf8 = p_path.utf8();
+ sd.path_utf8 = simplified_path.trim_prefix("res://").utf8();
sd.ofs = pd->f->get_position();
sd.size = p_data.size();
sd.encrypted = false;
for (int i = 0; i < p_enc_in_filters.size(); ++i) {
- if (p_path.matchn(p_enc_in_filters[i]) || p_path.replace("res://", "").matchn(p_enc_in_filters[i])) {
+ if (simplified_path.matchn(p_enc_in_filters[i]) || simplified_path.trim_prefix("res://").matchn(p_enc_in_filters[i])) {
sd.encrypted = true;
break;
}
}
for (int i = 0; i < p_enc_ex_filters.size(); ++i) {
- if (p_path.matchn(p_enc_ex_filters[i]) || p_path.replace("res://", "").matchn(p_enc_ex_filters[i])) {
+ if (simplified_path.matchn(p_enc_ex_filters[i]) || simplified_path.trim_prefix("res://").matchn(p_enc_ex_filters[i])) {
sd.encrypted = false;
break;
}
@@ -965,10 +978,10 @@ Error EditorExportPlatform::_export_project_files(const Ref<EditorExportPreset>
ScriptCallbackData data;
data.file_cb = p_save_func;
data.so_cb = p_so_func;
- return export_project_files(p_preset, p_debug, _script_save_file, &data, _script_add_shared_object);
+ return export_project_files(p_preset, p_debug, _script_save_file, nullptr, &data, _script_add_shared_object);
}
-Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) {
+Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_save_func, EditorExportRemoveFunction p_remove_func, void *p_udata, EditorExportSaveSharedObject p_so_func) {
//figure out paths of files that will be exported
HashSet<String> paths;
Vector<String> path_remaps;
@@ -1082,6 +1095,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Error err = OK;
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
+ Vector<String> extra_paths;
struct SortByName {
bool operator()(const Ref<EditorExportPlugin> &left, const Ref<EditorExportPlugin> &right) const {
@@ -1102,10 +1116,12 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
}
for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) {
- err = p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
+
+ extra_paths.push_back(export_plugins[i]->extra_files[j].path);
}
export_plugins.write[i]->_clear();
@@ -1218,7 +1234,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) {
- err = p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
@@ -1227,6 +1243,8 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
path_remaps.push_back(path);
path_remaps.push_back(export_plugins[i]->extra_files[j].path);
}
+
+ extra_paths.push_back(export_plugins[i]->extra_files[j].path);
}
if (export_plugins[i]->skipped) {
@@ -1248,7 +1266,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
if (importer_type == "keep") {
// Just keep file as-is.
Vector<uint8_t> array = FileAccess::get_file_as_bytes(path);
- err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
@@ -1291,13 +1309,13 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
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);
+ err = p_save_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_bytes(export_path);
- err = p_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
@@ -1327,14 +1345,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
if (remap == "path") {
String remapped_path = config->get_value("remap", remap);
Vector<uint8_t> array = FileAccess::get_file_as_bytes(remapped_path);
- err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_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_bytes(remapped_path);
- err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
} else {
// Remove paths if feature not enabled.
config->erase_section_key("remap", remap);
@@ -1360,7 +1378,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
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);
+ err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
@@ -1381,7 +1399,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
Vector<uint8_t> array = FileAccess::get_file_as_bytes(export_path);
- err = p_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
@@ -1445,7 +1463,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
new_file.write[j] = utf8[j];
}
- err = p_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
@@ -1459,7 +1477,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Vector<String> forced_export = get_forced_export_files();
for (int i = 0; i < forced_export.size(); i++) {
Vector<uint8_t> array = FileAccess::get_file_as_bytes(forced_export[i]);
- err = p_func(p_udata, forced_export[i], array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, forced_export[i], array, idx, total, enc_in_filters, enc_ex_filters, key);
if (err != OK) {
return err;
}
@@ -1471,7 +1489,30 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Vector<uint8_t> data = FileAccess::get_file_as_bytes(engine_cfb);
DirAccess::remove_file_or_error(engine_cfb);
- return p_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
+
+ if (p_remove_func) {
+ for (const String &E : PackedData::get_singleton()->get_file_paths()) {
+ String simplified_path = E.simplify_path();
+ if (simplified_path == config_file) {
+ continue;
+ }
+
+ String pack_path = simplified_path.trim_suffix(".remap");
+
+ if (!_has_pack_path(paths, pack_path) && !_has_pack_path(extra_paths, pack_path) && !_has_pack_path(path_remaps, pack_path) && !_has_pack_path(forced_export, pack_path)) {
+ err = p_remove_func(p_udata, E);
+ if (err != OK) {
+ return err;
+ }
+ }
+ }
+ }
+
+ return OK;
}
Error EditorExportPlatform::_pack_add_shared_object(void *p_userdata, const SharedObject &p_so) {
@@ -1483,6 +1524,29 @@ Error EditorExportPlatform::_pack_add_shared_object(void *p_userdata, const Shar
return OK;
}
+Error EditorExportPlatform::_remove_pack_file(void *p_userdata, const String &p_path) {
+ PackData *pd = (PackData *)p_userdata;
+
+ SavedData sd;
+ sd.path_utf8 = p_path.utf8();
+ sd.ofs = pd->f->get_position();
+ sd.size = 0;
+ sd.removal = true;
+
+ // This padding will likely never be added, as we should already be aligned when removals are added.
+ int pad = _get_pad(PCK_PADDING, pd->f->get_position());
+ for (int i = 0; i < pad; i++) {
+ pd->f->store_8(0);
+ }
+
+ sd.md5.resize(16);
+ sd.md5.fill(0);
+
+ pd->file_ofs.push_back(sd);
+
+ return OK;
+}
+
Error EditorExportPlatform::_zip_add_shared_object(void *p_userdata, const SharedObject &p_so) {
ZipData *zip_data = (ZipData *)p_userdata;
if (zip_data->so_files) {
@@ -1613,7 +1677,7 @@ Dictionary EditorExportPlatform::_save_pack(const Ref<EditorExportPreset> &p_pre
Vector<SharedObject> so_files;
int64_t embedded_start = 0;
int64_t embedded_size = 0;
- Error err_code = save_pack(p_preset, p_debug, p_path, &so_files, nullptr, p_embed, &embedded_start, &embedded_size);
+ Error err_code = save_pack(p_preset, p_debug, p_path, &so_files, nullptr, nullptr, p_embed, &embedded_start, &embedded_size);
Dictionary ret;
ret["result"] = err_code;
@@ -1699,7 +1763,7 @@ Dictionary EditorExportPlatform::_save_zip_patch(const Ref<EditorExportPreset> &
return ret;
}
-Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, EditorExportSaveFunction p_save_func, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
+Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, EditorExportSaveFunction p_save_func, EditorExportRemoveFunction p_remove_func, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
EditorProgress ep("savepack", TTR("Packing"), 102, true);
if (p_save_func == nullptr) {
@@ -1722,7 +1786,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
pd.f = ftmp;
pd.so_files = p_so_files;
- Error err = export_project_files(p_preset, p_debug, p_save_func, &pd, _pack_add_shared_object);
+ Error err = export_project_files(p_preset, p_debug, p_save_func, p_remove_func, &pd, _pack_add_shared_object);
// Close temp file.
pd.f.unref();
@@ -1868,6 +1932,9 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
if (pd.file_ofs[i].encrypted) {
flags |= PACK_FILE_ENCRYPTED;
}
+ if (pd.file_ofs[i].removal) {
+ flags |= PACK_FILE_REMOVAL;
+ }
fhead->store_32(flags);
}
@@ -1936,7 +2003,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
}
Error EditorExportPlatform::save_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
- return save_pack(p_preset, p_debug, p_path, p_so_files, _save_pack_patch_file, p_embed, r_embedded_start, r_embedded_size);
+ return save_pack(p_preset, p_debug, p_path, p_so_files, _save_pack_patch_file, _remove_pack_file, p_embed, r_embedded_start, r_embedded_size);
}
Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, EditorExportSaveFunction p_save_func) {
@@ -1957,7 +2024,7 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bo
zd.zip = zip;
zd.so_files = p_so_files;
- Error err = export_project_files(p_preset, p_debug, p_save_func, &zd, _zip_add_shared_object);
+ Error err = export_project_files(p_preset, p_debug, p_save_func, nullptr, &zd, _zip_add_shared_object);
if (err != OK && err != ERR_SKIP) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Save ZIP"), TTR("Failed to export project files."));
}
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index ef3274c5e4..919fb2915a 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -54,6 +54,7 @@ protected:
public:
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ typedef Error (*EditorExportRemoveFunction)(void *p_userdata, const String &p_path);
typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const SharedObject &p_so);
enum DebugFlags {
@@ -82,6 +83,7 @@ private:
uint64_t ofs = 0;
uint64_t size = 0;
bool encrypted = false;
+ bool removal = false;
Vector<uint8_t> md5;
CharString path_utf8;
@@ -116,6 +118,8 @@ private:
static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
static Error _pack_add_shared_object(void *p_userdata, const SharedObject &p_so);
+ static Error _remove_pack_file(void *p_userdata, const String &p_path);
+
static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
static Error _zip_add_shared_object(void *p_userdata, const SharedObject &p_so);
@@ -287,7 +291,7 @@ public:
Array get_current_presets() const;
Error _export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, const Callable &p_save_func, const Callable &p_so_func);
- Error export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func = nullptr);
+ Error export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_save_func, EditorExportRemoveFunction p_remove_func, void *p_udata, EditorExportSaveSharedObject p_so_func = nullptr);
Dictionary _save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, bool p_embed = false);
Dictionary _save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
@@ -295,7 +299,7 @@ public:
Dictionary _save_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
Dictionary _save_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
- Error save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, EditorExportSaveFunction p_save_func = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
+ Error save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, EditorExportSaveFunction p_save_func = nullptr, EditorExportRemoveFunction p_remove_func = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
Error save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, EditorExportSaveFunction p_save_func = nullptr);
Error save_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index 52f7a0cee8..4eff096840 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -194,7 +194,7 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
int64_t embedded_pos;
int64_t embedded_size;
- Error err = save_pack(p_preset, p_debug, pck_path, &so_files, nullptr, p_preset->get("binary_format/embed_pck"), &embedded_pos, &embedded_size);
+ Error err = save_pack(p_preset, p_debug, pck_path, &so_files, nullptr, nullptr, p_preset->get("binary_format/embed_pck"), &embedded_pos, &embedded_size);
if (err == OK && p_preset->get("binary_format/embed_pck")) {
if (embedded_size >= 0x100000000 && String(p_preset->get("binary_format/architecture")).contains("32")) {
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."));
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index 2309319376..a90c16f66e 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -889,7 +889,7 @@ void ExportTemplateManager::_notification(int p_what) {
current_missing_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
current_installed_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
- mirror_options_button->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ mirror_options_button->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index f9137082d7..a3cd6523e9 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -100,15 +100,15 @@ void ProjectExportDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- duplicate_preset->set_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
- delete_preset->set_icon(presets->get_editor_theme_icon(SNAME("Remove")));
- patch_add_btn->set_icon(get_editor_theme_icon(SNAME("Add")));
+ duplicate_preset->set_button_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
+ delete_preset->set_button_icon(presets->get_editor_theme_icon(SNAME("Remove")));
+ patch_add_btn->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
case NOTIFICATION_READY: {
- duplicate_preset->set_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
- delete_preset->set_icon(presets->get_editor_theme_icon(SNAME("Remove")));
- patch_add_btn->set_icon(get_editor_theme_icon(SNAME("Add")));
+ duplicate_preset->set_button_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
+ delete_preset->set_button_icon(presets->get_editor_theme_icon(SNAME("Remove")));
+ patch_add_btn->set_button_icon(get_editor_theme_icon(SNAME("Add")));
connect(SceneStringName(confirmed), callable_mp(this, &ProjectExportDialog::_export_pck_zip));
_update_export_all();
} break;
diff --git a/editor/export/project_export.h b/editor/export/project_export.h
index e360596be6..bbf0d81228 100644
--- a/editor/export/project_export.h
+++ b/editor/export/project_export.h
@@ -216,7 +216,7 @@ public:
Ref<EditorExportPreset> get_current_preset() const;
- bool is_exporting() const { return exporting; };
+ bool is_exporting() const { return exporting; }
ProjectExportDialog();
~ProjectExportDialog();
diff --git a/editor/fbx_importer_manager.cpp b/editor/fbx_importer_manager.cpp
index 2650b642fa..f612c3bd81 100644
--- a/editor/fbx_importer_manager.cpp
+++ b/editor/fbx_importer_manager.cpp
@@ -40,7 +40,7 @@
void FBXImporterManager::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- fbx_path_browse->set_icon(get_editor_theme_icon(SNAME("FileBrowse")));
+ fbx_path_browse->set_button_icon(get_editor_theme_icon(SNAME("FileBrowse")));
} break;
case NOTIFICATION_READY: {
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 53982b37b9..fcd5a572b4 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -495,7 +495,7 @@ void FileSystemDock::_update_display_mode(bool p_force) {
if (p_force || old_display_mode != display_mode) {
switch (display_mode) {
case DISPLAY_MODE_TREE_ONLY:
- button_toggle_display_mode->set_icon(get_editor_theme_icon(SNAME("Panels1")));
+ button_toggle_display_mode->set_button_icon(get_editor_theme_icon(SNAME("Panels1")));
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
toolbar2_hbc->show();
@@ -512,7 +512,7 @@ void FileSystemDock::_update_display_mode(bool p_force) {
const int actual_offset = is_vertical ? split_box_offset_v : split_box_offset_h;
split_box->set_split_offset(actual_offset);
const StringName icon = is_vertical ? SNAME("Panels2") : SNAME("Panels2Alt");
- button_toggle_display_mode->set_icon(get_editor_theme_icon(icon));
+ button_toggle_display_mode->set_button_icon(get_editor_theme_icon(icon));
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -597,7 +597,7 @@ void FileSystemDock::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
_update_display_mode(true);
- button_reload->set_icon(get_editor_theme_icon(SNAME("Reload")));
+ button_reload->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
StringName mode_icon = "Panels1";
if (display_mode == DISPLAY_MODE_VSPLIT) {
@@ -605,28 +605,28 @@ void FileSystemDock::_notification(int p_what) {
} else if (display_mode == DISPLAY_MODE_HSPLIT) {
mode_icon = "Panels2Alt";
}
- button_toggle_display_mode->set_icon(get_editor_theme_icon(mode_icon));
+ button_toggle_display_mode->set_button_icon(get_editor_theme_icon(mode_icon));
if (file_list_display_mode == FILE_LIST_DISPLAY_LIST) {
- button_file_list_display_mode->set_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
} else {
- button_file_list_display_mode->set_icon(get_editor_theme_icon(SNAME("FileList")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileList")));
}
tree_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- tree_button_sort->set_icon(get_editor_theme_icon(SNAME("Sort")));
+ tree_button_sort->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
file_list_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- file_list_button_sort->set_icon(get_editor_theme_icon(SNAME("Sort")));
+ file_list_button_sort->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
- button_dock_placement->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ button_dock_placement->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
if (is_layout_rtl()) {
- button_hist_next->set_icon(get_editor_theme_icon(SNAME("Back")));
- button_hist_prev->set_icon(get_editor_theme_icon(SNAME("Forward")));
+ button_hist_next->set_button_icon(get_editor_theme_icon(SNAME("Back")));
+ button_hist_prev->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
} else {
- button_hist_next->set_icon(get_editor_theme_icon(SNAME("Forward")));
- button_hist_prev->set_icon(get_editor_theme_icon(SNAME("Back")));
+ button_hist_next->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
+ button_hist_prev->set_button_icon(get_editor_theme_icon(SNAME("Back")));
}
overwrite_dialog_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), "Tree"));
@@ -818,11 +818,11 @@ void FileSystemDock::_toggle_file_display() {
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_editor_theme_icon(SNAME("FileThumbnail")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
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_editor_theme_icon(SNAME("FileList")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileList")));
button_file_list_display_mode->set_tooltip_text(TTR("View items as a list."));
}
@@ -1446,6 +1446,13 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_
}
}
+ if (p_item.is_file && FileAccess::exists(old_path + ".uid")) {
+ err = da->rename(old_path + ".uid", new_path + ".uid");
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error moving:") + "\n" + old_path + ".uid\n");
+ }
+ }
+
// Update scene if it is open.
for (int i = 0; i < file_changed_paths.size(); ++i) {
String new_item_path = p_item.is_file ? new_path : file_changed_paths[i].replace_first(old_path, new_path);
@@ -1491,76 +1498,22 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.") + "\n" + old_path + "\n");
return;
}
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (p_item.is_file) {
print_verbose("Duplicating " + old_path + " -> " + new_path);
// Create the directory structure.
- da->make_dir_recursive(new_path.get_base_dir());
+ EditorFileSystem::get_singleton()->make_dir_recursive(p_new_path.get_base_dir());
- if (FileAccess::exists(old_path + ".import")) {
- Error err = da->copy(old_path, new_path);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
- return;
- }
-
- // Remove uid from .import file to avoid conflict.
- Ref<ConfigFile> cfg;
- cfg.instantiate();
- cfg->load(old_path + ".import");
- cfg->erase_section_key("remap", "uid");
- err = cfg->save(new_path + ".import");
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ".import: " + error_names[err] + "\n");
- return;
- }
- } else {
- // Files which do not use an uid can just be copied.
- if (ResourceLoader::get_resource_uid(old_path) == ResourceUID::INVALID_ID) {
- Error err = da->copy(old_path, new_path);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
- }
- return;
- }
-
- // Load the resource and save it again in the new location (this generates a new UID).
- Error err;
- Ref<Resource> res = ResourceLoader::load(old_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
- if (err == OK && res.is_valid()) {
- err = ResourceSaver::save(res, new_path, ResourceSaver::FLAG_COMPRESS);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + " " + vformat(TTR("Failed to save resource at %s: %s"), new_path, error_names[err]));
- }
- } else if (err != OK) {
- // When loading files like text files the error is OK but the resource is still null.
- // We can ignore such files.
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + " " + vformat(TTR("Failed to load resource at %s: %s"), new_path, error_names[err]));
- }
+ Error err = EditorFileSystem::get_singleton()->copy_file(old_path, new_path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
}
} else {
- da->make_dir(new_path);
-
- // Recursively duplicate all files inside the folder.
- Ref<DirAccess> old_dir = DirAccess::open(old_path);
- ERR_FAIL_COND(old_dir.is_null());
-
- Ref<FileAccess> file_access = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- old_dir->set_include_navigational(false);
- old_dir->list_dir_begin();
- for (String f = old_dir->_get_next(); !f.is_empty(); f = old_dir->_get_next()) {
- if (f.get_extension() == "import") {
- continue;
- }
- if (file_access->file_exists(old_path + f)) {
- _try_duplicate_item(FileOrFolder(old_path + f, true), new_path + f);
- } else if (da->dir_exists(old_path + f)) {
- _try_duplicate_item(FileOrFolder(old_path + f, false), new_path + f);
- }
+ Error err = EditorFileSystem::get_singleton()->copy_directory(old_path, new_path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating directory:") + "\n" + old_path + "\n");
}
- old_dir->list_dir_end();
}
}
@@ -1695,21 +1648,27 @@ String FileSystemDock::_get_unique_name(const FileOrFolder &p_entry, const Strin
return new_path;
}
-void FileSystemDock::_update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const {
- Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
- Vector<String> new_favorites;
-
- for (const String &old_path : favorites_list) {
+void FileSystemDock::_update_favorites_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const {
+ Vector<String> favorite_files = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> new_favorite_files;
+ for (const String &old_path : favorite_files) {
if (p_folders_renames.has(old_path)) {
- new_favorites.push_back(p_folders_renames[old_path]);
+ new_favorite_files.push_back(p_folders_renames[old_path]);
} else if (p_files_renames.has(old_path)) {
- new_favorites.push_back(p_files_renames[old_path]);
+ new_favorite_files.push_back(p_files_renames[old_path]);
} else {
- new_favorites.push_back(old_path);
+ new_favorite_files.push_back(old_path);
}
}
+ EditorSettings::get_singleton()->set_favorites(new_favorite_files);
- EditorSettings::get_singleton()->set_favorites(new_favorites);
+ HashMap<String, PackedStringArray> favorite_properties = EditorSettings::get_singleton()->get_favorite_properties();
+ for (const KeyValue<String, String> &KV : p_files_renames) {
+ if (favorite_properties.has(KV.key)) {
+ favorite_properties.replace_key(KV.key, KV.value);
+ }
+ }
+ EditorSettings::get_singleton()->set_favorite_properties(favorite_properties);
}
void FileSystemDock::_make_scene_confirm() {
@@ -1852,7 +1811,7 @@ void FileSystemDock::_rename_operation_confirm() {
_update_resource_paths_after_move(file_renames, uids);
_update_dependencies_after_move(file_renames, file_owners);
_update_project_settings_after_move(file_renames, folder_renames);
- _update_favorites_list_after_move(file_renames, folder_renames);
+ _update_favorites_after_move(file_renames, folder_renames);
EditorSceneTabs::get_singleton()->set_current_tab(current_tab);
@@ -1866,21 +1825,15 @@ void FileSystemDock::_rename_operation_confirm() {
}
void FileSystemDock::_duplicate_operation_confirm(const String &p_path) {
- String base_dir = p_path.trim_suffix("/").get_base_dir();
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- if (!da->dir_exists(base_dir)) {
- Error err = da->make_dir_recursive(base_dir);
-
+ const String base_dir = p_path.trim_suffix("/").get_base_dir();
+ if (!DirAccess::dir_exists_absolute(base_dir)) {
+ Error err = EditorFileSystem::get_singleton()->make_dir_recursive(base_dir);
if (err != OK) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Could not create base directory: %s"), error_names[err]));
return;
}
}
_try_duplicate_item(to_duplicate, p_path);
-
- // Rescan everything.
- print_verbose("FileSystem: calling rescan.");
- _rescan();
}
void FileSystemDock::_overwrite_dialog_action(bool p_overwrite) {
@@ -2019,7 +1972,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop
_update_resource_paths_after_move(file_renames, uids);
_update_dependencies_after_move(file_renames, file_owners);
_update_project_settings_after_move(file_renames, folder_renames);
- _update_favorites_list_after_move(file_renames, folder_renames);
+ _update_favorites_after_move(file_renames, folder_renames);
EditorSceneTabs::get_singleton()->set_current_tab(current_tab);
@@ -2532,9 +2485,6 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
make_dir_dialog->popup_centered();
} break;
- case FILE_INFO: {
- } break;
-
case FILE_REIMPORT: {
ImportDock::get_singleton()->reimport_resources(p_selected);
} break;
@@ -2776,7 +2726,7 @@ void FileSystemDock::focus_on_filter() {
}
void FileSystemDock::create_directory(const String &p_path, const String &p_base_dir) {
- Error err = EditorFileSystem::get_singleton()->make_dir_recursive(p_path, p_base_dir);
+ Error err = EditorFileSystem::get_singleton()->make_dir_recursive(p_path.trim_prefix(p_base_dir), p_base_dir);
if (err != OK) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Could not create folder: %s"), error_names[err]));
}
@@ -3431,7 +3381,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
const bool is_directory = fpath.ends_with("/");
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
- p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Containing Folder in Terminal"));
+ p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Folder in Terminal"));
if (!is_directory) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("ExternalLink")), ED_GET_SHORTCUT("filesystem_dock/open_in_external_program"), FILE_OPEN_EXTERNAL);
@@ -4060,17 +4010,17 @@ FileSystemDock::FileSystemDock() {
// `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_absolute_path", TTR("Copy Absolute Path"));
- ED_SHORTCUT("filesystem_dock/copy_uid", TTR("Copy UID"));
+ ED_SHORTCUT("filesystem_dock/copy_absolute_path", TTR("Copy Absolute Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::C);
+ ED_SHORTCUT("filesystem_dock/copy_uid", TTR("Copy UID"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | KeyModifierMask::SHIFT | Key::C);
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);
#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
// Opening the system file manager or opening in an external program is not supported on the Android and web editors.
- ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager"));
- ED_SHORTCUT("filesystem_dock/open_in_external_program", TTR("Open in External Program"));
- ED_SHORTCUT("filesystem_dock/open_in_terminal", TTR("Open in Terminal"));
+ ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::R);
+ ED_SHORTCUT("filesystem_dock/open_in_external_program", TTR("Open in External Program"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::E);
+ ED_SHORTCUT("filesystem_dock/open_in_terminal", TTR("Open in Terminal"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T);
#endif
// Properly translating color names would require a separate HashMap, so for simplicity they are provided as comments.
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 819abbd389..fe83129c07 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -116,7 +116,6 @@ private:
FILE_REMOVE,
FILE_DUPLICATE,
FILE_REIMPORT,
- FILE_INFO,
FILE_NEW,
FILE_SHOW_IN_EXPLORER,
FILE_OPEN_EXTERNAL,
@@ -276,7 +275,7 @@ private:
void _before_move(HashMap<String, ResourceUID::ID> &r_uids, HashSet<String> &r_file_owners) const;
void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const;
void _update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const;
- void _update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const;
+ void _update_favorites_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const;
void _update_project_settings_after_move(const HashMap<String, String> &p_renames, const HashMap<String, String> &p_folders_renames);
String _get_unique_name(const FileOrFolder &p_entry, const String &p_at_path);
@@ -402,7 +401,7 @@ public:
FileSortOption get_file_sort() const { return file_sort; }
void set_file_list_display_mode(FileListDisplayMode p_mode);
- FileListDisplayMode get_file_list_display_mode() const { return file_list_display_mode; };
+ FileListDisplayMode get_file_list_display_mode() const { return file_list_display_mode; }
Tree *get_tree_control() { return tree; }
diff --git a/editor/group_settings_editor.cpp b/editor/group_settings_editor.cpp
index bb899af582..93d5ee0716 100644
--- a/editor/group_settings_editor.cpp
+++ b/editor/group_settings_editor.cpp
@@ -45,7 +45,7 @@ void GroupSettingsEditor::_notification(int p_what) {
update_groups();
} break;
case NOTIFICATION_THEME_CHANGED: {
- add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
}
}
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index e0de6bbcb1..bd0805bd7e 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -373,7 +373,7 @@ void GroupsEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
filter->set_right_icon(get_editor_theme_icon("Search"));
- add->set_icon(get_editor_theme_icon("Add"));
+ add->set_button_icon(get_editor_theme_icon("Add"));
_update_tree();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
diff --git a/editor/gui/editor_bottom_panel.cpp b/editor/gui/editor_bottom_panel.cpp
index f6ba74fe95..3cc1e37be0 100644
--- a/editor/gui/editor_bottom_panel.cpp
+++ b/editor/gui/editor_bottom_panel.cpp
@@ -31,35 +31,35 @@
#include "editor_bottom_panel.h"
#include "editor/debugger/editor_debugger_node.h"
-#include "editor/editor_about.h"
#include "editor/editor_command_palette.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
-#include "editor/engine_update_label.h"
#include "editor/gui/editor_toaster.h"
#include "editor/gui/editor_version_button.h"
#include "editor/themes/editor_scale.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
+#include "scene/gui/split_container.h"
void EditorBottomPanel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- expand_button->set_icon(get_editor_theme_icon(SNAME("ExpandBottomDock")));
+ pin_button->set_button_icon(get_editor_theme_icon(SNAME("Pin")));
+ expand_button->set_button_icon(get_editor_theme_icon(SNAME("ExpandBottomDock")));
} break;
}
}
-void EditorBottomPanel::_switch_by_control(bool p_visible, Control *p_control) {
+void EditorBottomPanel::_switch_by_control(bool p_visible, Control *p_control, bool p_ignore_lock) {
for (int i = 0; i < items.size(); i++) {
if (items[i].control == p_control) {
- _switch_to_item(p_visible, i);
+ _switch_to_item(p_visible, i, p_ignore_lock);
return;
}
}
}
-void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx) {
+void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx, bool p_ignore_lock) {
ERR_FAIL_INDEX(p_idx, items.size());
if (items[p_idx].control->is_visible() == p_visible) {
@@ -70,6 +70,10 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx) {
ERR_FAIL_NULL(center_split);
if (p_visible) {
+ if (!p_ignore_lock && lock_panel_switching && pin_button->is_visible()) {
+ return;
+ }
+
for (int i = 0; i < items.size(); i++) {
items[i].button->set_pressed_no_signal(i == p_idx);
items[i].control->set_visible(i == p_idx);
@@ -80,18 +84,23 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx) {
} else {
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
}
+
center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE);
center_split->set_collapsed(false);
+ pin_button->show();
+
+ expand_button->show();
if (expand_button->is_pressed()) {
EditorNode::get_top_split()->hide();
}
- expand_button->show();
} else {
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
items[p_idx].button->set_pressed_no_signal(false);
items[p_idx].control->set_visible(false);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
center_split->set_collapsed(true);
+ pin_button->hide();
+
expand_button->hide();
if (expand_button->is_pressed()) {
EditorNode::get_top_split()->show();
@@ -101,13 +110,17 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx) {
last_opened_control = items[p_idx].control;
}
+void EditorBottomPanel::_pin_button_toggled(bool p_pressed) {
+ lock_panel_switching = p_pressed;
+}
+
void EditorBottomPanel::_expand_button_toggled(bool p_pressed) {
EditorNode::get_top_split()->set_visible(!p_pressed);
}
bool EditorBottomPanel::_button_drag_hover(const Vector2 &, const Variant &, Button *p_button, Control *p_control) {
if (!p_button->is_pressed()) {
- _switch_by_control(true, p_control);
+ _switch_by_control(true, p_control, true);
}
return false;
}
@@ -149,7 +162,7 @@ void EditorBottomPanel::load_layout_from_config(Ref<ConfigFile> p_config_file, c
Button *EditorBottomPanel::add_item(String p_text, Control *p_item, const Ref<Shortcut> &p_shortcut, bool p_at_front) {
Button *tb = memnew(Button);
tb->set_theme_type_variation("BottomPanelButton");
- tb->connect(SceneStringName(toggled), callable_mp(this, &EditorBottomPanel::_switch_by_control).bind(p_item));
+ tb->connect(SceneStringName(toggled), callable_mp(this, &EditorBottomPanel::_switch_by_control).bind(p_item, true));
tb->set_drag_forwarding(Callable(), callable_mp(this, &EditorBottomPanel::_button_drag_hover).bind(tb, p_item), Callable());
tb->set_text(p_text);
tb->set_shortcut(p_shortcut);
@@ -231,10 +244,10 @@ void EditorBottomPanel::toggle_last_opened_bottom_panel() {
// Select by control instead of index, so that the last bottom panel is opened correctly
// if it's been reordered since.
if (last_opened_control) {
- _switch_by_control(!last_opened_control->is_visible(), last_opened_control);
+ _switch_by_control(!last_opened_control->is_visible(), last_opened_control, true);
} else {
// Open the first panel in the list if no panel was opened this session.
- _switch_to_item(true, 0);
+ _switch_to_item(true, 0, true);
}
}
@@ -263,10 +276,17 @@ EditorBottomPanel::EditorBottomPanel() {
Control *h_spacer = memnew(Control);
bottom_hbox->add_child(h_spacer);
+ pin_button = memnew(Button);
+ bottom_hbox->add_child(pin_button);
+ pin_button->hide();
+ pin_button->set_theme_type_variation("FlatMenuButton");
+ pin_button->set_toggle_mode(true);
+ pin_button->set_tooltip_text(TTR("Pin Bottom Panel Switching"));
+ pin_button->connect(SceneStringName(toggled), callable_mp(this, &EditorBottomPanel::_pin_button_toggled));
+
expand_button = memnew(Button);
bottom_hbox->add_child(expand_button);
expand_button->hide();
- expand_button->set_flat(false);
expand_button->set_theme_type_variation("FlatMenuButton");
expand_button->set_toggle_mode(true);
expand_button->set_shortcut(ED_SHORTCUT_AND_COMMAND("editor/bottom_panel_expand", TTR("Expand Bottom Panel"), KeyModifierMask::SHIFT | Key::F12));
diff --git a/editor/gui/editor_bottom_panel.h b/editor/gui/editor_bottom_panel.h
index 3d44b3750a..950f0e2570 100644
--- a/editor/gui/editor_bottom_panel.h
+++ b/editor/gui/editor_bottom_panel.h
@@ -49,16 +49,19 @@ class EditorBottomPanel : public PanelContainer {
};
Vector<BottomPanelItem> items;
+ bool lock_panel_switching = false;
VBoxContainer *item_vbox = nullptr;
HBoxContainer *bottom_hbox = nullptr;
HBoxContainer *button_hbox = nullptr;
EditorToaster *editor_toaster = nullptr;
+ Button *pin_button = nullptr;
Button *expand_button = nullptr;
Control *last_opened_control = nullptr;
- void _switch_by_control(bool p_visible, Control *p_control);
- void _switch_to_item(bool p_visible, int p_idx);
+ void _switch_by_control(bool p_visible, Control *p_control, bool p_ignore_lock = false);
+ void _switch_to_item(bool p_visible, int p_idx, bool p_ignore_lock = false);
+ void _pin_button_toggled(bool p_pressed);
void _expand_button_toggled(bool p_pressed);
bool _button_drag_hover(const Vector2 &, const Variant &, Button *p_button, Control *p_control);
diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp
index 7600748685..ceff62723f 100644
--- a/editor/gui/editor_file_dialog.cpp
+++ b/editor/gui/editor_file_dialog.cpp
@@ -350,7 +350,7 @@ void EditorFileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
void EditorFileDialog::set_enable_multiple_selection(bool p_enable) {
item_list->set_select_mode(p_enable ? ItemList::SELECT_MULTI : ItemList::SELECT_SINGLE);
-};
+}
Vector<String> EditorFileDialog::get_selected_files() const {
Vector<String> list;
@@ -360,7 +360,7 @@ Vector<String> EditorFileDialog::get_selected_files() const {
}
}
return list;
-};
+}
void EditorFileDialog::update_dir() {
if (drives->is_visible()) {
@@ -1483,29 +1483,29 @@ void EditorFileDialog::_update_drives(bool p_select) {
void EditorFileDialog::_update_icons() {
// Update icons.
- mode_thumbnails->set_icon(theme_cache.mode_thumbnails);
- mode_list->set_icon(theme_cache.mode_list);
+ mode_thumbnails->set_button_icon(theme_cache.mode_thumbnails);
+ mode_list->set_button_icon(theme_cache.mode_list);
if (is_layout_rtl()) {
- dir_prev->set_icon(theme_cache.forward_folder);
- dir_next->set_icon(theme_cache.back_folder);
+ dir_prev->set_button_icon(theme_cache.forward_folder);
+ dir_next->set_button_icon(theme_cache.back_folder);
} else {
- dir_prev->set_icon(theme_cache.back_folder);
- dir_next->set_icon(theme_cache.forward_folder);
+ dir_prev->set_button_icon(theme_cache.back_folder);
+ dir_next->set_button_icon(theme_cache.forward_folder);
}
- dir_up->set_icon(theme_cache.parent_folder);
+ dir_up->set_button_icon(theme_cache.parent_folder);
- refresh->set_icon(theme_cache.reload);
- favorite->set_icon(theme_cache.favorite);
- show_hidden->set_icon(theme_cache.toggle_hidden);
- makedir->set_icon(theme_cache.create_folder);
+ refresh->set_button_icon(theme_cache.reload);
+ favorite->set_button_icon(theme_cache.favorite);
+ show_hidden->set_button_icon(theme_cache.toggle_hidden);
+ makedir->set_button_icon(theme_cache.create_folder);
filter_box->set_right_icon(theme_cache.filter_box);
- file_sort_button->set_icon(theme_cache.file_sort_button);
+ file_sort_button->set_button_icon(theme_cache.file_sort_button);
filter_box->set_clear_button_enabled(true);
- fav_up->set_icon(theme_cache.favorites_up);
- fav_down->set_icon(theme_cache.favorites_down);
+ fav_up->set_button_icon(theme_cache.favorites_up);
+ fav_down->set_button_icon(theme_cache.favorites_down);
}
void EditorFileDialog::_favorite_selected(int p_idx) {
diff --git a/editor/gui/editor_quick_open_dialog.cpp b/editor/gui/editor_quick_open_dialog.cpp
index 94a5ff94a3..44e7b3e483 100644
--- a/editor/gui/editor_quick_open_dialog.cpp
+++ b/editor/gui/editor_quick_open_dialog.cpp
@@ -30,6 +30,7 @@
#include "editor_quick_open_dialog.h"
+#include "core/string/fuzzy_search.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
@@ -45,6 +46,55 @@
#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
+void HighlightedLabel::draw_substr_rects(const Vector2i &p_substr, Vector2 p_offset, int p_line_limit, int line_spacing) {
+ for (int i = get_lines_skipped(); i < p_line_limit; i++) {
+ RID line = get_line_rid(i);
+ Vector<Vector2> ranges = TS->shaped_text_get_selection(line, p_substr.x, p_substr.x + p_substr.y);
+ Rect2 line_rect = get_line_rect(i);
+ for (const Vector2 &range : ranges) {
+ Rect2 rect = Rect2(Point2(range.x, 0) + line_rect.position, Size2(range.y - range.x, line_rect.size.y));
+ rect.position = p_offset + line_rect.position;
+ rect.position.x += range.x;
+ rect.size = Size2(range.y - range.x, line_rect.size.y);
+ rect.size.x = MIN(rect.size.x, line_rect.size.x - range.x);
+ if (rect.size.x > 0) {
+ draw_rect(rect, Color(1, 1, 1, 0.07), true);
+ draw_rect(rect, Color(0.5, 0.7, 1.0, 0.4), false, 1);
+ }
+ }
+ p_offset.y += line_spacing + TS->shaped_text_get_ascent(line) + TS->shaped_text_get_descent(line);
+ }
+}
+
+void HighlightedLabel::add_highlight(const Vector2i &p_interval) {
+ if (p_interval.y > 0) {
+ highlights.append(p_interval);
+ queue_redraw();
+ }
+}
+
+void HighlightedLabel::reset_highlights() {
+ highlights.clear();
+ queue_redraw();
+}
+
+void HighlightedLabel::_notification(int p_notification) {
+ if (p_notification == NOTIFICATION_DRAW) {
+ if (highlights.is_empty()) {
+ return;
+ }
+
+ Vector2 offset;
+ int line_limit;
+ int line_spacing;
+ get_layout_data(offset, line_limit, line_spacing);
+
+ for (const Vector2i &substr : highlights) {
+ draw_substr_rects(substr, offset, line_limit, line_spacing);
+ }
+ }
+}
+
EditorQuickOpenDialog::EditorQuickOpenDialog() {
VBoxContainer *vbc = memnew(VBoxContainer);
vbc->add_theme_constant_override("separation", 0);
@@ -100,7 +150,7 @@ void EditorQuickOpenDialog::popup_dialog(const Vector<StringName> &p_base_types,
get_ok_button()->set_disabled(container->has_nothing_selected());
set_title(get_dialog_title(p_base_types));
- popup_centered_clamped(Size2(710, 650) * EDSCALE, 0.8f);
+ popup_centered_clamped(Size2(780, 650) * EDSCALE, 0.8f);
search_box->grab_focus();
}
@@ -119,13 +169,18 @@ void EditorQuickOpenDialog::cancel_pressed() {
}
void EditorQuickOpenDialog::_search_box_text_changed(const String &p_query) {
- container->update_results(p_query.to_lower());
-
+ container->set_query_and_update(p_query);
get_ok_button()->set_disabled(container->has_nothing_selected());
}
//------------------------- Result Container
+void style_button(Button *p_button) {
+ p_button->set_flat(true);
+ p_button->set_focus_mode(Control::FOCUS_NONE);
+ p_button->set_default_cursor_shape(Control::CURSOR_POINTING_HAND);
+}
+
QuickOpenResultContainer::QuickOpenResultContainer() {
set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -175,91 +230,107 @@ QuickOpenResultContainer::QuickOpenResultContainer() {
}
{
- // Bottom bar
- HBoxContainer *bottom_bar = memnew(HBoxContainer);
- add_child(bottom_bar);
-
+ // Selected filepath
file_details_path = memnew(Label);
file_details_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
file_details_path->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
file_details_path->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
- bottom_bar->add_child(file_details_path);
+ add_child(file_details_path);
+ }
- {
- HBoxContainer *hbc = memnew(HBoxContainer);
- hbc->add_theme_constant_override("separation", 3);
- bottom_bar->add_child(hbc);
-
- include_addons_toggle = memnew(CheckButton);
- include_addons_toggle->set_flat(true);
- include_addons_toggle->set_focus_mode(Control::FOCUS_NONE);
- include_addons_toggle->set_default_cursor_shape(CURSOR_POINTING_HAND);
- include_addons_toggle->set_tooltip_text(TTR("Include files from addons"));
- include_addons_toggle->connect(SceneStringName(toggled), callable_mp(this, &QuickOpenResultContainer::_toggle_include_addons));
- hbc->add_child(include_addons_toggle);
-
- VSeparator *vsep = memnew(VSeparator);
- vsep->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
- vsep->set_custom_minimum_size(Size2i(0, 14 * EDSCALE));
- hbc->add_child(vsep);
-
- display_mode_toggle = memnew(Button);
- display_mode_toggle->set_flat(true);
- display_mode_toggle->set_focus_mode(Control::FOCUS_NONE);
- display_mode_toggle->set_default_cursor_shape(CURSOR_POINTING_HAND);
- display_mode_toggle->connect(SceneStringName(pressed), callable_mp(this, &QuickOpenResultContainer::_toggle_display_mode));
- hbc->add_child(display_mode_toggle);
- }
+ {
+ // Bottom bar
+ HBoxContainer *bottom_bar = memnew(HBoxContainer);
+ bottom_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ bottom_bar->set_alignment(ALIGNMENT_END);
+ bottom_bar->add_theme_constant_override("separation", 3);
+ add_child(bottom_bar);
+
+ fuzzy_search_toggle = memnew(CheckButton);
+ style_button(fuzzy_search_toggle);
+ fuzzy_search_toggle->set_text(TTR("Fuzzy Search"));
+ fuzzy_search_toggle->set_tooltip_text(TTR("Enable fuzzy matching"));
+ fuzzy_search_toggle->connect(SceneStringName(toggled), callable_mp(this, &QuickOpenResultContainer::_toggle_fuzzy_search));
+ bottom_bar->add_child(fuzzy_search_toggle);
+
+ include_addons_toggle = memnew(CheckButton);
+ style_button(include_addons_toggle);
+ include_addons_toggle->set_text(TTR("Addons"));
+ include_addons_toggle->set_tooltip_text(TTR("Include files from addons"));
+ include_addons_toggle->connect(SceneStringName(toggled), callable_mp(this, &QuickOpenResultContainer::_toggle_include_addons));
+ bottom_bar->add_child(include_addons_toggle);
+
+ VSeparator *vsep = memnew(VSeparator);
+ vsep->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ vsep->set_custom_minimum_size(Size2i(0, 14 * EDSCALE));
+ bottom_bar->add_child(vsep);
+
+ display_mode_toggle = memnew(Button);
+ style_button(display_mode_toggle);
+ display_mode_toggle->connect(SceneStringName(pressed), callable_mp(this, &QuickOpenResultContainer::_toggle_display_mode));
+ bottom_bar->add_child(display_mode_toggle);
}
+}
- // Creating and deleting nodes while searching is slow, so we allocate
- // a bunch of result nodes and fill in the content based on result ranking.
- result_items.resize(TOTAL_ALLOCATED_RESULT_ITEMS);
- for (int i = 0; i < TOTAL_ALLOCATED_RESULT_ITEMS; i++) {
+void QuickOpenResultContainer::_ensure_result_vector_capacity() {
+ int target_size = EDITOR_GET("filesystem/quick_open_dialog/max_results");
+ int initial_size = result_items.size();
+ for (int i = target_size; i < initial_size; i++) {
+ result_items[i]->queue_free();
+ }
+ result_items.resize(target_size);
+ for (int i = initial_size; i < target_size; i++) {
QuickOpenResultItem *item = memnew(QuickOpenResultItem);
item->connect(SceneStringName(gui_input), callable_mp(this, &QuickOpenResultContainer::_item_input).bind(i));
result_items.write[i] = item;
- }
-}
-
-QuickOpenResultContainer::~QuickOpenResultContainer() {
- if (never_opened) {
- for (QuickOpenResultItem *E : result_items) {
- memdelete(E);
+ if (!never_opened) {
+ _layout_result_item(item);
}
}
}
void QuickOpenResultContainer::init(const Vector<StringName> &p_base_types) {
+ _ensure_result_vector_capacity();
base_types = p_base_types;
- never_opened = false;
const int display_mode_behavior = EDITOR_GET("filesystem/quick_open_dialog/default_display_mode");
const bool adaptive_display_mode = (display_mode_behavior == 0);
if (adaptive_display_mode) {
_set_display_mode(get_adaptive_display_mode(p_base_types));
+ } else if (never_opened) {
+ int last = EditorSettings::get_singleton()->get_project_metadata("quick_open_dialog", "last_mode", (int)QuickOpenDisplayMode::LIST);
+ _set_display_mode((QuickOpenDisplayMode)last);
}
+ const bool fuzzy_matching = EDITOR_GET("filesystem/quick_open_dialog/enable_fuzzy_matching");
const bool include_addons = EDITOR_GET("filesystem/quick_open_dialog/include_addons");
+ fuzzy_search_toggle->set_pressed_no_signal(fuzzy_matching);
include_addons_toggle->set_pressed_no_signal(include_addons);
+ never_opened = false;
- _create_initial_results(include_addons);
+ const bool enable_highlights = EDITOR_GET("filesystem/quick_open_dialog/show_search_highlight");
+ for (QuickOpenResultItem *E : result_items) {
+ E->enable_highlights = enable_highlights;
+ }
+
+ _create_initial_results();
}
-void QuickOpenResultContainer::_create_initial_results(bool p_include_addons) {
- file_type_icons.insert("__default_icon", get_editor_theme_icon(SNAME("Object")));
- _find_candidates_in_folder(EditorFileSystem::get_singleton()->get_filesystem(), p_include_addons);
- max_total_results = MIN(candidates.size(), TOTAL_ALLOCATED_RESULT_ITEMS);
+void QuickOpenResultContainer::_create_initial_results() {
file_type_icons.clear();
-
- update_results(query);
+ file_type_icons.insert("__default_icon", get_editor_theme_icon(SNAME("Object")));
+ filepaths.clear();
+ filetypes.clear();
+ _find_filepaths_in_folder(EditorFileSystem::get_singleton()->get_filesystem(), include_addons_toggle->is_pressed());
+ max_total_results = MIN(filepaths.size(), result_items.size());
+ update_results();
}
-void QuickOpenResultContainer::_find_candidates_in_folder(EditorFileSystemDirectory *p_directory, bool p_include_addons) {
+void QuickOpenResultContainer::_find_filepaths_in_folder(EditorFileSystemDirectory *p_directory, bool p_include_addons) {
for (int i = 0; i < p_directory->get_subdir_count(); i++) {
if (p_include_addons || p_directory->get_name() != "addons") {
- _find_candidates_in_folder(p_directory->get_subdir(i), p_include_addons);
+ _find_filepaths_in_folder(p_directory->get_subdir(i), p_include_addons);
}
}
@@ -276,146 +347,91 @@ void QuickOpenResultContainer::_find_candidates_in_folder(EditorFileSystemDirect
bool is_valid = ClassDB::is_parent_class(engine_type, parent_type) || (!is_engine_type && EditorNode::get_editor_data().script_class_is_parent(script_type, parent_type));
if (is_valid) {
- Candidate c;
- c.file_name = file_path.get_file();
- c.file_directory = file_path.get_base_dir();
-
- EditorResourcePreview::PreviewItem item = EditorResourcePreview::get_singleton()->get_resource_preview_if_available(file_path);
- if (item.preview.is_valid()) {
- c.thumbnail = item.preview;
- } else if (file_type_icons.has(actual_type)) {
- c.thumbnail = *file_type_icons.lookup_ptr(actual_type);
- } else if (has_theme_icon(actual_type, EditorStringName(EditorIcons))) {
- c.thumbnail = get_editor_theme_icon(actual_type);
- file_type_icons.insert(actual_type, c.thumbnail);
- } else {
- c.thumbnail = *file_type_icons.lookup_ptr("__default_icon");
- }
-
- candidates.push_back(c);
-
+ filepaths.append(file_path);
+ filetypes.insert(file_path, actual_type);
break; // Stop testing base types as soon as we get a match.
}
}
}
}
-void QuickOpenResultContainer::update_results(const String &p_query) {
+void QuickOpenResultContainer::set_query_and_update(const String &p_query) {
query = p_query;
-
- int relevant_candidates = _sort_candidates(p_query);
- _update_result_items(MIN(relevant_candidates, max_total_results), 0);
-}
-
-int QuickOpenResultContainer::_sort_candidates(const String &p_query) {
- if (p_query.is_empty()) {
- return 0;
+ update_results();
+}
+
+void QuickOpenResultContainer::_setup_candidate(QuickOpenResultCandidate &candidate, const String &filepath) {
+ StringName actual_type = *filetypes.lookup_ptr(filepath);
+ candidate.file_path = filepath;
+ candidate.result = nullptr;
+
+ EditorResourcePreview::PreviewItem item = EditorResourcePreview::get_singleton()->get_resource_preview_if_available(filepath);
+ if (item.preview.is_valid()) {
+ candidate.thumbnail = item.preview;
+ } else if (file_type_icons.has(actual_type)) {
+ candidate.thumbnail = *file_type_icons.lookup_ptr(actual_type);
+ } else if (has_theme_icon(actual_type, EditorStringName(EditorIcons))) {
+ candidate.thumbnail = get_editor_theme_icon(actual_type);
+ file_type_icons.insert(actual_type, candidate.thumbnail);
+ } else {
+ candidate.thumbnail = *file_type_icons.lookup_ptr("__default_icon");
}
+}
- const PackedStringArray search_tokens = p_query.to_lower().replace("/", " ").split(" ", false);
+void QuickOpenResultContainer::_setup_candidate(QuickOpenResultCandidate &p_candidate, const FuzzySearchResult &p_result) {
+ _setup_candidate(p_candidate, p_result.target);
+ p_candidate.result = &p_result;
+}
- if (search_tokens.is_empty()) {
- return 0;
+void QuickOpenResultContainer::update_results() {
+ showing_history = false;
+ candidates.clear();
+ if (query.is_empty()) {
+ _use_default_candidates();
+ } else {
+ _score_and_sort_candidates();
}
+ _update_result_items(MIN(candidates.size(), max_total_results), 0);
+}
- // First, we assign a score to each candidate.
- int num_relevant_candidates = 0;
- for (Candidate &c : candidates) {
- c.score = 0;
- int prev_token_match_pos = -1;
-
- for (const String &token : search_tokens) {
- const int file_pos = c.file_name.findn(token);
- const int dir_pos = c.file_directory.findn(token);
-
- const bool file_match = file_pos > -1;
- const bool dir_match = dir_pos > -1;
- if (!file_match && !dir_match) {
- c.score = -1.0f;
- break;
- }
-
- float token_score = file_match ? 0.6f : 0.1999f;
-
- // Add bias for shorter filenames/paths: they resemble the query more.
- const String &matched_string = file_match ? c.file_name : c.file_directory;
- int matched_string_token_pos = file_match ? file_pos : dir_pos;
- token_score += 0.1f * (1.0f - ((float)matched_string_token_pos / (float)matched_string.length()));
-
- // Add bias if the match happened in the file name, not the extension.
- if (file_match) {
- int ext_pos = matched_string.rfind(".");
- if (ext_pos == -1 || ext_pos > matched_string_token_pos) {
- token_score += 0.1f;
- }
- }
-
- // Add bias if token is in order.
- {
- int candidate_string_token_pos = file_match ? (c.file_directory.length() + file_pos) : dir_pos;
-
- if (prev_token_match_pos != -1 && candidate_string_token_pos > prev_token_match_pos) {
- token_score += 0.2f;
- }
-
- prev_token_match_pos = candidate_string_token_pos;
- }
-
- c.score += token_score;
+void QuickOpenResultContainer::_use_default_candidates() {
+ if (filepaths.size() <= SHOW_ALL_FILES_THRESHOLD) {
+ candidates.resize(filepaths.size());
+ QuickOpenResultCandidate *candidates_write = candidates.ptrw();
+ for (const String &filepath : filepaths) {
+ _setup_candidate(*candidates_write++, filepath);
}
-
- if (c.score > 0.0f) {
- num_relevant_candidates++;
+ } else if (base_types.size() == 1) {
+ Vector<QuickOpenResultCandidate> *history = selected_history.lookup_ptr(base_types[0]);
+ if (history) {
+ showing_history = true;
+ candidates.append_array(*history);
}
}
-
- // Now we will sort the candidates based on score, resolving ties by favoring:
- // 1. Shorter file length.
- // 2. Shorter directory length.
- // 3. Lower alphabetic order.
- struct CandidateComparator {
- _FORCE_INLINE_ bool operator()(const Candidate &p_a, const Candidate &p_b) const {
- if (!Math::is_equal_approx(p_a.score, p_b.score)) {
- return p_a.score > p_b.score;
- }
-
- if (p_a.file_name.length() != p_b.file_name.length()) {
- return p_a.file_name.length() < p_b.file_name.length();
- }
-
- if (p_a.file_directory.length() != p_b.file_directory.length()) {
- return p_a.file_directory.length() < p_b.file_directory.length();
- }
-
- return p_a.file_name < p_b.file_name;
- }
- };
- candidates.sort_custom<CandidateComparator>();
-
- return num_relevant_candidates;
}
-void QuickOpenResultContainer::_update_result_items(int p_new_visible_results_count, int p_new_selection_index) {
- List<Candidate> *type_history = nullptr;
-
- showing_history = false;
-
- if (query.is_empty()) {
- if (candidates.size() <= SHOW_ALL_FILES_THRESHOLD) {
- p_new_visible_results_count = candidates.size();
- } else {
- p_new_visible_results_count = 0;
+void QuickOpenResultContainer::_update_fuzzy_search_results() {
+ FuzzySearch fuzzy_search;
+ fuzzy_search.start_offset = 6; // Don't match against "res://" at the start of each filepath.
+ fuzzy_search.set_query(query);
+ fuzzy_search.max_results = max_total_results;
+ bool fuzzy_matching = EDITOR_GET("filesystem/quick_open_dialog/enable_fuzzy_matching");
+ int max_misses = EDITOR_GET("filesystem/quick_open_dialog/max_fuzzy_misses");
+ fuzzy_search.allow_subsequences = fuzzy_matching;
+ fuzzy_search.max_misses = fuzzy_matching ? max_misses : 0;
+ fuzzy_search.search_all(filepaths, search_results);
+}
- if (base_types.size() == 1) {
- type_history = selected_history.lookup_ptr(base_types[0]);
- if (type_history) {
- p_new_visible_results_count = type_history->size();
- showing_history = true;
- }
- }
- }
+void QuickOpenResultContainer::_score_and_sort_candidates() {
+ _update_fuzzy_search_results();
+ candidates.resize(search_results.size());
+ QuickOpenResultCandidate *candidates_write = candidates.ptrw();
+ for (const FuzzySearchResult &result : search_results) {
+ _setup_candidate(*candidates_write++, result);
}
+}
+void QuickOpenResultContainer::_update_result_items(int p_new_visible_results_count, int p_new_selection_index) {
// Only need to update items that were not hidden in previous update.
int num_items_needing_updates = MAX(num_visible_results, p_new_visible_results_count);
num_visible_results = p_new_visible_results_count;
@@ -424,13 +440,7 @@ void QuickOpenResultContainer::_update_result_items(int p_new_visible_results_co
QuickOpenResultItem *item = result_items[i];
if (i < num_visible_results) {
- if (type_history) {
- const Candidate &c = type_history->get(i);
- item->set_content(c.thumbnail, c.file_name, c.file_directory);
- } else {
- const Candidate &c = candidates[i];
- item->set_content(c.thumbnail, c.file_name, c.file_directory);
- }
+ item->set_content(candidates[i]);
} else {
item->reset();
}
@@ -443,7 +453,7 @@ void QuickOpenResultContainer::_update_result_items(int p_new_visible_results_co
no_results_container->set_visible(!any_results);
if (!any_results) {
- if (candidates.is_empty()) {
+ if (filepaths.is_empty()) {
no_results_label->set_text(TTR("No files found for this type"));
} else if (query.is_empty()) {
no_results_label->set_text(TTR("Start searching to find files..."));
@@ -471,10 +481,12 @@ void QuickOpenResultContainer::handle_search_box_input(const Ref<InputEvent> &p_
} break;
case Key::LEFT:
case Key::RIGHT: {
- // Both grid and the search box use left/right keys. By default, grid will take it.
- // It would be nice if we could check for ALT to give the event to the searchbox cursor.
- // However, if you press ALT, the searchbox also denies the input.
- move_selection = (content_display_mode == QuickOpenDisplayMode::GRID);
+ if (content_display_mode == QuickOpenDisplayMode::GRID) {
+ // Maybe strip off the shift modifier to allow non-selecting navigation by character?
+ if (key_event->get_modifiers_mask() == 0) {
+ move_selection = true;
+ }
+ }
} break;
default:
break; // Let the event through so it will reach the search box.
@@ -489,6 +501,10 @@ void QuickOpenResultContainer::handle_search_box_input(const Ref<InputEvent> &p_
}
void QuickOpenResultContainer::_move_selection_index(Key p_key) {
+ // Don't move selection if there are no results.
+ if (num_visible_results <= 0) {
+ return;
+ }
const int max_index = num_visible_results - 1;
int idx = selection_index;
@@ -562,11 +578,15 @@ void QuickOpenResultContainer::_item_input(const Ref<InputEvent> &p_ev, int p_in
}
}
+void QuickOpenResultContainer::_toggle_fuzzy_search(bool p_pressed) {
+ EditorSettings::get_singleton()->set("filesystem/quick_open_dialog/enable_fuzzy_matching", p_pressed);
+ update_results();
+}
+
void QuickOpenResultContainer::_toggle_include_addons(bool p_pressed) {
EditorSettings::get_singleton()->set("filesystem/quick_open_dialog/include_addons", p_pressed);
-
cleanup();
- _create_initial_results(p_pressed);
+ _create_initial_results();
}
void QuickOpenResultContainer::_toggle_display_mode() {
@@ -574,49 +594,49 @@ void QuickOpenResultContainer::_toggle_display_mode() {
_set_display_mode(new_display_mode);
}
-void QuickOpenResultContainer::_set_display_mode(QuickOpenDisplayMode p_display_mode) {
- content_display_mode = p_display_mode;
+CanvasItem *QuickOpenResultContainer::_get_result_root() {
+ if (content_display_mode == QuickOpenDisplayMode::LIST) {
+ return list;
+ } else {
+ return grid;
+ }
+}
- const bool show_list = (content_display_mode == QuickOpenDisplayMode::LIST);
- if ((show_list && list->is_visible()) || (!show_list && grid->is_visible())) {
- return;
+void QuickOpenResultContainer::_layout_result_item(QuickOpenResultItem *item) {
+ item->set_display_mode(content_display_mode);
+ Node *parent = item->get_parent();
+ if (parent) {
+ parent->remove_child(item);
}
+ _get_result_root()->add_child(item);
+}
- hide();
+void QuickOpenResultContainer::_set_display_mode(QuickOpenDisplayMode p_display_mode) {
+ CanvasItem *prev_root = _get_result_root();
- // Move result item nodes from one container to the other.
- CanvasItem *prev_root;
- CanvasItem *next_root;
- if (content_display_mode == QuickOpenDisplayMode::LIST) {
- prev_root = Object::cast_to<CanvasItem>(grid);
- next_root = Object::cast_to<CanvasItem>(list);
- } else {
- prev_root = Object::cast_to<CanvasItem>(list);
- next_root = Object::cast_to<CanvasItem>(grid);
+ if (prev_root->is_visible() && content_display_mode == p_display_mode) {
+ return;
}
- const bool first_time = !list->is_visible() && !grid->is_visible();
+ content_display_mode = p_display_mode;
+ CanvasItem *next_root = _get_result_root();
- prev_root->hide();
- for (QuickOpenResultItem *item : result_items) {
- item->set_display_mode(content_display_mode);
+ EditorSettings::get_singleton()->set_project_metadata("quick_open_dialog", "last_mode", (int)content_display_mode);
- if (!first_time) {
- prev_root->remove_child(item);
- }
+ prev_root->hide();
+ next_root->show();
- next_root->add_child(item);
+ for (QuickOpenResultItem *item : result_items) {
+ _layout_result_item(item);
}
- next_root->show();
- show();
_update_result_items(num_visible_results, selection_index);
if (content_display_mode == QuickOpenDisplayMode::LIST) {
- display_mode_toggle->set_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
+ display_mode_toggle->set_button_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
display_mode_toggle->set_tooltip_text(TTR("Grid view"));
} else {
- display_mode_toggle->set_icon(get_editor_theme_icon(SNAME("FileList")));
+ display_mode_toggle->set_button_icon(get_editor_theme_icon(SNAME("FileList")));
display_mode_toggle->set_tooltip_text(TTR("List view"));
}
}
@@ -627,16 +647,7 @@ bool QuickOpenResultContainer::has_nothing_selected() const {
String QuickOpenResultContainer::get_selected() const {
ERR_FAIL_COND_V_MSG(has_nothing_selected(), String(), "Tried to get selected file, but nothing was selected.");
-
- if (showing_history) {
- const List<Candidate> *type_history = selected_history.lookup_ptr(base_types[0]);
-
- const Candidate &c = type_history->get(selection_index);
- return c.file_directory.path_join(c.file_name);
- } else {
- const Candidate &c = candidates[selection_index];
- return c.file_directory.path_join(c.file_name);
- }
+ return candidates[selection_index].file_path;
}
QuickOpenDisplayMode QuickOpenResultContainer::get_adaptive_display_mode(const Vector<StringName> &p_base_types) {
@@ -649,8 +660,9 @@ QuickOpenDisplayMode QuickOpenResultContainer::get_adaptive_display_mode(const V
for (const StringName &type : grid_preferred_types) {
for (const StringName &base_type : p_base_types) {
- if (base_type == type || ClassDB::is_parent_class(base_type, type))
+ if (base_type == type || ClassDB::is_parent_class(base_type, type)) {
return QuickOpenDisplayMode::GRID;
+ }
}
}
@@ -664,32 +676,27 @@ void QuickOpenResultContainer::save_selected_item() {
return;
}
- if (showing_history) {
- // Selecting from history, so already added.
- return;
- }
-
const StringName &base_type = base_types[0];
+ const QuickOpenResultCandidate &selected = candidates[selection_index];
+ Vector<QuickOpenResultCandidate> *type_history = selected_history.lookup_ptr(base_type);
- List<Candidate> *type_history = selected_history.lookup_ptr(base_type);
if (!type_history) {
- selected_history.insert(base_type, List<Candidate>());
+ selected_history.insert(base_type, Vector<QuickOpenResultCandidate>());
type_history = selected_history.lookup_ptr(base_type);
} else {
- const Candidate &selected = candidates[selection_index];
-
- for (const Candidate &candidate : *type_history) {
- if (candidate.file_directory == selected.file_directory && candidate.file_name == selected.file_name) {
- return;
+ for (int i = 0; i < type_history->size(); i++) {
+ if (selected.file_path == type_history->get(i).file_path) {
+ type_history->remove_at(i);
+ break;
}
}
-
- if (type_history->size() > 8) {
- type_history->pop_back();
- }
}
- type_history->push_front(candidates[selection_index]);
+ type_history->insert(0, selected);
+ type_history->ptrw()->result = nullptr;
+ if (type_history->size() > MAX_HISTORY_SIZE) {
+ type_history->resize(MAX_HISTORY_SIZE);
+ }
}
void QuickOpenResultContainer::cleanup() {
@@ -712,9 +719,9 @@ void QuickOpenResultContainer::_notification(int p_what) {
panel_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
if (content_display_mode == QuickOpenDisplayMode::LIST) {
- display_mode_toggle->set_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
+ display_mode_toggle->set_button_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
} else {
- display_mode_toggle->set_icon(get_editor_theme_icon(SNAME("FileList")));
+ display_mode_toggle->set_button_icon(get_editor_theme_icon(SNAME("FileList")));
}
} break;
}
@@ -743,36 +750,35 @@ QuickOpenResultItem::QuickOpenResultItem() {
void QuickOpenResultItem::set_display_mode(QuickOpenDisplayMode p_display_mode) {
if (p_display_mode == QuickOpenDisplayMode::LIST) {
grid_item->hide();
+ grid_item->reset();
list_item->show();
} else {
list_item->hide();
+ list_item->reset();
grid_item->show();
}
queue_redraw();
}
-void QuickOpenResultItem::set_content(const Ref<Texture2D> &p_thumbnail, const String &p_file, const String &p_file_directory) {
+void QuickOpenResultItem::set_content(const QuickOpenResultCandidate &p_candidate) {
_set_enabled(true);
if (list_item->is_visible()) {
- list_item->set_content(p_thumbnail, p_file, p_file_directory);
+ list_item->set_content(p_candidate, enable_highlights);
} else {
- grid_item->set_content(p_thumbnail, p_file);
+ grid_item->set_content(p_candidate, enable_highlights);
}
+
+ queue_redraw();
}
void QuickOpenResultItem::reset() {
_set_enabled(false);
-
is_hovering = false;
is_selected = false;
-
- if (list_item->is_visible()) {
- list_item->reset();
- } else {
- grid_item->reset();
- }
+ list_item->reset();
+ grid_item->reset();
}
void QuickOpenResultItem::highlight_item(bool p_enabled) {
@@ -825,6 +831,22 @@ void QuickOpenResultItem::_notification(int p_what) {
//----------------- List item
+static Vector2i _get_path_interval(const Vector2i &p_interval, int p_dir_index) {
+ if (p_interval.x >= p_dir_index || p_interval.y < 1) {
+ return { -1, -1 };
+ }
+ return { p_interval.x, MIN(p_interval.x + p_interval.y, p_dir_index) - p_interval.x };
+}
+
+static Vector2i _get_name_interval(const Vector2i &p_interval, int p_dir_index) {
+ if (p_interval.x + p_interval.y <= p_dir_index || p_interval.y < 1) {
+ return { -1, -1 };
+ }
+ int first_name_idx = p_dir_index + 1;
+ int start = MAX(p_interval.x, first_name_idx);
+ return { start - first_name_idx, p_interval.y - start + p_interval.x };
+}
+
QuickOpenResultListItem::QuickOpenResultListItem() {
set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_theme_constant_override("separation", 4 * EDSCALE);
@@ -852,13 +874,13 @@ QuickOpenResultListItem::QuickOpenResultListItem() {
text_container->set_v_size_flags(Control::SIZE_FILL);
add_child(text_container);
- name = memnew(Label);
+ name = memnew(HighlightedLabel);
name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
name->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
name->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_LEFT);
text_container->add_child(name);
- path = memnew(Label);
+ path = memnew(HighlightedLabel);
path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
path->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
path->add_theme_font_size_override(SceneStringName(font_size), 12 * EDSCALE);
@@ -866,18 +888,29 @@ QuickOpenResultListItem::QuickOpenResultListItem() {
}
}
-void QuickOpenResultListItem::set_content(const Ref<Texture2D> &p_thumbnail, const String &p_file, const String &p_file_directory) {
- thumbnail->set_texture(p_thumbnail);
- name->set_text(p_file);
- path->set_text(p_file_directory);
+void QuickOpenResultListItem::set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight) {
+ thumbnail->set_texture(p_candidate.thumbnail);
+ name->set_text(p_candidate.file_path.get_file());
+ path->set_text(p_candidate.file_path.get_base_dir());
+ name->reset_highlights();
+ path->reset_highlights();
+
+ if (p_highlight && p_candidate.result != nullptr) {
+ for (const FuzzyTokenMatch &match : p_candidate.result->token_matches) {
+ for (const Vector2i &interval : match.substrings) {
+ path->add_highlight(_get_path_interval(interval, p_candidate.result->dir_index));
+ name->add_highlight(_get_name_interval(interval, p_candidate.result->dir_index));
+ }
+ }
+ }
const int max_size = 32 * EDSCALE;
- bool uses_icon = p_thumbnail->get_width() < max_size;
+ bool uses_icon = p_candidate.thumbnail->get_width() < max_size;
if (uses_icon) {
- thumbnail->set_custom_minimum_size(p_thumbnail->get_size());
+ thumbnail->set_custom_minimum_size(p_candidate.thumbnail->get_size());
- int margin_needed = (max_size - p_thumbnail->get_width()) / 2;
+ int margin_needed = (max_size - p_candidate.thumbnail->get_width()) / 2;
image_container->add_theme_constant_override("margin_left", CONTAINER_MARGIN + margin_needed);
image_container->add_theme_constant_override("margin_right", margin_needed);
} else {
@@ -888,9 +921,11 @@ void QuickOpenResultListItem::set_content(const Ref<Texture2D> &p_thumbnail, con
}
void QuickOpenResultListItem::reset() {
- name->set_text("");
thumbnail->set_texture(nullptr);
+ name->set_text("");
path->set_text("");
+ name->reset_highlights();
+ path->reset_highlights();
}
void QuickOpenResultListItem::highlight_item(const Color &p_color) {
@@ -919,10 +954,10 @@ QuickOpenResultGridItem::QuickOpenResultGridItem() {
thumbnail = memnew(TextureRect);
thumbnail->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
thumbnail->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
- thumbnail->set_custom_minimum_size(Size2i(80 * EDSCALE, 64 * EDSCALE));
+ thumbnail->set_custom_minimum_size(Size2i(120 * EDSCALE, 64 * EDSCALE));
add_child(thumbnail);
- name = memnew(Label);
+ name = memnew(HighlightedLabel);
name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
name->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
name->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
@@ -930,16 +965,23 @@ QuickOpenResultGridItem::QuickOpenResultGridItem() {
add_child(name);
}
-void QuickOpenResultGridItem::set_content(const Ref<Texture2D> &p_thumbnail, const String &p_file) {
- thumbnail->set_texture(p_thumbnail);
+void QuickOpenResultGridItem::set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight) {
+ thumbnail->set_texture(p_candidate.thumbnail);
+ name->set_text(p_candidate.file_path.get_file());
+ name->set_tooltip_text(p_candidate.file_path);
+ name->reset_highlights();
- const String &file_name = p_file.get_basename();
- name->set_text(file_name);
- name->set_tooltip_text(file_name);
+ if (p_highlight && p_candidate.result != nullptr) {
+ for (const FuzzyTokenMatch &match : p_candidate.result->token_matches) {
+ for (const Vector2i &interval : match.substrings) {
+ name->add_highlight(_get_name_interval(interval, p_candidate.result->dir_index));
+ }
+ }
+ }
- bool uses_icon = p_thumbnail->get_width() < (32 * EDSCALE);
+ bool uses_icon = p_candidate.thumbnail->get_width() < (32 * EDSCALE);
- if (uses_icon || p_thumbnail->get_height() <= thumbnail->get_custom_minimum_size().y) {
+ if (uses_icon || p_candidate.thumbnail->get_height() <= thumbnail->get_custom_minimum_size().y) {
thumbnail->set_expand_mode(TextureRect::EXPAND_KEEP_SIZE);
thumbnail->set_stretch_mode(TextureRect::StretchMode::STRETCH_KEEP_CENTERED);
} else {
@@ -949,8 +991,9 @@ void QuickOpenResultGridItem::set_content(const Ref<Texture2D> &p_thumbnail, con
}
void QuickOpenResultGridItem::reset() {
- name->set_text("");
thumbnail->set_texture(nullptr);
+ name->set_text("");
+ name->reset_highlights();
}
void QuickOpenResultGridItem::highlight_item(const Color &p_color) {
diff --git a/editor/gui/editor_quick_open_dialog.h b/editor/gui/editor_quick_open_dialog.h
index 49257aed6b..3b3f927527 100644
--- a/editor/gui/editor_quick_open_dialog.h
+++ b/editor/gui/editor_quick_open_dialog.h
@@ -48,6 +48,8 @@ class Texture2D;
class TextureRect;
class VBoxContainer;
+class FuzzySearchResult;
+
class QuickOpenResultItem;
enum class QuickOpenDisplayMode {
@@ -55,13 +57,35 @@ enum class QuickOpenDisplayMode {
LIST,
};
+struct QuickOpenResultCandidate {
+ String file_path;
+ Ref<Texture2D> thumbnail;
+ const FuzzySearchResult *result = nullptr;
+};
+
+class HighlightedLabel : public Label {
+ GDCLASS(HighlightedLabel, Label)
+
+ Vector<Vector2i> highlights;
+
+ void draw_substr_rects(const Vector2i &p_substr, Vector2 p_offset, int p_line_limit, int line_spacing);
+
+public:
+ void add_highlight(const Vector2i &p_interval);
+ void reset_highlights();
+
+protected:
+ void _notification(int p_notification);
+};
+
class QuickOpenResultContainer : public VBoxContainer {
GDCLASS(QuickOpenResultContainer, VBoxContainer)
public:
void init(const Vector<StringName> &p_base_types);
void handle_search_box_input(const Ref<InputEvent> &p_ie);
- void update_results(const String &p_query);
+ void set_query_and_update(const String &p_query);
+ void update_results();
bool has_nothing_selected() const;
String get_selected() const;
@@ -70,27 +94,21 @@ public:
void cleanup();
QuickOpenResultContainer();
- ~QuickOpenResultContainer();
protected:
void _notification(int p_what);
private:
- static const int TOTAL_ALLOCATED_RESULT_ITEMS = 100;
- static const int SHOW_ALL_FILES_THRESHOLD = 30;
-
- struct Candidate {
- String file_name;
- String file_directory;
-
- Ref<Texture2D> thumbnail;
- float score = 0;
- };
+ static constexpr int SHOW_ALL_FILES_THRESHOLD = 30;
+ static constexpr int MAX_HISTORY_SIZE = 20;
+ Vector<FuzzySearchResult> search_results;
Vector<StringName> base_types;
- Vector<Candidate> candidates;
+ Vector<String> filepaths;
+ OAHashMap<String, StringName> filetypes;
+ Vector<QuickOpenResultCandidate> candidates;
- OAHashMap<StringName, List<Candidate>> selected_history;
+ OAHashMap<StringName, Vector<QuickOpenResultCandidate>> selected_history;
String query;
int selection_index = -1;
@@ -114,15 +132,21 @@ private:
Label *file_details_path = nullptr;
Button *display_mode_toggle = nullptr;
CheckButton *include_addons_toggle = nullptr;
+ CheckButton *fuzzy_search_toggle = nullptr;
OAHashMap<StringName, Ref<Texture2D>> file_type_icons;
static QuickOpenDisplayMode get_adaptive_display_mode(const Vector<StringName> &p_base_types);
- void _create_initial_results(bool p_include_addons);
- void _find_candidates_in_folder(EditorFileSystemDirectory *p_directory, bool p_include_addons);
+ void _ensure_result_vector_capacity();
+ void _create_initial_results();
+ void _find_filepaths_in_folder(EditorFileSystemDirectory *p_directory, bool p_include_addons);
- int _sort_candidates(const String &p_query);
+ void _setup_candidate(QuickOpenResultCandidate &p_candidate, const String &p_filepath);
+ void _setup_candidate(QuickOpenResultCandidate &p_candidate, const FuzzySearchResult &p_result);
+ void _update_fuzzy_search_results();
+ void _use_default_candidates();
+ void _score_and_sort_candidates();
void _update_result_items(int p_new_visible_results_count, int p_new_selection_index);
void _move_selection_index(Key p_key);
@@ -130,9 +154,12 @@ private:
void _item_input(const Ref<InputEvent> &p_ev, int p_index);
+ CanvasItem *_get_result_root();
+ void _layout_result_item(QuickOpenResultItem *p_item);
void _set_display_mode(QuickOpenDisplayMode p_display_mode);
void _toggle_display_mode();
void _toggle_include_addons(bool p_pressed);
+ void _toggle_fuzzy_search(bool p_pressed);
static void _bind_methods();
};
@@ -143,14 +170,14 @@ class QuickOpenResultGridItem : public VBoxContainer {
public:
QuickOpenResultGridItem();
- void set_content(const Ref<Texture2D> &p_thumbnail, const String &p_file_name);
void reset();
+ void set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight);
void highlight_item(const Color &p_color);
void remove_highlight();
private:
TextureRect *thumbnail = nullptr;
- Label *name = nullptr;
+ HighlightedLabel *name = nullptr;
};
class QuickOpenResultListItem : public HBoxContainer {
@@ -159,8 +186,8 @@ class QuickOpenResultListItem : public HBoxContainer {
public:
QuickOpenResultListItem();
- void set_content(const Ref<Texture2D> &p_thumbnail, const String &p_file_name, const String &p_file_directory);
void reset();
+ void set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight);
void highlight_item(const Color &p_color);
void remove_highlight();
@@ -174,8 +201,8 @@ private:
VBoxContainer *text_container = nullptr;
TextureRect *thumbnail = nullptr;
- Label *name = nullptr;
- Label *path = nullptr;
+ HighlightedLabel *name = nullptr;
+ HighlightedLabel *path = nullptr;
};
class QuickOpenResultItem : public HBoxContainer {
@@ -184,10 +211,11 @@ class QuickOpenResultItem : public HBoxContainer {
public:
QuickOpenResultItem();
- void set_content(const Ref<Texture2D> &p_thumbnail, const String &p_file_name, const String &p_file_directory);
- void set_display_mode(QuickOpenDisplayMode p_display_mode);
- void reset();
+ bool enable_highlights = true;
+ void reset();
+ void set_content(const QuickOpenResultCandidate &p_candidate);
+ void set_display_mode(QuickOpenDisplayMode p_display_mode);
void highlight_item(bool p_enabled);
protected:
diff --git a/editor/gui/editor_run_bar.cpp b/editor/gui/editor_run_bar.cpp
index 908b1e6719..64135c8d50 100644
--- a/editor/gui/editor_run_bar.cpp
+++ b/editor/gui/editor_run_bar.cpp
@@ -52,8 +52,8 @@ void EditorRunBar::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
_update_play_buttons();
- pause_button->set_icon(get_editor_theme_icon(SNAME("Pause")));
- stop_button->set_icon(get_editor_theme_icon(SNAME("Stop")));
+ pause_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
+ stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
if (is_movie_maker_enabled()) {
main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles)));
@@ -63,7 +63,7 @@ void EditorRunBar::_notification(int p_what) {
write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles)));
}
- write_movie_button->set_icon(get_editor_theme_icon(SNAME("MainMovieWrite")));
+ write_movie_button->set_button_icon(get_editor_theme_icon(SNAME("MainMovieWrite")));
// This button behaves differently, so color it as such.
write_movie_button->begin_bulk_theme_override();
write_movie_button->add_theme_color_override("icon_normal_color", get_theme_color(SNAME("movie_writer_icon_normal"), EditorStringName(EditorStyles)));
@@ -77,15 +77,15 @@ void EditorRunBar::_notification(int p_what) {
void EditorRunBar::_reset_play_buttons() {
play_button->set_pressed(false);
- play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
play_button->set_tooltip_text(TTR("Play the project."));
play_scene_button->set_pressed(false);
- play_scene_button->set_icon(get_editor_theme_icon(SNAME("PlayScene")));
+ play_scene_button->set_button_icon(get_editor_theme_icon(SNAME("PlayScene")));
play_scene_button->set_tooltip_text(TTR("Play the edited scene."));
play_custom_scene_button->set_pressed(false);
- play_custom_scene_button->set_icon(get_editor_theme_icon(SNAME("PlayCustom")));
+ play_custom_scene_button->set_button_icon(get_editor_theme_icon(SNAME("PlayCustom")));
play_custom_scene_button->set_tooltip_text(TTR("Play a custom scene."));
}
@@ -106,7 +106,7 @@ void EditorRunBar::_update_play_buttons() {
if (active_button) {
active_button->set_pressed(true);
- active_button->set_icon(get_editor_theme_icon(SNAME("Reload")));
+ active_button->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
active_button->set_tooltip_text(TTR("Reload the played scene."));
}
}
diff --git a/editor/gui/editor_scene_tabs.cpp b/editor/gui/editor_scene_tabs.cpp
index 4862b3436e..5b42afdbe8 100644
--- a/editor/gui/editor_scene_tabs.cpp
+++ b/editor/gui/editor_scene_tabs.cpp
@@ -53,7 +53,7 @@ void EditorSceneTabs::_notification(int p_what) {
tabbar_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer")));
scene_tabs->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)));
- scene_tab_add->set_icon(get_editor_theme_icon(SNAME("Add")));
+ scene_tab_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
scene_tab_add->add_theme_color_override("icon_normal_color", Color(0.6f, 0.6f, 0.6f, 0.8f));
scene_tab_add_ph->set_custom_minimum_size(scene_tab_add->get_minimum_size());
diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp
index a073a2338b..712e91faca 100644
--- a/editor/gui/editor_spin_slider.cpp
+++ b/editor/gui/editor_spin_slider.cpp
@@ -37,10 +37,6 @@
#include "editor/themes/editor_scale.h"
#include "scene/theme/theme_db.h"
-bool EditorSpinSlider::is_text_field() const {
- return true;
-}
-
String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const {
if (!read_only && grabber->is_visible()) {
Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL;
@@ -441,7 +437,7 @@ void EditorSpinSlider::_draw_spin_slider() {
Vector2 scale = get_global_transform_with_canvas().get_scale();
grabber->set_scale(scale);
grabber->reset_size();
- grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
+ grabber->set_position((grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
if (mousewheel_over_grabber) {
Input::get_singleton()->warp_mouse(grabber->get_position() + grabber_rect.size);
@@ -735,7 +731,7 @@ EditorSpinSlider::EditorSpinSlider() {
grabber = memnew(TextureRect);
add_child(grabber);
grabber->hide();
- grabber->set_as_top_level(true);
+ grabber->set_z_index(1);
grabber->set_mouse_filter(MOUSE_FILTER_STOP);
grabber->connect(SceneStringName(mouse_entered), callable_mp(this, &EditorSpinSlider::_grabber_mouse_entered));
grabber->connect(SceneStringName(mouse_exited), callable_mp(this, &EditorSpinSlider::_grabber_mouse_exited));
diff --git a/editor/gui/editor_spin_slider.h b/editor/gui/editor_spin_slider.h
index 2476c2f71b..dfc50878dd 100644
--- a/editor/gui/editor_spin_slider.h
+++ b/editor/gui/editor_spin_slider.h
@@ -101,8 +101,6 @@ protected:
void _focus_entered();
public:
- virtual bool is_text_field() const override;
-
String get_tooltip(const Point2 &p_pos) const override;
String get_text_value() const;
diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp
index 24f19db578..ffea1736a3 100644
--- a/editor/gui/editor_toaster.cpp
+++ b/editor/gui/editor_toaster.cpp
@@ -108,14 +108,13 @@ void EditorToaster::_notification(int p_what) {
}
} break;
- case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (vbox_container->is_visible()) {
- main_button->set_icon(get_editor_theme_icon(SNAME("Notification")));
+ main_button->set_button_icon(get_editor_theme_icon(SNAME("Notification")));
} else {
- main_button->set_icon(get_editor_theme_icon(SNAME("NotificationDisabled")));
+ main_button->set_button_icon(get_editor_theme_icon(SNAME("NotificationDisabled")));
}
- disable_notifications_button->set_icon(get_editor_theme_icon(SNAME("NotificationDisabled")));
+ disable_notifications_button->set_button_icon(get_editor_theme_icon(SNAME("NotificationDisabled")));
// Styleboxes background.
info_panel_style_background->set_bg_color(get_theme_color(SNAME("base_color"), EditorStringName(Editor)));
@@ -134,9 +133,6 @@ void EditorToaster::_notification(int p_what) {
error_panel_style_progress->set_bg_color(get_theme_color(SNAME("base_color"), EditorStringName(Editor)).lightened(0.03));
error_panel_style_progress->set_border_color(get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
-
- main_button->queue_redraw();
- disable_notifications_button->queue_redraw();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -243,6 +239,7 @@ void EditorToaster::_auto_hide_or_free_toasts() {
main_button->set_tooltip_text(TTR("No notifications."));
main_button->set_modulate(Color(0.5, 0.5, 0.5));
main_button->set_disabled(true);
+ set_process_internal(false);
} else {
main_button->set_tooltip_text(TTR("Show notifications."));
main_button->set_modulate(Color(1, 1, 1));
@@ -311,9 +308,9 @@ void EditorToaster::_draw_progress(Control *panel) {
void EditorToaster::_set_notifications_enabled(bool p_enabled) {
vbox_container->set_visible(p_enabled);
if (p_enabled) {
- main_button->set_icon(get_editor_theme_icon(SNAME("Notification")));
+ main_button->set_button_icon(get_editor_theme_icon(SNAME("Notification")));
} else {
- main_button->set_icon(get_editor_theme_icon(SNAME("NotificationDisabled")));
+ main_button->set_button_icon(get_editor_theme_icon(SNAME("NotificationDisabled")));
}
_update_disable_notifications_button();
}
@@ -361,6 +358,9 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_
}
panel->set_modulate(Color(1, 1, 1, 0));
panel->connect(SceneStringName(draw), callable_mp(this, &EditorToaster::_draw_progress).bind(panel));
+ panel->connect(SceneStringName(theme_changed), callable_mp(this, &EditorToaster::_toast_theme_changed).bind(panel));
+
+ Toast &toast = toasts[panel];
// Horizontal container.
HBoxContainer *hbox_container = memnew(HBoxContainer);
@@ -375,20 +375,20 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_
if (p_time > 0.0) {
Button *close_button = memnew(Button);
close_button->set_flat(true);
- close_button->set_icon(get_editor_theme_icon(SNAME("Close")));
- close_button->connect(SceneStringName(pressed), callable_mp(this, &EditorToaster::close).bind(panel));
- close_button->connect(SceneStringName(theme_changed), callable_mp(this, &EditorToaster::_close_button_theme_changed).bind(close_button));
+ close_button->connect(SceneStringName(pressed), callable_mp(this, &EditorToaster::instant_close).bind(panel));
hbox_container->add_child(close_button);
+
+ toast.close_button = close_button;
}
- toasts[panel].severity = p_severity;
+ toast.severity = p_severity;
if (p_time > 0.0) {
- toasts[panel].duration = p_time;
- toasts[panel].remaining_time = p_time;
+ toast.duration = p_time;
+ toast.remaining_time = p_time;
} else {
- toasts[panel].duration = -1.0;
+ toast.duration = -1.0;
}
- toasts[panel].popped = true;
+ toast.popped = true;
vbox_container->add_child(panel);
_auto_hide_or_free_toasts();
_update_vbox_position();
@@ -406,7 +406,7 @@ void EditorToaster::popup_str(const String &p_message, Severity p_severity, cons
// Since "_popup_str" adds nodes to the tree, and since the "add_child" method is not
// thread-safe, it's better to defer the call to the next cycle to be thread-safe.
is_processing_error = true;
- MessageQueue::get_main_singleton()->push_callable(callable_mp(this, &EditorToaster::_popup_str).bind(p_message, p_severity, p_tooltip));
+ callable_mp(this, &EditorToaster::_popup_str).call_deferred(p_message, p_severity, p_tooltip);
is_processing_error = false;
}
@@ -433,19 +433,22 @@ void EditorToaster::_popup_str(const String &p_message, Severity p_severity, con
hb->add_child(count_label);
control = popup(hb, p_severity, default_message_duration, p_tooltip);
- toasts[control].message = p_message;
- toasts[control].tooltip = p_tooltip;
- toasts[control].count = 1;
- toasts[control].message_label = label;
- toasts[control].message_count_label = count_label;
+
+ Toast &toast = toasts[control];
+ toast.message = p_message;
+ toast.tooltip = p_tooltip;
+ toast.count = 1;
+ toast.message_label = label;
+ toast.message_count_label = count_label;
} else {
- if (toasts[control].popped) {
- toasts[control].count += 1;
+ Toast &toast = toasts[control];
+ if (toast.popped) {
+ toast.count += 1;
} else {
- toasts[control].count = 1;
+ toast.count = 1;
}
- toasts[control].remaining_time = toasts[control].duration;
- toasts[control].popped = true;
+ toast.remaining_time = toast.duration;
+ toast.popped = true;
control->show();
vbox_container->move_child(control, vbox_container->get_child_count());
_auto_hide_or_free_toasts();
@@ -480,6 +483,16 @@ void EditorToaster::_popup_str(const String &p_message, Severity p_severity, con
vbox_container->reset_size();
is_processing_error = false;
+ set_process_internal(true);
+}
+
+void EditorToaster::_toast_theme_changed(Control *p_control) {
+ ERR_FAIL_COND(!toasts.has(p_control));
+
+ Toast &toast = toasts[p_control];
+ if (toast.close_button) {
+ toast.close_button->set_button_icon(get_editor_theme_icon(SNAME("Close")));
+ }
}
void EditorToaster::close(Control *p_control) {
@@ -488,11 +501,9 @@ void EditorToaster::close(Control *p_control) {
toasts[p_control].popped = false;
}
-void EditorToaster::_close_button_theme_changed(Control *p_close_button) {
- Button *close_button = Object::cast_to<Button>(p_close_button);
- if (close_button) {
- close_button->set_icon(get_editor_theme_icon(SNAME("Close")));
- }
+void EditorToaster::instant_close(Control *p_control) {
+ close(p_control);
+ p_control->set_modulate(Color(1, 1, 1, 0));
}
EditorToaster *EditorToaster::get_singleton() {
@@ -501,7 +512,6 @@ EditorToaster *EditorToaster::get_singleton() {
EditorToaster::EditorToaster() {
set_notify_transform(true);
- set_process_internal(true);
// VBox.
vbox_container = memnew(VBoxContainer);
@@ -566,7 +576,7 @@ EditorToaster::EditorToaster() {
eh.errfunc = _error_handler;
add_error_handler(&eh);
-};
+}
EditorToaster::~EditorToaster() {
singleton = nullptr;
diff --git a/editor/gui/editor_toaster.h b/editor/gui/editor_toaster.h
index 4bf32d94ba..6fcc2ce3e9 100644
--- a/editor/gui/editor_toaster.h
+++ b/editor/gui/editor_toaster.h
@@ -31,8 +31,6 @@
#ifndef EDITOR_TOASTER_H
#define EDITOR_TOASTER_H
-#include "core/string/ustring.h"
-#include "core/templates/local_vector.h"
#include "scene/gui/box_container.h"
class Button;
@@ -76,6 +74,9 @@ private:
real_t remaining_time = 0.0;
bool popped = false;
+ // Buttons
+ Button *close_button = nullptr;
+
// Messages
String message;
String tooltip;
@@ -101,7 +102,7 @@ private:
void _set_notifications_enabled(bool p_enabled);
void _repop_old();
void _popup_str(const String &p_message, Severity p_severity, const String &p_tooltip);
- void _close_button_theme_changed(Control *p_close_button);
+ void _toast_theme_changed(Control *p_control);
protected:
static EditorToaster *singleton;
@@ -114,6 +115,7 @@ public:
Control *popup(Control *p_control, Severity p_severity = SEVERITY_INFO, double p_time = 0.0, const String &p_tooltip = String());
void popup_str(const String &p_message, Severity p_severity = SEVERITY_INFO, const String &p_tooltip = String());
void close(Control *p_control);
+ void instant_close(Control *p_control);
EditorToaster();
~EditorToaster();
diff --git a/editor/gui/editor_zoom_widget.cpp b/editor/gui/editor_zoom_widget.cpp
index 50a4f020ab..ff232a854f 100644
--- a/editor/gui/editor_zoom_widget.cpp
+++ b/editor/gui/editor_zoom_widget.cpp
@@ -162,8 +162,8 @@ void EditorZoomWidget::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- zoom_minus->set_icon(get_editor_theme_icon(SNAME("ZoomLess")));
- zoom_plus->set_icon(get_editor_theme_icon(SNAME("ZoomMore")));
+ zoom_minus->set_button_icon(get_editor_theme_icon(SNAME("ZoomLess")));
+ zoom_plus->set_button_icon(get_editor_theme_icon(SNAME("ZoomMore")));
} break;
}
}
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 2e36b66025..c11da5dfdb 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -369,16 +369,14 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
msg_temp += String::utf8("• ") + String(E.name) + "\n";
}
}
- }
- if (num_connections >= 1 || num_groups >= 1) {
- if (num_groups < 1) {
- msg_temp += "\n";
- }
- msg_temp += TTR("Click to show signals dock.");
+ } else {
+ msg_temp += "\n";
}
Ref<Texture2D> icon_temp;
SceneTreeEditorButton signal_temp = BUTTON_SIGNALS;
+ String msg_temp_end = TTR("Click to show signals dock.");
+
if (num_connections >= 1 && num_groups >= 1) {
icon_temp = get_editor_theme_icon(SNAME("SignalsAndGroups"));
} else if (num_connections >= 1) {
@@ -386,9 +384,11 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
} else if (num_groups >= 1) {
icon_temp = get_editor_theme_icon(SNAME("Groups"));
signal_temp = BUTTON_GROUPS;
+ msg_temp_end = TTR("Click to show groups dock.");
}
if (num_connections >= 1 || num_groups >= 1) {
+ msg_temp += msg_temp_end;
item->add_button(0, icon_temp, signal_temp, false, msg_temp);
}
}
@@ -1684,24 +1684,30 @@ void SceneTreeDialog::_show_all_nodes_changed(bool p_button_pressed) {
}
void SceneTreeDialog::set_valid_types(const Vector<StringName> &p_valid) {
- if (p_valid.is_empty()) {
- return;
+ if (allowed_types_hbox) {
+ allowed_types_hbox->queue_free();
+ allowed_types_hbox = nullptr;
+ valid_type_icons.clear();
}
tree->set_valid_types(p_valid);
- HBoxContainer *hbox = memnew(HBoxContainer);
- content->add_child(hbox);
- content->move_child(hbox, 0);
+ if (p_valid.is_empty()) {
+ return;
+ }
+
+ allowed_types_hbox = memnew(HBoxContainer);
+ content->add_child(allowed_types_hbox);
+ content->move_child(allowed_types_hbox, 0);
{
Label *label = memnew(Label);
- hbox->add_child(label);
+ allowed_types_hbox->add_child(label);
label->set_text(TTR("Allowed:"));
}
HFlowContainer *hflow = memnew(HFlowContainer);
- hbox->add_child(hflow);
+ allowed_types_hbox->add_child(hflow);
hflow->set_h_size_flags(Control::SIZE_EXPAND_FILL);
for (const StringName &type : p_valid) {
@@ -1735,6 +1741,9 @@ void SceneTreeDialog::set_valid_types(const Vector<StringName> &p_valid) {
}
show_all_nodes->show();
+ if (is_inside_tree()) {
+ _update_valid_type_icons();
+ }
}
void SceneTreeDialog::_notification(int p_what) {
@@ -1753,11 +1762,7 @@ void SceneTreeDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- for (TextureRect *trect : valid_type_icons) {
- trect->set_custom_minimum_size(Vector2(get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)), 0));
- trect->set_texture(trect->get_meta("icon"));
- }
+ _update_valid_type_icons();
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -1766,6 +1771,14 @@ void SceneTreeDialog::_notification(int p_what) {
}
}
+void SceneTreeDialog::_update_valid_type_icons() {
+ filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));
+ for (TextureRect *trect : valid_type_icons) {
+ trect->set_custom_minimum_size(Vector2(get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)), 0));
+ trect->set_texture(trect->get_meta("icon"));
+ }
+}
+
void SceneTreeDialog::_cancel() {
hide();
}
diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h
index e623c8405d..eed6d4b954 100644
--- a/editor/gui/scene_tree_editor.h
+++ b/editor/gui/scene_tree_editor.h
@@ -199,6 +199,7 @@ class SceneTreeDialog : public ConfirmationDialog {
LineEdit *filter = nullptr;
CheckButton *show_all_nodes = nullptr;
LocalVector<TextureRect *> valid_type_icons;
+ HBoxContainer *allowed_types_hbox = nullptr;
void _select();
void _cancel();
@@ -208,6 +209,7 @@ class SceneTreeDialog : public ConfirmationDialog {
void _show_all_nodes_changed(bool p_button_pressed);
protected:
+ void _update_valid_type_icons();
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/icons/2DNodes.svg b/editor/icons/2DNodes.svg
new file mode 100644
index 0000000000..90b92a4bc7
--- /dev/null
+++ b/editor/icons/2DNodes.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path fill="none" stroke="#8da5f3" stroke-width="2" d="M 8,13 C 5.2385763,13 3,10.761424 3,8 3,5.2385763 5.2385763,3 8,3"/><path fill="none" stroke="#8eef97" stroke-width="2" d="m 8,13 c 2.761424,0 5,-2.238576 5,-5 C 13,5.2385763 10.761424,3 8,3"/></svg> \ No newline at end of file
diff --git a/editor/icons/Camera.svg b/editor/icons/Camera.svg
new file mode 100644
index 0000000000..8612d458a7
--- /dev/null
+++ b/editor/icons/Camera.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path fill="#e0e0e0" d="M9 2a3 3 0 0 0-3 2.777 3 3 0 1 0-3 5.047V12a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-1l3 2V7l-3 2V7.23A3 3 0 0 0 9 2z"/></svg> \ No newline at end of file
diff --git a/editor/icons/FPS.svg b/editor/icons/FPS.svg
new file mode 100644
index 0000000000..5ee818c308
--- /dev/null
+++ b/editor/icons/FPS.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M7.25 4h-2v8h2v-2c1.656 0 3-1.344 3-3 0-1.657-1.344-3-3-3zm0 4v-2c.553 0 1 .448 1 1s-.447 1-1 1zM.25 7v5h2v-2h2v-2h-2v-1c0-.553.447-1 1-1h1v-2h-1c-1.656 0-3 1.344-3 3zM13.25 7c-.276 0-.5-.224-.5-.5s.224-.5.5-.5h2v-2h-2c-1.381 0-2.5 1.119-2.5 2.5s1.119 2.5 2.5 2.5c.276 0 .5.224.5.5s-.224.5-.5.5h-2v2h2c1.381 0 2.5-1.119 2.5-2.5s-1.119-2.5-2.5-2.5z"/></svg> \ No newline at end of file
diff --git a/editor/icons/FlipWinding.svg b/editor/icons/FlipWinding.svg
new file mode 100644
index 0000000000..8964ca8d5d
--- /dev/null
+++ b/editor/icons/FlipWinding.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="4.596" height="4.596" x="5.7" y="5.7" fill="#e0e0e0" fill-opacity=".6" rx="1" ry="1" transform="rotate(45 8 8)"/><path fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 2a6 6 0 00-2.5 11m.5-3L6 14H2M9 14a6 6 0 002.5-11M11 6 10 2h4"/></svg> \ No newline at end of file
diff --git a/editor/icons/Game.svg b/editor/icons/Game.svg
new file mode 100644
index 0000000000..e75e5c5312
--- /dev/null
+++ b/editor/icons/Game.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M 1,15 V 12 C 1,11.5 1.5,11 2,11 H 3 V 10 C 3,9.5 3.5,9 4,9 h 1 c 0.5,0 1,0.5 1,1 v 1 H 8 V 5 h 2 v 6 h 4 c 0.5,0 1,0.5 1,1 v 3 z"/><circle cx="9" cy="4" r="3" fill="#e0e0e0"/></svg> \ No newline at end of file
diff --git a/editor/icons/LookAtModifier3D.svg b/editor/icons/LookAtModifier3D.svg
new file mode 100644
index 0000000000..9315b297ef
--- /dev/null
+++ b/editor/icons/LookAtModifier3D.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#fc7f7f"><path d="m5.742 11.508c.916-2.959 3.507-4.508 5.592-4.508.803 0 1.673.223 2.492.658.297-.182.563-.423.768-.731.754-1.134.446-2.665-.688-3.419-.309-.205-.66-.338-1.026-.389-.188-1.349-1.433-2.291-2.782-2.103s-2.29 1.433-2.103 2.782c.051.367.184.717.389 1.026l-3.56 3.56c-1.134-.754-2.665-.446-3.419.688s-.446 2.664.688 3.419c.308.205.659.338 1.026.389.188 1.349 1.433 2.29 2.782 2.103.342-.048.658-.164.936-.333-.467-.612-.856-1.337-1.102-2.206-.085-.3-.085-.617.007-.936z"/><path d="m11.334 8c-1.704 0-3.861 1.299-4.637 3.804-.034.119-.034.246 0 .366.745 2.638 2.97 3.83 4.637 3.83s3.891-1.192 4.641-3.816c.034-.12.034-.247 0-.367-.734-2.526-2.938-3.817-4.641-3.817zm0 6.667c-1.473 0-2.667-1.194-2.667-2.667s1.194-2.666 2.667-2.666 2.667 1.193 2.667 2.666-1.194 2.667-2.667 2.667z"/><circle cx="11.334" cy="12" r="1.333"/></g></svg> \ No newline at end of file
diff --git a/editor/icons/MaterialPreviewQuad.svg b/editor/icons/MaterialPreviewQuad.svg
new file mode 100644
index 0000000000..9765a15df7
--- /dev/null
+++ b/editor/icons/MaterialPreviewQuad.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="none" stroke="#000" stroke-linejoin="round" stroke-opacity=".8" stroke-width="2" d="m2 1 12 1v11l-12 1z"/><path fill="#f9f9f9" d="m2 14 12-1v-11l-12-1z"/></svg> \ No newline at end of file
diff --git a/editor/icons/NextFrame.svg b/editor/icons/NextFrame.svg
new file mode 100644
index 0000000000..9609b2538b
--- /dev/null
+++ b/editor/icons/NextFrame.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="m 12,3 c -0.552285,0 -1,0.4477153 -1,1 v 8 c 0,0.552285 0.447715,1 1,1 h 1 c 0.552285,0 1,-0.447715 1,-1 V 4 C 14,3.4477153 13.552285,3 13,3 Z M 2.975,3.002 C 2.4332786,3.0155465 2.0009144,3.45811 2,4 v 8 c -3.148e-4,0.838862 0.9701632,1.305289 1.625,0.781 l 5,-4 c 0.4989606,-0.4003069 0.4989606,-1.1596931 0,-1.56 l -5,-4 C 3.4409271,3.0736532 3.2107095,2.9960875 2.975,3.002 Z"/></svg> \ No newline at end of file
diff --git a/editor/icons/Unfavorite.svg b/editor/icons/Unfavorite.svg
new file mode 100644
index 0000000000..78f1b90fd0
--- /dev/null
+++ b/editor/icons/Unfavorite.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M 8 1.6992188 L 5.6269531 5.796875 L 1 6.8945312 L 4.2363281 10.302734 L 3.8769531 14.976562 L 8.0175781 12.998047 L 12.173828 14.941406 L 11.777344 10.287109 L 15 6.8945312 L 10.373047 5.796875 L 8 1.6992188 z M 8 4.2773438 L 9.4882812 6.8457031 L 12.388672 7.5332031 L 10.369141 9.6601562 L 10.617188 12.576172 L 8.0097656 11.359375 L 5.4160156 12.599609 L 5.640625 9.6699219 L 3.6113281 7.5332031 L 6.5117188 6.8457031 L 8 4.2773438 z"/></svg> \ No newline at end of file
diff --git a/editor/import/3d/collada.h b/editor/import/3d/collada.h
index 416b917a46..f9c26e090c 100644
--- a/editor/import/3d/collada.h
+++ b/editor/import/3d/collada.h
@@ -359,7 +359,7 @@ public:
for (int i = 0; i < children.size(); i++) {
memdelete(children[i]);
}
- };
+ }
};
struct NodeSkeleton : public Node {
diff --git a/editor/import/3d/editor_import_collada.cpp b/editor/import/3d/editor_import_collada.cpp
index 04a3f23154..c04278fc55 100644
--- a/editor/import/3d/editor_import_collada.cpp
+++ b/editor/import/3d/editor_import_collada.cpp
@@ -1263,7 +1263,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
//bleh, must ignore invalid
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
- mesh = Ref<ImporterMesh>(memnew(ImporterMesh));
+ mesh.instantiate();
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
String name = meshdata.name;
if (name.is_empty()) {
diff --git a/editor/import/3d/resource_importer_obj.cpp b/editor/import/3d/resource_importer_obj.cpp
index a579224ecd..59d39152e9 100644
--- a/editor/import/3d/resource_importer_obj.cpp
+++ b/editor/import/3d/resource_importer_obj.cpp
@@ -202,12 +202,12 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
return OK;
}
-static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, List<String> *r_missing_deps) {
+static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_generate_lods, bool p_generate_shadow_mesh, bool p_generate_lightmap_uv2, float p_generate_lightmap_uv2_texel_size, const PackedByteArray &p_src_lightmap_cache, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, Vector<Vector<uint8_t>> &r_lightmap_caches, List<String> *r_missing_deps) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
- // Avoid trying to load/interpret potential build artifacts from Visual Studio (e.g. when compiling native plugins inside the project tree)
- // This should only match, if it's indeed a COFF file header
+ // Avoid trying to load/interpret potential build artifacts from Visual Studio (e.g. when compiling native plugins inside the project tree).
+ // This should only match if it's indeed a COFF file header.
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types
const int first_bytes = f->get_16();
static const Vector<int> coff_header_machines{
@@ -445,6 +445,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
}
mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, array, TypedArray<Array>(), Dictionary(), material, name, mesh_flags);
+
print_verbose("OBJ: Added surface :" + mesh->get_surface_name(mesh->get_surface_count() - 1));
if (!current_material.is_empty()) {
@@ -508,6 +509,43 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
}
}
+ if (p_generate_lightmap_uv2) {
+ Vector<uint8_t> lightmap_cache;
+ mesh->lightmap_unwrap_cached(Transform3D(), p_generate_lightmap_uv2_texel_size, p_src_lightmap_cache, lightmap_cache);
+
+ if (!lightmap_cache.is_empty()) {
+ if (r_lightmap_caches.is_empty()) {
+ r_lightmap_caches.push_back(lightmap_cache);
+ } else {
+ // MD5 is stored at the beginning of the cache data.
+ const String new_md5 = String::md5(lightmap_cache.ptr());
+
+ for (int i = 0; i < r_lightmap_caches.size(); i++) {
+ const String md5 = String::md5(r_lightmap_caches[i].ptr());
+ if (new_md5 < md5) {
+ r_lightmap_caches.insert(i, lightmap_cache);
+ break;
+ }
+
+ if (new_md5 == md5) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (p_generate_lods) {
+ // Use normal merge/split angles that match the defaults used for 3D scene importing.
+ mesh->generate_lods(60.0f, {});
+ }
+
+ if (p_generate_shadow_mesh) {
+ mesh->create_shadow_mesh();
+ }
+
+ mesh->optimize_indices();
+
if (p_single_mesh && mesh->get_surface_count() > 0) {
r_meshes.push_back(mesh);
}
@@ -518,7 +556,10 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
List<Ref<ImporterMesh>> meshes;
- Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, Vector3(1, 1, 1), Vector3(0, 0, 0), p_flags & IMPORT_FORCE_DISABLE_MESH_COMPRESSION, r_missing_deps);
+ // LOD, shadow mesh and lightmap UV2 generation are handled by ResourceImporterScene in this case,
+ // so disable it within the OBJ mesh import.
+ Vector<Vector<uint8_t>> mesh_lightmap_caches;
+ Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, false, false, 0.2, PackedByteArray(), Vector3(1, 1, 1), Vector3(0, 0, 0), p_flags & IMPORT_FORCE_DISABLE_MESH_COMPRESSION, mesh_lightmap_caches, r_missing_deps);
if (err != OK) {
if (r_err) {
@@ -587,19 +628,51 @@ String ResourceImporterOBJ::get_preset_name(int p_idx) const {
void ResourceImporterOBJ::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_tangents"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_lods"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_shadow_mesh"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_lightmap_uv2", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "generate_lightmap_uv2_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2));
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "scale_mesh"), Vector3(1, 1, 1)));
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "offset_mesh"), Vector3(0, 0, 0)));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_disable_mesh_compression"), false));
}
bool ResourceImporterOBJ::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
+ if (p_option == "generate_lightmap_uv2_texel_size" && !p_options["generate_lightmap_uv2"]) {
+ // Only display the lightmap texel size import option when lightmap UV2 generation is enabled.
+ return false;
+ }
+
return true;
}
-Error ResourceImporterOBJ::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) {
+Error ResourceImporterOBJ::import(ResourceUID::ID p_source_id, 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) {
List<Ref<ImporterMesh>> meshes;
- Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["scale_mesh"], p_options["offset_mesh"], p_options["force_disable_mesh_compression"], nullptr);
+ Vector<uint8_t> src_lightmap_cache;
+ Vector<Vector<uint8_t>> mesh_lightmap_caches;
+
+ Error err;
+ {
+ src_lightmap_cache = FileAccess::get_file_as_bytes(p_source_file + ".unwrap_cache", &err);
+ if (err != OK) {
+ src_lightmap_cache.clear();
+ }
+ }
+
+ err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["generate_lods"], p_options["generate_shadow_mesh"], p_options["generate_lightmap_uv2"], p_options["generate_lightmap_uv2_texel_size"], src_lightmap_cache, p_options["scale_mesh"], p_options["offset_mesh"], p_options["force_disable_mesh_compression"], mesh_lightmap_caches, nullptr);
+
+ if (mesh_lightmap_caches.size()) {
+ Ref<FileAccess> f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_32(mesh_lightmap_caches.size());
+ for (int i = 0; i < mesh_lightmap_caches.size(); i++) {
+ String md5 = String::md5(mesh_lightmap_caches[i].ptr());
+ f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size());
+ }
+ }
+ }
+ err = OK;
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(meshes.size() != 1, ERR_BUG);
diff --git a/editor/import/3d/resource_importer_obj.h b/editor/import/3d/resource_importer_obj.h
index faf0f336c0..c4a99428ef 100644
--- a/editor/import/3d/resource_importer_obj.h
+++ b/editor/import/3d/resource_importer_obj.h
@@ -61,10 +61,7 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
-
- // Threaded import can currently cause deadlocks, see GH-48265.
- virtual bool can_import_threaded() const override { return false; }
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
ResourceImporterOBJ();
};
diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp
index cb348f713c..86af9caf26 100644
--- a/editor/import/3d/resource_importer_scene.cpp
+++ b/editor/import/3d/resource_importer_scene.cpp
@@ -2043,9 +2043,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/shadow_meshes", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lightmap_uv", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lods", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lods/normal_split_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), 25.0f));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "lods/normal_merge_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), 60.0f));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "lods/raycast_normals", PROPERTY_HINT_NONE, ""), false));
} break;
case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "use_external/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
@@ -2474,9 +2472,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
//do mesh processing
bool generate_lods = p_generate_lods;
- float split_angle = 25.0f;
float merge_angle = 60.0f;
- bool raycast_normals = false;
bool create_shadow_meshes = p_create_shadow_meshes;
bool bake_lightmaps = p_light_bake_mode == LIGHT_BAKE_STATIC_LIGHTMAPS;
String save_to_file;
@@ -2523,18 +2519,10 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
}
}
- if (mesh_settings.has("lods/normal_split_angle")) {
- split_angle = mesh_settings["lods/normal_split_angle"];
- }
-
if (mesh_settings.has("lods/normal_merge_angle")) {
merge_angle = mesh_settings["lods/normal_merge_angle"];
}
- if (mesh_settings.has("lods/raycast_normals")) {
- raycast_normals = mesh_settings["lods/raycast_normals"];
- }
-
if (bool(mesh_settings.get("save_to_file/enabled", false))) {
save_to_file = mesh_settings.get("save_to_file/path", String());
if (!save_to_file.is_resource_file()) {
@@ -2579,17 +2567,17 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
}
}
- src_mesh_node->get_mesh()->optimize_indices_for_cache();
-
if (generate_lods) {
Array skin_pose_transform_array = _get_skinned_pose_transforms(src_mesh_node);
- src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle, skin_pose_transform_array, raycast_normals);
+ src_mesh_node->get_mesh()->generate_lods(merge_angle, skin_pose_transform_array);
}
if (create_shadow_meshes) {
src_mesh_node->get_mesh()->create_shadow_mesh();
}
+ src_mesh_node->get_mesh()->optimize_indices();
+
if (!save_to_file.is_empty()) {
Ref<Mesh> existing = ResourceCache::get_ref(save_to_file);
if (existing.is_valid()) {
@@ -2634,6 +2622,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
mesh_node->set_layer_mask(src_mesh_node->get_layer_mask());
mesh_node->set_cast_shadows_setting(src_mesh_node->get_cast_shadows_setting());
+ mesh_node->set_visible(src_mesh_node->is_visible());
mesh_node->set_visibility_range_begin(src_mesh_node->get_visibility_range_begin());
mesh_node->set_visibility_range_begin_margin(src_mesh_node->get_visibility_range_begin_margin());
mesh_node->set_visibility_range_end(src_mesh_node->get_visibility_range_end());
@@ -2883,7 +2872,7 @@ Error ResourceImporterScene::_check_resource_save_paths(const Dictionary &p_data
return OK;
}
-Error ResourceImporterScene::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) {
+Error ResourceImporterScene::import(ResourceUID::ID p_source_id, 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) {
const String &src_path = p_source_file;
Ref<EditorSceneFormatImporter> importer;
@@ -3103,7 +3092,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (!scr.is_valid()) {
EditorNode::add_io_error(TTR("Couldn't load post-import script:") + " " + post_import_script_path);
} else {
- post_import_script = Ref<EditorScenePostImport>(memnew(EditorScenePostImport));
+ post_import_script.instantiate();
post_import_script->set_script(scr);
if (!post_import_script->get_script_instance()) {
EditorNode::add_io_error(TTR("Invalid/broken script for post-import (check console):") + " " + post_import_script_path);
diff --git a/editor/import/3d/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h
index fe757dc2a3..b2f5fab0eb 100644
--- a/editor/import/3d/resource_importer_scene.h
+++ b/editor/import/3d/resource_importer_scene.h
@@ -299,13 +299,11 @@ public:
void _compress_animations(AnimationPlayer *anim, int p_page_size_kb);
Node *pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options);
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
virtual bool has_advanced_options() const override;
virtual void show_advanced_options(const String &p_path) override;
- virtual bool can_import_threaded() const override { return false; }
-
ResourceImporterScene(const String &p_scene_import_type = "PackedScene", bool p_singleton = false);
~ResourceImporterScene();
diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp
index 011d0135b4..945c1811d7 100644
--- a/editor/import/3d/scene_import_settings.cpp
+++ b/editor/import/3d/scene_import_settings.cpp
@@ -368,6 +368,7 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite
mesh_node->set_transform(src_mesh_node->get_transform());
mesh_node->set_skin(src_mesh_node->get_skin());
mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
+ mesh_node->set_visible(src_mesh_node->is_visible());
if (src_mesh_node->get_mesh().is_valid()) {
Ref<ImporterMesh> editor_mesh = src_mesh_node->get_mesh();
mesh_node->set_mesh(editor_mesh->get_mesh());
@@ -1019,11 +1020,11 @@ void SceneImportSettingsDialog::_play_animation() {
if (animation_player->has_animation(id)) {
if (animation_player->is_playing()) {
animation_player->pause();
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
set_process(false);
} else {
animation_player->play(id);
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("Pause")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
set_process(true);
}
}
@@ -1032,7 +1033,7 @@ void SceneImportSettingsDialog::_play_animation() {
void SceneImportSettingsDialog::_stop_current_animation() {
animation_pingpong = false;
animation_player->stop();
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
animation_slider->set_value_no_signal(0.0);
set_process(false);
}
@@ -1044,7 +1045,7 @@ void SceneImportSettingsDialog::_reset_animation(const String &p_animation_name)
if (animation_player != nullptr && animation_player->is_playing()) {
animation_player->stop();
}
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
_reset_bone_transforms();
set_process(false);
@@ -1066,7 +1067,7 @@ void SceneImportSettingsDialog::_reset_animation(const String &p_animation_name)
animation_player->play(p_animation_name);
} else {
animation_player->stop(true);
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
animation_player->set_assigned_animation(p_animation_name);
animation_player->seek(0.0, true);
animation_slider->set_value_no_signal(0.0);
@@ -1081,7 +1082,7 @@ void SceneImportSettingsDialog::_animation_slider_value_changed(double p_value)
}
if (animation_player->is_playing()) {
animation_player->stop();
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
set_process(false);
}
animation_player->seek(p_value * animation_map[selected_id].animation->get_length(), true);
@@ -1097,7 +1098,7 @@ void SceneImportSettingsDialog::_animation_finished(const StringName &p_name) {
switch (loop_mode) {
case Animation::LOOP_NONE: {
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
animation_slider->set_value_no_signal(1.0);
set_process(false);
} break;
@@ -1318,17 +1319,17 @@ void SceneImportSettingsDialog::_notification(int p_what) {
action_menu->end_bulk_theme_override();
if (animation_player != nullptr && animation_player->is_playing()) {
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("Pause")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
} else {
- animation_play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ animation_play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
}
- animation_stop_button->set_icon(get_editor_theme_icon(SNAME("Stop")));
+ animation_stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
- light_1_switch->set_icon(theme_cache.light_1_icon);
- light_2_switch->set_icon(theme_cache.light_2_icon);
- light_rotate_switch->set_icon(theme_cache.rotate_icon);
+ light_1_switch->set_button_icon(theme_cache.light_1_icon);
+ light_2_switch->set_button_icon(theme_cache.light_2_icon);
+ light_rotate_switch->set_button_icon(theme_cache.rotate_icon);
- animation_toggle_skeleton_visibility->set_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
+ animation_toggle_skeleton_visibility->set_button_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
} break;
case NOTIFICATION_PROCESS: {
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index 9a0c62193c..dd45806385 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -45,8 +45,8 @@ void AudioStreamImportSettingsDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
- _stop_button->set_icon(get_editor_theme_icon(SNAME("Stop")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
_preview->set_color(get_theme_color(SNAME("dark_color_2"), EditorStringName(Editor)));
color_rect->set_color(get_theme_color(SNAME("dark_color_1"), EditorStringName(Editor)));
@@ -61,9 +61,9 @@ void AudioStreamImportSettingsDialog::_notification(int p_what) {
_duration_label->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts)));
_duration_label->end_bulk_theme_override();
- zoom_in->set_icon(get_editor_theme_icon(SNAME("ZoomMore")));
- zoom_out->set_icon(get_editor_theme_icon(SNAME("ZoomLess")));
- zoom_reset->set_icon(get_editor_theme_icon(SNAME("ZoomReset")));
+ zoom_in->set_button_icon(get_editor_theme_icon(SNAME("ZoomMore")));
+ zoom_out->set_button_icon(get_editor_theme_icon(SNAME("ZoomLess")));
+ zoom_reset->set_button_icon(get_editor_theme_icon(SNAME("ZoomReset")));
_indicator->queue_redraw();
_preview->queue_redraw();
@@ -233,25 +233,25 @@ void AudioStreamImportSettingsDialog::_play() {
// '_pausing' variable indicates that we want to pause the audio player, not stop it. See '_on_finished()'.
_pausing = true;
_player->stop();
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
set_process(false);
} else {
_player->play(_current);
- _play_button->set_icon(get_editor_theme_icon(SNAME("Pause")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
set_process(true);
}
}
void AudioStreamImportSettingsDialog::_stop() {
_player->stop();
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
_current = 0;
_indicator->queue_redraw();
set_process(false);
}
void AudioStreamImportSettingsDialog::_on_finished() {
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
if (!_pausing) {
_current = 0;
_indicator->queue_redraw();
@@ -580,12 +580,10 @@ AudioStreamImportSettingsDialog::AudioStreamImportSettingsDialog() {
bar_beats_edit->set_max(32);
bar_beats_edit->connect(SceneStringName(value_changed), callable_mp(this, &AudioStreamImportSettingsDialog::_settings_changed).unbind(1));
interactive_hb->add_child(bar_beats_edit);
- interactive_hb->add_spacer();
main_vbox->add_margin_child(TTR("Music Playback:"), interactive_hb);
color_rect = memnew(ColorRect);
- main_vbox->add_margin_child(TTR("Preview:"), color_rect);
-
+ main_vbox->add_margin_child(TTR("Preview:"), color_rect, true);
color_rect->set_custom_minimum_size(Size2(600, 200) * EDSCALE);
color_rect->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index e124697b20..8bbad91b68 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -940,7 +940,7 @@ void DynamicFontImportSettingsDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- add_var->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_var->set_button_icon(get_editor_theme_icon(SNAME("Add")));
label_warn->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
} break;
}
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index 3243dcf256..650c0e27ca 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -163,7 +163,7 @@ bool EditorImportPlugin::get_option_visibility(const String &p_path, const Strin
ERR_FAIL_V_MSG(false, "Unimplemented _get_option_visibility in add-on.");
}
-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) {
+Error EditorImportPlugin::import(ResourceUID::ID p_source_id, 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;
TypedArray<String> platform_variants, gen_files;
diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h
index ea5cfc2682..df472b416b 100644
--- a/editor/import/editor_import_plugin.h
+++ b/editor/import/editor_import_plugin.h
@@ -69,7 +69,7 @@ public:
virtual int get_import_order() const override;
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr) override;
virtual bool can_import_threaded() const override;
Error append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant());
};
diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp
index e7b7850b02..8441a49666 100644
--- a/editor/import/resource_importer_bitmask.cpp
+++ b/editor/import/resource_importer_bitmask.cpp
@@ -72,7 +72,7 @@ void ResourceImporterBitMap::get_import_options(const String &p_path, List<Impor
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.5));
}
-Error ResourceImporterBitMap::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) {
+Error ResourceImporterBitMap::import(ResourceUID::ID p_source_id, 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) {
int create_from = p_options["create_from"];
float threshold = p_options["threshold"];
Ref<Image> image;
diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h
index 8963c8d918..fcb152b47d 100644
--- a/editor/import/resource_importer_bitmask.h
+++ b/editor/import/resource_importer_bitmask.h
@@ -48,7 +48,9 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterBitMap();
~ResourceImporterBitMap();
diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp
index 085ca1362d..b7efdbb6d6 100644
--- a/editor/import/resource_importer_bmfont.cpp
+++ b/editor/import/resource_importer_bmfont.cpp
@@ -67,7 +67,7 @@ void ResourceImporterBMFont::get_import_options(const String &p_path, List<Impor
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "scaling_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled (Integer),Enabled (Fractional)"), TextServer::FIXED_SIZE_SCALE_ENABLED));
}
-Error ResourceImporterBMFont::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) {
+Error ResourceImporterBMFont::import(ResourceUID::ID p_source_id, 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 BMFont font from: " + p_source_file);
Array fallbacks = p_options["fallbacks"];
diff --git a/editor/import/resource_importer_bmfont.h b/editor/import/resource_importer_bmfont.h
index d31cd03736..74fef9ff16 100644
--- a/editor/import/resource_importer_bmfont.h
+++ b/editor/import/resource_importer_bmfont.h
@@ -48,7 +48,9 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterBMFont();
};
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index c181011402..17f6070d35 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -72,7 +72,7 @@ void ResourceImporterCSVTranslation::get_import_options(const String &p_path, Li
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "delimiter", PROPERTY_HINT_ENUM, "Comma,Semicolon,Tab"), 0));
}
-Error ResourceImporterCSVTranslation::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) {
+Error ResourceImporterCSVTranslation::import(ResourceUID::ID p_source_id, 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) {
bool compress = p_options["compress"];
String delimiter;
@@ -147,6 +147,9 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
if (r_gen_files) {
r_gen_files->push_back(save_path);
}
+
+ ResourceUID::ID save_id = hash64_murmur3_64(translations[i]->get_locale().hash64(), p_source_id);
+ ResourceSaver::set_uid(save_path, save_id);
}
return OK;
diff --git a/editor/import/resource_importer_csv_translation.h b/editor/import/resource_importer_csv_translation.h
index c6b05eb043..63676c61a6 100644
--- a/editor/import/resource_importer_csv_translation.h
+++ b/editor/import/resource_importer_csv_translation.h
@@ -49,7 +49,9 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterCSVTranslation();
};
diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp
index fa222b2790..a4a5e445e3 100644
--- a/editor/import/resource_importer_dynamic_font.cpp
+++ b/editor/import/resource_importer_dynamic_font.cpp
@@ -141,7 +141,7 @@ void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) {
DynamicFontImportSettingsDialog::get_singleton()->open_settings(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) {
+Error ResourceImporterDynamicFont::import(ResourceUID::ID p_source_id, 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);
int antialiasing = p_options["antialiasing"];
diff --git a/editor/import/resource_importer_dynamic_font.h b/editor/import/resource_importer_dynamic_font.h
index de89e6b76f..73ef96d583 100644
--- a/editor/import/resource_importer_dynamic_font.h
+++ b/editor/import/resource_importer_dynamic_font.h
@@ -58,7 +58,9 @@ public:
bool has_advanced_options() const override;
void show_advanced_options(const String &p_path) override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterDynamicFont();
};
diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp
index 4f6dd4e4ef..5a4f64d245 100644
--- a/editor/import/resource_importer_image.cpp
+++ b/editor/import/resource_importer_image.cpp
@@ -70,7 +70,7 @@ String ResourceImporterImage::get_preset_name(int p_idx) const {
void ResourceImporterImage::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
}
-Error ResourceImporterImage::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) {
+Error ResourceImporterImage::import(ResourceUID::ID p_source_id, 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) {
Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'.");
diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h
index 1490ab30d5..da1925bc5c 100644
--- a/editor/import/resource_importer_image.h
+++ b/editor/import/resource_importer_image.h
@@ -50,7 +50,9 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterImage();
};
diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp
index f01381904d..44ae2b5ff1 100644
--- a/editor/import/resource_importer_imagefont.cpp
+++ b/editor/import/resource_importer_imagefont.cpp
@@ -75,7 +75,7 @@ void ResourceImporterImageFont::get_import_options(const String &p_path, List<Im
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "scaling_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled (Integer),Enabled (Fractional)"), TextServer::FIXED_SIZE_SCALE_ENABLED));
}
-Error ResourceImporterImageFont::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) {
+Error ResourceImporterImageFont::import(ResourceUID::ID p_source_id, 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 image font from: " + p_source_file);
int columns = p_options["columns"];
diff --git a/editor/import/resource_importer_imagefont.h b/editor/import/resource_importer_imagefont.h
index 065351c361..79e9455d6d 100644
--- a/editor/import/resource_importer_imagefont.h
+++ b/editor/import/resource_importer_imagefont.h
@@ -48,7 +48,9 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterImageFont();
};
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index 312195fcd7..0d0c89425d 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -289,7 +289,7 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons
}
}
-Error ResourceImporterLayeredTexture::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) {
+Error ResourceImporterLayeredTexture::import(ResourceUID::ID p_source_id, 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) {
int compress_mode = p_options["compress/mode"];
float lossy = p_options["compress/lossy_quality"];
bool high_quality = p_options["compress/high_quality"];
diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h
index 26495eed8d..271f1f4543 100644
--- a/editor/import/resource_importer_layered_texture.h
+++ b/editor/import/resource_importer_layered_texture.h
@@ -112,11 +112,13 @@ public:
void _save_tex(Vector<Ref<Image>> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2);
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
virtual bool are_import_settings_valid(const String &p_path, const Dictionary &p_meta) const override;
virtual String get_import_settings_string() const override;
+ virtual bool can_import_threaded() const override { return true; }
+
void set_mode(Mode p_mode) { mode = p_mode; }
ResourceImporterLayeredTexture(bool p_singleton = false);
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index b7508e7644..639ce48f75 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -89,7 +89,7 @@ static String _include_function(const String &p_path, void *userpointer) {
return file_inc->get_as_utf8_string();
}
-Error ResourceImporterShaderFile::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) {
+Error ResourceImporterShaderFile::import(ResourceUID::ID p_source_id, 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) {
/* STEP 1, Read shader code */
ERR_FAIL_COND_V_EDMSG((OS::get_singleton()->get_current_rendering_method() == "gl_compatibility"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when using the gl_compatibility rendering_method. Please switch to the forward_plus or mobile rendering methods to use custom shaders.");
ERR_FAIL_COND_V_EDMSG((DisplayServer::get_singleton()->get_name() == "headless"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when running in headless mode.");
diff --git a/editor/import/resource_importer_shader_file.h b/editor/import/resource_importer_shader_file.h
index aefc967989..440a3d86b4 100644
--- a/editor/import/resource_importer_shader_file.h
+++ b/editor/import/resource_importer_shader_file.h
@@ -49,7 +49,9 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterShaderFile();
};
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 24a14c60ad..71ccef4752 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -428,7 +428,7 @@ Dictionary ResourceImporterTexture::_load_editor_meta(const String &p_path) cons
return f->get_var();
}
-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) {
+Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, 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;
diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h
index 6d74c4e2f9..8aa044f3c8 100644
--- a/editor/import/resource_importer_texture.h
+++ b/editor/import/resource_importer_texture.h
@@ -100,7 +100,9 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
void update_imports();
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index d6ce39f6a6..7e645cc0d0 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -91,7 +91,7 @@ String ResourceImporterTextureAtlas::get_option_group_file() const {
return "atlas_file";
}
-Error ResourceImporterTextureAtlas::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) {
+Error ResourceImporterTextureAtlas::import(ResourceUID::ID p_source_id, 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) {
/* If this happens, it's because the atlas_file field was not filled, so just import a broken texture */
//use an xpm because it's size independent, the editor images are vector and size dependent
diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h
index 0f2b10424c..943f221679 100644
--- a/editor/import/resource_importer_texture_atlas.h
+++ b/editor/import/resource_importer_texture_atlas.h
@@ -64,9 +64,11 @@ public:
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual String get_option_group_file() const override;
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
virtual Error import_group_file(const String &p_group_file, const HashMap<String, HashMap<StringName, Variant>> &p_source_file_options, const HashMap<String, String> &p_base_paths) override;
+ virtual bool can_import_threaded() const override { return true; }
+
ResourceImporterTextureAtlas();
};
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index 7a6f39906c..f500ec4a07 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -94,7 +94,7 @@ void ResourceImporterWAV::get_import_options(const String &p_path, List<ImportOp
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "PCM (Uncompressed),IMA ADPCM,Quite OK Audio"), 2));
}
-Error ResourceImporterWAV::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) {
+Error ResourceImporterWAV::import(ResourceUID::ID p_source_id, 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) {
/* STEP 1, READ WAVE FILE */
Error err;
@@ -112,7 +112,15 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
}
/* GET FILESIZE */
- file->get_32(); // filesize
+
+ // The file size in header is 8 bytes less than the actual size.
+ // See https://docs.fileformat.com/audio/wav/
+ const int FILE_SIZE_HEADER_OFFSET = 8;
+ uint32_t file_size_header = file->get_32() + FILE_SIZE_HEADER_OFFSET;
+ uint64_t file_size = file->get_length();
+ if (file_size != file_size_header) {
+ WARN_PRINT(vformat("File size %d is %s than the expected size %d. (%s)", file_size, file_size > file_size_header ? "larger" : "smaller", file_size_header, p_source_file));
+ }
/* CHECK WAVE */
@@ -198,11 +206,14 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
break;
}
+ uint64_t remaining_bytes = file_size - file_pos;
frames = chunksize;
-
- if (format_channels == 0) {
- ERR_FAIL_COND_V(format_channels == 0, ERR_INVALID_DATA);
+ if (remaining_bytes < chunksize) {
+ WARN_PRINT(vformat("Data chunk size is smaller than expected. Proceeding with actual data size. (%s)", p_source_file));
+ frames = remaining_bytes;
}
+
+ ERR_FAIL_COND_V(format_channels == 0, ERR_INVALID_DATA);
frames /= format_channels;
frames /= (format_bits >> 3);
diff --git a/editor/import/resource_importer_wav.h b/editor/import/resource_importer_wav.h
index 47af37ba41..361541c6c1 100644
--- a/editor/import/resource_importer_wav.h
+++ b/editor/import/resource_importer_wav.h
@@ -140,7 +140,9 @@ public:
}
}
- virtual Error 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 = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(ResourceUID::ID p_source_id, 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 = nullptr, Variant *r_metadata = nullptr) override;
+
+ virtual bool can_import_threaded() const override { return true; }
ResourceImporterWAV();
};
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 14065abf73..6c22a965ae 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -790,23 +790,14 @@ ImportDock::ImportDock() {
import->set_text(TTR("Reimport"));
import->set_disabled(true);
import->connect(SceneStringName(pressed), callable_mp(this, &ImportDock::_reimport_pressed));
- if (!DisplayServer::get_singleton()->get_swap_cancel_ok()) {
- advanced_spacer = hb->add_spacer();
- advanced = memnew(Button);
- advanced->set_text(TTR("Advanced..."));
- hb->add_child(advanced);
- }
+ advanced_spacer = hb->add_spacer();
+ advanced = memnew(Button);
+ advanced->set_text(TTR("Advanced..."));
+ hb->add_child(advanced);
hb->add_spacer();
hb->add_child(import);
hb->add_spacer();
- if (DisplayServer::get_singleton()->get_swap_cancel_ok()) {
- advanced = memnew(Button);
- advanced->set_text(TTR("Advanced..."));
- hb->add_child(advanced);
- advanced_spacer = hb->add_spacer();
- }
-
advanced->hide();
advanced_spacer->hide();
advanced->connect(SceneStringName(pressed), callable_mp(this, &ImportDock::_advanced_options));
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index d13a022d52..46876644fb 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -427,35 +427,36 @@ void InspectorDock::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
- resource_new_button->set_icon(get_editor_theme_icon(SNAME("New")));
- resource_load_button->set_icon(get_editor_theme_icon(SNAME("Load")));
- resource_save_button->set_icon(get_editor_theme_icon(SNAME("Save")));
- resource_extra_button->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
- open_docs_button->set_icon(get_editor_theme_icon(SNAME("HelpSearch")));
+ resource_new_button->set_button_icon(get_editor_theme_icon(SNAME("New")));
+ resource_load_button->set_button_icon(get_editor_theme_icon(SNAME("Load")));
+ resource_save_button->set_button_icon(get_editor_theme_icon(SNAME("Save")));
+ resource_extra_button->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ open_docs_button->set_button_icon(get_editor_theme_icon(SNAME("HelpSearch")));
PopupMenu *resource_extra_popup = resource_extra_button->get_popup();
resource_extra_popup->set_item_icon(resource_extra_popup->get_item_index(RESOURCE_EDIT_CLIPBOARD), get_editor_theme_icon(SNAME("ActionPaste")));
resource_extra_popup->set_item_icon(resource_extra_popup->get_item_index(RESOURCE_COPY), get_editor_theme_icon(SNAME("ActionCopy")));
+ resource_extra_popup->set_item_icon(resource_extra_popup->get_item_index(RESOURCE_SHOW_IN_FILESYSTEM), get_editor_theme_icon(SNAME("ShowInFileSystem")));
if (is_layout_rtl()) {
- backward_button->set_icon(get_editor_theme_icon(SNAME("Forward")));
- forward_button->set_icon(get_editor_theme_icon(SNAME("Back")));
+ backward_button->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
+ forward_button->set_button_icon(get_editor_theme_icon(SNAME("Back")));
} else {
- backward_button->set_icon(get_editor_theme_icon(SNAME("Back")));
- forward_button->set_icon(get_editor_theme_icon(SNAME("Forward")));
+ backward_button->set_button_icon(get_editor_theme_icon(SNAME("Back")));
+ forward_button->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
}
const int icon_width = get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
history_menu->get_popup()->add_theme_constant_override("icon_max_width", icon_width);
- history_menu->set_icon(get_editor_theme_icon(SNAME("History")));
- object_menu->set_icon(get_editor_theme_icon(SNAME("Tools")));
+ history_menu->set_button_icon(get_editor_theme_icon(SNAME("History")));
+ object_menu->set_button_icon(get_editor_theme_icon(SNAME("Tools")));
search->set_right_icon(get_editor_theme_icon(SNAME("Search")));
if (info_is_warning) {
- info->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
+ info->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
info->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
} else {
- info->set_icon(get_editor_theme_icon(SNAME("NodeInfo")));
+ info->set_button_icon(get_editor_theme_icon(SNAME("NodeInfo")));
info->add_theme_color_override(SceneStringName(font_color), get_theme_color(SceneStringName(font_color), EditorStringName(Editor)));
}
} break;
@@ -482,10 +483,10 @@ void InspectorDock::set_info(const String &p_button_text, const String &p_messag
info_is_warning = p_is_warning;
if (info_is_warning) {
- info->set_icon(get_editor_theme_icon(SNAME("NodeWarning")));
+ info->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
info->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
} else {
- info->set_icon(get_editor_theme_icon(SNAME("NodeInfo")));
+ info->set_button_icon(get_editor_theme_icon(SNAME("NodeInfo")));
info->add_theme_color_override(SceneStringName(font_color), get_theme_color(SceneStringName(font_color), EditorStringName(Editor)));
}
diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h
index 60ce8100aa..924f7abdd2 100644
--- a/editor/inspector_dock.h
+++ b/editor/inspector_dock.h
@@ -113,7 +113,7 @@ class InspectorDock : public VBoxContainer {
void _new_resource();
void _load_resource(const String &p_type = "");
- void _open_resource_selector() { _load_resource(); }; // just used to call from arg-less signal
+ void _open_resource_selector() { _load_resource(); } // just used to call from arg-less signal
void _resource_file_selected(const String &p_file);
void _save_resource(bool save_as);
void _unref_resource();
diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp
index 0da8d8291f..985a319c84 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -52,8 +52,8 @@ void NodeDock::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- connections_button->set_icon(get_editor_theme_icon(SNAME("Signals")));
- groups_button->set_icon(get_editor_theme_icon(SNAME("Groups")));
+ connections_button->set_button_icon(get_editor_theme_icon(SNAME("Signals")));
+ groups_button->set_button_icon(get_editor_theme_icon(SNAME("Groups")));
} break;
}
}
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 804f9c607e..990b8df49d 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -158,9 +158,9 @@ void AbstractPolygon2DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- button_create->set_icon(get_editor_theme_icon(SNAME("CurveCreate")));
- button_edit->set_icon(get_editor_theme_icon(SNAME("CurveEdit")));
- button_delete->set_icon(get_editor_theme_icon(SNAME("CurveDelete")));
+ button_create->set_button_icon(get_editor_theme_icon(SNAME("CurveCreate")));
+ button_edit->set_button_icon(get_editor_theme_icon(SNAME("CurveEdit")));
+ button_delete->set_button_icon(get_editor_theme_icon(SNAME("CurveDelete")));
} break;
case NOTIFICATION_READY: {
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index cbf8b27b32..3f534eebc5 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -576,12 +576,12 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
error_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
- tool_blend->set_icon(get_editor_theme_icon(SNAME("EditPivot")));
- tool_select->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
- tool_create->set_icon(get_editor_theme_icon(SNAME("EditKey")));
- tool_erase->set_icon(get_editor_theme_icon(SNAME("Remove")));
- snap->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
- open_editor->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ tool_blend->set_button_icon(get_editor_theme_icon(SNAME("EditPivot")));
+ tool_select->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
+ tool_create->set_button_icon(get_editor_theme_icon(SNAME("EditKey")));
+ tool_erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
+ snap->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
+ open_editor->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
interpolation->clear();
interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackContinuous")), TTR("Continuous"), 0);
interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackDiscrete")), TTR("Discrete"), 1);
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 934f26415a..ba2dad5880 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -798,14 +798,14 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
error_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
- tool_blend->set_icon(get_editor_theme_icon(SNAME("EditPivot")));
- tool_select->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
- tool_create->set_icon(get_editor_theme_icon(SNAME("EditKey")));
- tool_triangle->set_icon(get_editor_theme_icon(SNAME("ToolTriangle")));
- tool_erase->set_icon(get_editor_theme_icon(SNAME("Remove")));
- snap->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
- open_editor->set_icon(get_editor_theme_icon(SNAME("Edit")));
- auto_triangles->set_icon(get_editor_theme_icon(SNAME("AutoTriangle")));
+ tool_blend->set_button_icon(get_editor_theme_icon(SNAME("EditPivot")));
+ tool_select->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
+ tool_create->set_button_icon(get_editor_theme_icon(SNAME("EditKey")));
+ tool_triangle->set_button_icon(get_editor_theme_icon(SNAME("ToolTriangle")));
+ tool_erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
+ snap->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
+ open_editor->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
+ auto_triangles->set_button_icon(get_editor_theme_icon(SNAME("AutoTriangle")));
interpolation->clear();
interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackContinuous")), TTR("Continuous"), 0);
interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackDiscrete")), TTR("Discrete"), 1);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 9e282cb3fa..096e92e235 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -45,6 +45,7 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/check_box.h"
+#include "scene/gui/grid_container.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel.h"
@@ -178,7 +179,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
Button *delete_button = memnew(Button);
delete_button->set_flat(true);
delete_button->set_focus_mode(FOCUS_NONE);
- delete_button->set_icon(get_editor_theme_icon(SNAME("Close")));
+ delete_button->set_button_icon(get_editor_theme_icon(SNAME("Close")));
delete_button->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_node_request).bind(E), CONNECT_DEFERRED);
node->get_titlebar_hbox()->add_child(delete_button);
}
@@ -216,7 +217,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
node->add_child(memnew(HSeparator));
Button *open_in_editor = memnew(Button);
open_in_editor->set_text(TTR("Open Editor"));
- open_in_editor->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ open_in_editor->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
node->add_child(open_in_editor);
open_in_editor->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendTreeEditor::_open_in_editor).bind(E), CONNECT_DEFERRED);
open_in_editor->set_h_size_flags(SIZE_SHRINK_CENTER);
@@ -230,7 +231,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
} else {
inspect_filters->set_text(TTR("Edit Filters"));
}
- inspect_filters->set_icon(get_editor_theme_icon(SNAME("AnimationFilter")));
+ inspect_filters->set_button_icon(get_editor_theme_icon(SNAME("AnimationFilter")));
node->add_child(inspect_filters);
inspect_filters->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendTreeEditor::_inspect_filters).bind(E), CONNECT_DEFERRED);
inspect_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
@@ -240,7 +241,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
if (anim.is_valid()) {
MenuButton *mb = memnew(MenuButton);
mb->set_text(anim->get_animation());
- mb->set_icon(get_editor_theme_icon(SNAME("Animation")));
+ mb->set_button_icon(get_editor_theme_icon(SNAME("Animation")));
mb->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
mb->set_disabled(read_only);
Array options;
@@ -1265,7 +1266,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendTreeEditor::_file_opened));
- animation_node_inspector_plugin = Ref<EditorInspectorPluginAnimationNodeAnimation>(memnew(EditorInspectorPluginAnimationNodeAnimation));
+ animation_node_inspector_plugin.instantiate();
EditorInspector::add_inspector_plugin(animation_node_inspector_plugin);
}
@@ -1375,7 +1376,7 @@ void AnimationNodeAnimationEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
button->set_theme_type_variation(SNAME("InspectorActionButton"));
- button->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
} break;
}
}
@@ -1397,32 +1398,30 @@ bool EditorInspectorPluginAnimationNodeAnimation::parse_property(Object *p_objec
}
AnimationNodeAnimationEditorDialog::AnimationNodeAnimationEditorDialog() {
- set_title(TTR("Select Markers..."));
- VBoxContainer *vbox = memnew(VBoxContainer);
- add_child(vbox);
- vbox->set_offsets_preset(Control::PRESET_FULL_RECT);
-
- HBoxContainer *container_start = memnew(HBoxContainer);
- vbox->add_child(container_start);
- Label *label_start = memnew(Label);
- container_start->add_child(label_start);
+ set_title(TTR("Select Markers"));
+
+ GridContainer *grid = memnew(GridContainer);
+ grid->set_columns(2);
+ grid->set_offsets_preset(Control::PRESET_FULL_RECT);
+ add_child(grid);
+
+ Label *label_start = memnew(Label(TTR("Start Marker")));
+ grid->add_child(label_start);
label_start->set_h_size_flags(Control::SIZE_EXPAND_FILL);
label_start->set_stretch_ratio(1);
- label_start->set_text(TTR("Start Marker"));
select_start = memnew(OptionButton);
- container_start->add_child(select_start);
+ select_start->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+ grid->add_child(select_start);
select_start->set_h_size_flags(Control::SIZE_EXPAND_FILL);
select_start->set_stretch_ratio(2);
- HBoxContainer *container_end = memnew(HBoxContainer);
- vbox->add_child(container_end);
- Label *label_end = memnew(Label);
- container_end->add_child(label_end);
+ Label *label_end = memnew(Label(TTR("End Marker")));
+ grid->add_child(label_end);
label_end->set_h_size_flags(Control::SIZE_EXPAND_FILL);
label_end->set_stretch_ratio(1);
- label_end->set_text(TTR("End Marker"));
select_end = memnew(OptionButton);
- container_end->add_child(select_end);
+ select_end->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+ grid->add_child(select_end);
select_end->set_h_size_flags(Control::SIZE_EXPAND_FILL);
select_end->set_stretch_ratio(2);
}
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index 147b92c094..4e8a1bd89b 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -773,8 +773,8 @@ void AnimationLibraryEditor::show_dialog() {
void AnimationLibraryEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- new_library_button->set_icon(get_editor_theme_icon(SNAME("Add")));
- load_library_button->set_icon(get_editor_theme_icon(SNAME("Load")));
+ new_library_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ load_library_button->set_button_icon(get_editor_theme_icon(SNAME("Load")));
}
}
}
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 1581e7cc66..4edd021b4d 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -113,7 +113,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
// Need the last frame after it stopped.
frame->set_value(player->get_current_animation_position());
track_editor->set_anim_pos(player->get_current_animation_position());
- stop->set_icon(stop_icon);
+ stop->set_button_icon(stop_icon);
}
last_active = player->is_playing();
@@ -145,16 +145,16 @@ void AnimationPlayerEditor::_notification(int p_what) {
stop_icon = get_editor_theme_icon(SNAME("Stop"));
pause_icon = get_editor_theme_icon(SNAME("Pause"));
if (player && player->is_playing()) {
- stop->set_icon(pause_icon);
+ stop->set_button_icon(pause_icon);
} else {
- stop->set_icon(stop_icon);
+ stop->set_button_icon(stop_icon);
}
- autoplay->set_icon(get_editor_theme_icon(SNAME("AutoPlay")));
- play->set_icon(get_editor_theme_icon(SNAME("PlayStart")));
- play_from->set_icon(get_editor_theme_icon(SNAME("Play")));
- play_bw->set_icon(get_editor_theme_icon(SNAME("PlayStartBackwards")));
- play_bw_from->set_icon(get_editor_theme_icon(SNAME("PlayBackwards")));
+ autoplay->set_button_icon(get_editor_theme_icon(SNAME("AutoPlay")));
+ play->set_button_icon(get_editor_theme_icon(SNAME("PlayStart")));
+ play_from->set_button_icon(get_editor_theme_icon(SNAME("Play")));
+ play_bw->set_button_icon(get_editor_theme_icon(SNAME("PlayStartBackwards")));
+ play_bw_from->set_button_icon(get_editor_theme_icon(SNAME("PlayBackwards")));
autoplay_icon = get_editor_theme_icon(SNAME("AutoPlay"));
reset_icon = get_editor_theme_icon(SNAME("Reload"));
@@ -168,10 +168,10 @@ void AnimationPlayerEditor::_notification(int p_what) {
autoplay_reset_icon = ImageTexture::create_from_image(autoplay_reset_img);
}
- onion_toggle->set_icon(get_editor_theme_icon(SNAME("Onion")));
- onion_skinning->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ onion_toggle->set_button_icon(get_editor_theme_icon(SNAME("Onion")));
+ onion_skinning->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
- pin->set_icon(get_editor_theme_icon(SNAME("Pin")));
+ pin->set_button_icon(get_editor_theme_icon(SNAME("Pin")));
tool_anim->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), SNAME("Button")));
track_editor->get_edit_menu()->add_theme_style_override(CoreStringName(normal), get_theme_stylebox(CoreStringName(normal), SNAME("Button")));
@@ -307,7 +307,7 @@ void AnimationPlayerEditor::_play_pressed() {
}
//unstop
- stop->set_icon(pause_icon);
+ stop->set_button_icon(pause_icon);
}
void AnimationPlayerEditor::_play_from_pressed() {
@@ -331,7 +331,7 @@ void AnimationPlayerEditor::_play_from_pressed() {
}
//unstop
- stop->set_icon(pause_icon);
+ stop->set_button_icon(pause_icon);
}
String AnimationPlayerEditor::_get_current() const {
@@ -359,7 +359,7 @@ void AnimationPlayerEditor::_play_bw_pressed() {
}
//unstop
- stop->set_icon(pause_icon);
+ stop->set_button_icon(pause_icon);
}
void AnimationPlayerEditor::_play_bw_from_pressed() {
@@ -383,7 +383,7 @@ void AnimationPlayerEditor::_play_bw_from_pressed() {
}
//unstop
- stop->set_icon(pause_icon);
+ stop->set_button_icon(pause_icon);
}
void AnimationPlayerEditor::_stop_pressed() {
@@ -400,7 +400,7 @@ void AnimationPlayerEditor::_stop_pressed() {
frame->set_value(0);
track_editor->set_anim_pos(0);
}
- stop->set_icon(stop_icon);
+ stop->set_button_icon(stop_icon);
}
void AnimationPlayerEditor::_animation_selected(int p_which) {
@@ -580,8 +580,10 @@ float AnimationPlayerEditor::_get_editor_step() const {
const Ref<Animation> anim = player->get_animation(current);
ERR_FAIL_COND_V(anim.is_null(), 0.0);
+ float step = track_editor->get_snap_unit();
+
// Use more precise snapping when holding Shift
- return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
+ return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? step * 0.25 : step;
}
void AnimationPlayerEditor::_animation_name_edited() {
@@ -959,9 +961,9 @@ void AnimationPlayerEditor::_update_animation() {
updating = true;
if (player->is_playing()) {
- stop->set_icon(pause_icon);
+ stop->set_button_icon(pause_icon);
} else {
- stop->set_icon(stop_icon);
+ stop->set_button_icon(stop_icon);
}
scale->set_text(String::num(player->get_speed_scale(), 2));
@@ -1397,7 +1399,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_timeline_o
}
track_editor->set_anim_pos(pos);
-};
+}
void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) {
_update_player();
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index e9dd54f73b..d10daa2bfc 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -1271,18 +1271,18 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
error_panel->add_theme_style_override(SceneStringName(panel), theme_cache.error_panel_style);
error_label->add_theme_color_override(SceneStringName(font_color), theme_cache.error_color);
- tool_select->set_icon(theme_cache.tool_icon_select);
- tool_create->set_icon(theme_cache.tool_icon_create);
- tool_connect->set_icon(theme_cache.tool_icon_connect);
+ tool_select->set_button_icon(theme_cache.tool_icon_select);
+ tool_create->set_button_icon(theme_cache.tool_icon_create);
+ tool_connect->set_button_icon(theme_cache.tool_icon_connect);
switch_mode->clear();
switch_mode->add_icon_item(theme_cache.transition_icon_immediate, TTR("Immediate"));
switch_mode->add_icon_item(theme_cache.transition_icon_sync, TTR("Sync"));
switch_mode->add_icon_item(theme_cache.transition_icon_end, TTR("At End"));
- auto_advance->set_icon(theme_cache.play_icon_auto);
+ auto_advance->set_button_icon(theme_cache.play_icon_auto);
- tool_erase->set_icon(theme_cache.tool_icon_erase);
+ tool_erase->set_button_icon(theme_cache.tool_icon_erase);
play_mode->clear();
play_mode->add_icon_item(theme_cache.play_icon_travel, TTR("Travel"));
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index fec8d4b897..8db106da07 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -212,12 +212,12 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
// Overlay and thumbnail need the same format for `blend_rect` to work.
thumbnail->convert(Image::FORMAT_RGBA8);
thumbnail->blend_rect(overlay, overlay->get_used_rect(), overlay_pos);
- preview_images[i].button->set_icon(ImageTexture::create_from_image(thumbnail));
+ preview_images[i].button->set_button_icon(ImageTexture::create_from_image(thumbnail));
// Make it clearer that clicking it will open an external link
preview_images[i].button->set_default_cursor_shape(Control::CURSOR_POINTING_HAND);
} else {
- preview_images[i].button->set_icon(p_image);
+ preview_images[i].button->set_button_icon(p_image);
}
break;
}
@@ -302,7 +302,7 @@ void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, cons
new_preview.video_link = p_url;
new_preview.is_video = p_video;
new_preview.button = memnew(Button);
- new_preview.button->set_icon(previews->get_editor_theme_icon(SNAME("ThumbnailWait")));
+ new_preview.button->set_button_icon(previews->get_editor_theme_icon(SNAME("ThumbnailWait")));
new_preview.button->set_toggle_mode(true);
new_preview.button->connect(SceneStringName(pressed), callable_mp(this, &EditorAssetLibraryItemDescription::_preview_click).bind(p_id));
preview_hb->add_child(new_preview.button);
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index f691bad3c3..23eeedea93 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -50,8 +50,8 @@ void AudioStreamEditor::_notification(int p_what) {
_current_label->add_theme_font_override(SceneStringName(font), font);
_duration_label->add_theme_font_override(SceneStringName(font), font);
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
- _stop_button->set_icon(get_editor_theme_icon(SNAME("Stop")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
_preview->set_color(get_theme_color(SNAME("dark_color_2"), EditorStringName(Editor)));
set_color(get_theme_color(SNAME("dark_color_1"), EditorStringName(Editor)));
@@ -121,26 +121,26 @@ void AudioStreamEditor::_play() {
if (_player->is_playing()) {
_pausing = true;
_player->stop();
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
set_process(false);
} else {
_pausing = false;
_player->play(_current);
- _play_button->set_icon(get_editor_theme_icon(SNAME("Pause")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
set_process(true);
}
}
void AudioStreamEditor::_stop() {
_player->stop();
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
_current = 0;
_indicator->queue_redraw();
set_process(false);
}
void AudioStreamEditor::_on_finished() {
- _play_button->set_icon(get_editor_theme_icon(SNAME("MainPlay")));
+ _play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
if (!_pausing) {
_current = 0;
_indicator->queue_redraw();
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index d81ec21705..8b105955e7 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -119,7 +119,7 @@ void BoneMapperItem::create_editor() {
hbox->add_child(skeleton_bone_selector);
picker_button = memnew(Button);
- picker_button->set_icon(get_editor_theme_icon(SNAME("ClassList")));
+ picker_button->set_button_icon(get_editor_theme_icon(SNAME("ClassList")));
picker_button->connect(SceneStringName(pressed), callable_mp(this, &BoneMapperItem::_open_picker));
hbox->add_child(picker_button);
@@ -296,7 +296,7 @@ void BoneMapper::create_editor() {
group_hbox->add_child(profile_group_selector);
clear_mapping_button = memnew(Button);
- clear_mapping_button->set_icon(get_editor_theme_icon(SNAME("Clear")));
+ clear_mapping_button->set_button_icon(get_editor_theme_icon(SNAME("Clear")));
clear_mapping_button->set_tooltip_text(TTR("Clear mappings in current group."));
clear_mapping_button->connect(SceneStringName(pressed), callable_mp(this, &BoneMapper::_clear_mapping_current_group));
group_hbox->add_child(clear_mapping_button);
@@ -859,7 +859,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
// 4-1. Guess Finger
int tips_index = -1;
- bool thumb_tips_size = 0;
+ bool thumb_tips_size = false;
bool named_finger_is_found = false;
LocalVector<String> fingers;
fingers.push_back("thumb|pollex");
@@ -994,7 +994,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
}
tips_index = -1;
- thumb_tips_size = 0;
+ thumb_tips_size = false;
named_finger_is_found = false;
if (right_hand_or_palm != -1) {
LocalVector<LocalVector<String>> right_fingers_map;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index e9a796dae7..62793fbcb5 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1464,10 +1464,12 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
List<CanvasItem *> selection = _get_edited_canvas_items(false, true, &has_locked_items);
// Remove not movable nodes
- for (CanvasItem *E : selection) {
- if (!_is_node_movable(E, true)) {
+ for (List<CanvasItem *>::Element *E = selection.front(); E;) {
+ List<CanvasItem *>::Element *N = E->next();
+ if (!_is_node_movable(E->get(), true)) {
selection.erase(E);
}
+ E = N;
}
drag_selection = selection;
@@ -3964,39 +3966,38 @@ void CanvasItemEditor::set_current_tool(Tool p_tool) {
}
void CanvasItemEditor::_update_editor_settings() {
- button_center_view->set_icon(get_editor_theme_icon(SNAME("CenterView")));
- select_button->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
+ button_center_view->set_button_icon(get_editor_theme_icon(SNAME("CenterView")));
+ select_button->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
select_sb->set_texture(get_editor_theme_icon(SNAME("EditorRect2D")));
- list_select_button->set_icon(get_editor_theme_icon(SNAME("ListSelect")));
- move_button->set_icon(get_editor_theme_icon(SNAME("ToolMove")));
- scale_button->set_icon(get_editor_theme_icon(SNAME("ToolScale")));
- rotate_button->set_icon(get_editor_theme_icon(SNAME("ToolRotate")));
- smart_snap_button->set_icon(get_editor_theme_icon(SNAME("Snap")));
- grid_snap_button->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
- snap_config_menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
- skeleton_menu->set_icon(get_editor_theme_icon(SNAME("Bone")));
- override_camera_button->set_icon(get_editor_theme_icon(SNAME("Camera2D")));
- pan_button->set_icon(get_editor_theme_icon(SNAME("ToolPan")));
- ruler_button->set_icon(get_editor_theme_icon(SNAME("Ruler")));
- pivot_button->set_icon(get_editor_theme_icon(SNAME("EditPivot")));
+ list_select_button->set_button_icon(get_editor_theme_icon(SNAME("ListSelect")));
+ move_button->set_button_icon(get_editor_theme_icon(SNAME("ToolMove")));
+ scale_button->set_button_icon(get_editor_theme_icon(SNAME("ToolScale")));
+ rotate_button->set_button_icon(get_editor_theme_icon(SNAME("ToolRotate")));
+ smart_snap_button->set_button_icon(get_editor_theme_icon(SNAME("Snap")));
+ grid_snap_button->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
+ snap_config_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ skeleton_menu->set_button_icon(get_editor_theme_icon(SNAME("Bone")));
+ pan_button->set_button_icon(get_editor_theme_icon(SNAME("ToolPan")));
+ ruler_button->set_button_icon(get_editor_theme_icon(SNAME("Ruler")));
+ pivot_button->set_button_icon(get_editor_theme_icon(SNAME("EditPivot")));
select_handle = get_editor_theme_icon(SNAME("EditorHandle"));
anchor_handle = get_editor_theme_icon(SNAME("EditorControlAnchor"));
- lock_button->set_icon(get_editor_theme_icon(SNAME("Lock")));
- unlock_button->set_icon(get_editor_theme_icon(SNAME("Unlock")));
- group_button->set_icon(get_editor_theme_icon(SNAME("Group")));
- ungroup_button->set_icon(get_editor_theme_icon(SNAME("Ungroup")));
- key_loc_button->set_icon(get_editor_theme_icon(SNAME("KeyPosition")));
- key_rot_button->set_icon(get_editor_theme_icon(SNAME("KeyRotation")));
- key_scale_button->set_icon(get_editor_theme_icon(SNAME("KeyScale")));
- key_insert_button->set_icon(get_editor_theme_icon(SNAME("Key")));
- key_auto_insert_button->set_icon(get_editor_theme_icon(SNAME("AutoKey")));
+ lock_button->set_button_icon(get_editor_theme_icon(SNAME("Lock")));
+ unlock_button->set_button_icon(get_editor_theme_icon(SNAME("Unlock")));
+ group_button->set_button_icon(get_editor_theme_icon(SNAME("Group")));
+ ungroup_button->set_button_icon(get_editor_theme_icon(SNAME("Ungroup")));
+ key_loc_button->set_button_icon(get_editor_theme_icon(SNAME("KeyPosition")));
+ key_rot_button->set_button_icon(get_editor_theme_icon(SNAME("KeyRotation")));
+ key_scale_button->set_button_icon(get_editor_theme_icon(SNAME("KeyScale")));
+ key_insert_button->set_button_icon(get_editor_theme_icon(SNAME("Key")));
+ key_auto_insert_button->set_button_icon(get_editor_theme_icon(SNAME("AutoKey")));
// Use a different color for the active autokey icon to make them easier
// to distinguish from the other key icons at the top. On a light theme,
// the icon will be dark, so we need to lighten it before blending it
// with the red color.
const Color key_auto_color = EditorThemeManager::is_dark_theme() ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25);
key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55));
- animation_menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ animation_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
context_toolbar_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles)));
@@ -4014,8 +4015,6 @@ void CanvasItemEditor::_notification(int p_what) {
case NOTIFICATION_READY: {
_update_lock_and_group_button();
- EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
- EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &CanvasItemEditor::_project_settings_changed));
} break;
@@ -4114,15 +4113,6 @@ void CanvasItemEditor::_notification(int p_what) {
_update_editor_settings();
} break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
- if (!is_visible() && override_camera_button->is_pressed()) {
- EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
-
- debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
- override_camera_button->set_pressed(false);
- }
- } break;
-
case NOTIFICATION_APPLICATION_FOCUS_OUT:
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
if (drag_type != DRAG_NONE) {
@@ -4280,16 +4270,6 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
viewport->queue_redraw();
}
-void CanvasItemEditor::_button_override_camera(bool p_pressed) {
- EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
-
- if (p_pressed) {
- debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_2D);
- } else {
- debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
- }
-}
-
void CanvasItemEditor::_button_tool_select(int p_index) {
Button *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button };
for (int i = 0; i < TOOL_MAX; i++) {
@@ -4396,17 +4376,6 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
te->commit_insert_queue();
}
-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_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_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
- }
-}
-
void CanvasItemEditor::_popup_callback(int p_op) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
last_option = MenuOption(p_op);
@@ -5512,16 +5481,6 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(memnew(VSeparator));
- override_camera_button = memnew(Button);
- override_camera_button->set_theme_type_variation("FlatButton");
- main_menu_hbox->add_child(override_camera_button);
- override_camera_button->connect(SceneStringName(toggled), callable_mp(this, &CanvasItemEditor::_button_override_camera));
- override_camera_button->set_toggle_mode(true);
- override_camera_button->set_disabled(true);
- _update_override_camera_button(false);
-
- main_menu_hbox->add_child(memnew(VSeparator));
-
view_menu = memnew(MenuButton);
view_menu->set_flat(false);
view_menu->set_theme_type_variation("FlatMenuButton");
@@ -5661,7 +5620,7 @@ CanvasItemEditor::CanvasItemEditor() {
snap_dialog->connect(SceneStringName(confirmed), callable_mp(this, &CanvasItemEditor::_snap_changed));
add_child(snap_dialog);
- select_sb = Ref<StyleBoxTexture>(memnew(StyleBoxTexture));
+ select_sb.instantiate();
selection_menu = memnew(PopupMenu);
add_child(selection_menu);
@@ -6264,7 +6223,7 @@ void CanvasItemEditorViewport::_update_theme() {
for (BaseButton *btn : btn_list) {
CheckBox *check = Object::cast_to<CheckBox>(btn);
- check->set_icon(get_editor_theme_icon(check->get_text()));
+ check->set_button_icon(get_editor_theme_icon(check->get_text()));
}
label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index bae9efebc9..c5335bf9c1 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -335,7 +335,6 @@ private:
Button *group_button = nullptr;
Button *ungroup_button = nullptr;
- Button *override_camera_button = nullptr;
MenuButton *view_menu = nullptr;
PopupMenu *grid_menu = nullptr;
PopupMenu *theme_menu = nullptr;
@@ -518,11 +517,8 @@ private:
void _zoom_on_position(real_t p_zoom, Point2 p_position = Point2());
void _button_toggle_smart_snap(bool p_status);
void _button_toggle_grid_snap(bool p_status);
- void _button_override_camera(bool p_pressed);
void _button_tool_select(int p_index);
- void _update_override_camera_button(bool p_game_running);
-
HSplitContainer *left_panel_split = nullptr;
HSplitContainer *right_panel_split = nullptr;
VSplitContainer *bottom_split = nullptr;
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index cd13deb3e9..a52d949819 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -157,7 +157,7 @@ ControlPositioningWarning::ControlPositioningWarning() {
void EditorPropertyAnchorsPreset::_set_read_only(bool p_read_only) {
options->set_disabled(p_read_only);
-};
+}
void EditorPropertyAnchorsPreset::_option_selected(int p_which) {
int64_t val = options->get_item_metadata(p_which);
@@ -221,7 +221,7 @@ void EditorPropertySizeFlags::_set_read_only(bool p_read_only) {
check->set_disabled(p_read_only);
}
flag_presets->set_disabled(p_read_only);
-};
+}
void EditorPropertySizeFlags::_preset_selected(int p_which) {
int preset = flag_presets->get_item_id(p_which);
@@ -536,7 +536,6 @@ ControlEditorPopupButton::ControlEditorPopupButton() {
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));
@@ -573,27 +572,27 @@ 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_editor_theme_icon(SNAME("ControlAlignTopLeft")));
- preset_buttons[PRESET_CENTER_TOP]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterTop")));
- preset_buttons[PRESET_TOP_RIGHT]->set_icon(get_editor_theme_icon(SNAME("ControlAlignTopRight")));
+ preset_buttons[PRESET_TOP_LEFT]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignTopLeft")));
+ preset_buttons[PRESET_CENTER_TOP]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterTop")));
+ preset_buttons[PRESET_TOP_RIGHT]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignTopRight")));
- preset_buttons[PRESET_CENTER_LEFT]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterLeft")));
- preset_buttons[PRESET_CENTER]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenter")));
- preset_buttons[PRESET_CENTER_RIGHT]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterRight")));
+ preset_buttons[PRESET_CENTER_LEFT]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterLeft")));
+ preset_buttons[PRESET_CENTER]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenter")));
+ preset_buttons[PRESET_CENTER_RIGHT]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterRight")));
- preset_buttons[PRESET_BOTTOM_LEFT]->set_icon(get_editor_theme_icon(SNAME("ControlAlignBottomLeft")));
- preset_buttons[PRESET_CENTER_BOTTOM]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterBottom")));
- preset_buttons[PRESET_BOTTOM_RIGHT]->set_icon(get_editor_theme_icon(SNAME("ControlAlignBottomRight")));
+ preset_buttons[PRESET_BOTTOM_LEFT]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignBottomLeft")));
+ preset_buttons[PRESET_CENTER_BOTTOM]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterBottom")));
+ preset_buttons[PRESET_BOTTOM_RIGHT]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignBottomRight")));
- preset_buttons[PRESET_TOP_WIDE]->set_icon(get_editor_theme_icon(SNAME("ControlAlignTopWide")));
- preset_buttons[PRESET_HCENTER_WIDE]->set_icon(get_editor_theme_icon(SNAME("ControlAlignHCenterWide")));
- preset_buttons[PRESET_BOTTOM_WIDE]->set_icon(get_editor_theme_icon(SNAME("ControlAlignBottomWide")));
+ preset_buttons[PRESET_TOP_WIDE]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignTopWide")));
+ preset_buttons[PRESET_HCENTER_WIDE]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignHCenterWide")));
+ preset_buttons[PRESET_BOTTOM_WIDE]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignBottomWide")));
- preset_buttons[PRESET_LEFT_WIDE]->set_icon(get_editor_theme_icon(SNAME("ControlAlignLeftWide")));
- preset_buttons[PRESET_VCENTER_WIDE]->set_icon(get_editor_theme_icon(SNAME("ControlAlignVCenterWide")));
- preset_buttons[PRESET_RIGHT_WIDE]->set_icon(get_editor_theme_icon(SNAME("ControlAlignRightWide")));
+ preset_buttons[PRESET_LEFT_WIDE]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignLeftWide")));
+ preset_buttons[PRESET_VCENTER_WIDE]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignVCenterWide")));
+ preset_buttons[PRESET_RIGHT_WIDE]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignRightWide")));
- preset_buttons[PRESET_FULL_RECT]->set_icon(get_editor_theme_icon(SNAME("ControlAlignFullRect")));
+ preset_buttons[PRESET_FULL_RECT]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignFullRect")));
} break;
}
}
@@ -691,17 +690,17 @@ void SizeFlagPresetPicker::_notification(int p_notification) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (vertical) {
- preset_buttons[SIZE_SHRINK_BEGIN]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterTop")));
- preset_buttons[SIZE_SHRINK_CENTER]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenter")));
- preset_buttons[SIZE_SHRINK_END]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterBottom")));
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterTop")));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenter")));
+ preset_buttons[SIZE_SHRINK_END]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterBottom")));
- preset_buttons[SIZE_FILL]->set_icon(get_editor_theme_icon(SNAME("ControlAlignVCenterWide")));
+ preset_buttons[SIZE_FILL]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignVCenterWide")));
} else {
- preset_buttons[SIZE_SHRINK_BEGIN]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterLeft")));
- preset_buttons[SIZE_SHRINK_CENTER]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenter")));
- preset_buttons[SIZE_SHRINK_END]->set_icon(get_editor_theme_icon(SNAME("ControlAlignCenterRight")));
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterLeft")));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenter")));
+ preset_buttons[SIZE_SHRINK_END]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignCenterRight")));
- preset_buttons[SIZE_FILL]->set_icon(get_editor_theme_icon(SNAME("ControlAlignHCenterWide")));
+ preset_buttons[SIZE_FILL]->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignHCenterWide")));
}
} break;
}
@@ -1051,9 +1050,9 @@ void ControlEditorToolbar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- anchors_button->set_icon(get_editor_theme_icon(SNAME("ControlLayout")));
- anchor_mode_button->set_icon(get_editor_theme_icon(SNAME("Anchor")));
- containers_button->set_icon(get_editor_theme_icon(SNAME("ContainerLayout")));
+ anchors_button->set_button_icon(get_editor_theme_icon(SNAME("ControlLayout")));
+ anchor_mode_button->set_button_icon(get_editor_theme_icon(SNAME("Anchor")));
+ containers_button->set_button_icon(get_editor_theme_icon(SNAME("ContainerLayout")));
} break;
}
}
diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h
index 2672e8ef97..56e9f6ced4 100644
--- a/editor/plugins/control_editor_plugin.h
+++ b/editor/plugins/control_editor_plugin.h
@@ -241,7 +241,7 @@ protected:
static ControlEditorToolbar *singleton;
public:
- bool is_anchors_mode_enabled() { return anchors_mode; };
+ bool is_anchors_mode_enabled() { return anchors_mode; }
static ControlEditorToolbar *get_singleton() { return singleton; }
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index e518cf7815..67006af44b 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -972,7 +972,7 @@ void CurveEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
spacing = Math::round(BASE_SPACING * get_theme_default_base_scale());
- snap_button->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
+ snap_button->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
PopupMenu *p = presets_button->get_popup();
p->clear();
p->add_icon_item(get_editor_theme_icon(SNAME("CurveConstant")), TTR("Constant"), CurveEdit::PRESET_CONSTANT);
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index 6366d20539..7cf0b2d2ac 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -149,7 +149,7 @@ void EditorPropertyFontMetaOverride::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (button_add) {
- button_add->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
}
} break;
}
@@ -295,7 +295,7 @@ void EditorPropertyFontMetaOverride::update_property() {
hbox->add_child(prop);
prop->set_h_size_flags(SIZE_EXPAND_FILL);
Button *remove = memnew(Button);
- remove->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ remove->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
hbox->add_child(remove);
remove->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyFontMetaOverride::_remove).bind(remove, name));
@@ -470,7 +470,7 @@ void EditorPropertyOTVariation::update_property() {
Vector3i range = supported.get_value_at_index(i);
EditorPropertyInteger *prop = memnew(EditorPropertyInteger);
- prop->setup(range.x, range.y, false, 1, false, false);
+ prop->setup(range.x, range.y, false, true, false, false);
prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag));
String name = TS->tag_to_name(name_tag);
@@ -552,7 +552,7 @@ void EditorPropertyOTFeatures::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
if (button_add) {
- button_add->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
}
} break;
}
@@ -789,7 +789,7 @@ void EditorPropertyOTFeatures::update_property() {
hbox->add_child(prop);
prop->set_h_size_flags(SIZE_EXPAND_FILL);
Button *remove = memnew(Button);
- remove->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ remove->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
hbox->add_child(remove);
remove->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyOTFeatures::_remove).bind(remove, name_tag));
@@ -798,7 +798,7 @@ void EditorPropertyOTFeatures::update_property() {
}
button_add = EditorInspector::create_inspector_action_button(TTR("Add Feature"));
- button_add->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
button_add->connect(SceneStringName(pressed), callable_mp(this, &EditorPropertyOTFeatures::_add_menu));
property_vbox->add_child(button_add);
diff --git a/editor/plugins/game_view_plugin.cpp b/editor/plugins/game_view_plugin.cpp
new file mode 100644
index 0000000000..5c1f81ee94
--- /dev/null
+++ b/editor/plugins/game_view_plugin.cpp
@@ -0,0 +1,487 @@
+/**************************************************************************/
+/* game_view_plugin.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 "game_view_plugin.h"
+
+#include "core/debugger/debugger_marshalls.h"
+#include "editor/editor_main_screen.h"
+#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
+#include "editor/themes/editor_scale.h"
+#include "scene/gui/button.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/panel.h"
+#include "scene/gui/separator.h"
+
+void GameViewDebugger::_session_started(Ref<EditorDebuggerSession> p_session) {
+ Array setup_data;
+ Dictionary settings;
+ settings["editors/panning/2d_editor_panning_scheme"] = EDITOR_GET("editors/panning/2d_editor_panning_scheme");
+ settings["editors/panning/simple_panning"] = EDITOR_GET("editors/panning/simple_panning");
+ settings["editors/panning/warped_mouse_panning"] = EDITOR_GET("editors/panning/warped_mouse_panning");
+ settings["editors/panning/2d_editor_pan_speed"] = EDITOR_GET("editors/panning/2d_editor_pan_speed");
+ settings["canvas_item_editor/pan_view"] = DebuggerMarshalls::serialize_key_shortcut(ED_GET_SHORTCUT("canvas_item_editor/pan_view"));
+ setup_data.append(settings);
+ p_session->send_message("scene:runtime_node_select_setup", setup_data);
+
+ Array type;
+ type.append(node_type);
+ p_session->send_message("scene:runtime_node_select_set_type", type);
+ Array visible;
+ visible.append(selection_visible);
+ p_session->send_message("scene:runtime_node_select_set_visible", visible);
+ Array mode;
+ mode.append(select_mode);
+ p_session->send_message("scene:runtime_node_select_set_mode", mode);
+
+ emit_signal(SNAME("session_started"));
+}
+
+void GameViewDebugger::_session_stopped() {
+ emit_signal(SNAME("session_stopped"));
+}
+
+void GameViewDebugger::set_suspend(bool p_enabled) {
+ Array message;
+ message.append(p_enabled);
+
+ for (Ref<EditorDebuggerSession> &I : sessions) {
+ if (I->is_active()) {
+ I->send_message("scene:suspend_changed", message);
+ }
+ }
+}
+
+void GameViewDebugger::next_frame() {
+ for (Ref<EditorDebuggerSession> &I : sessions) {
+ if (I->is_active()) {
+ I->send_message("scene:next_frame", Array());
+ }
+ }
+}
+
+void GameViewDebugger::set_node_type(int p_type) {
+ node_type = p_type;
+
+ Array message;
+ message.append(p_type);
+
+ for (Ref<EditorDebuggerSession> &I : sessions) {
+ if (I->is_active()) {
+ I->send_message("scene:runtime_node_select_set_type", message);
+ }
+ }
+}
+
+void GameViewDebugger::set_selection_visible(bool p_visible) {
+ selection_visible = p_visible;
+
+ Array message;
+ message.append(p_visible);
+
+ for (Ref<EditorDebuggerSession> &I : sessions) {
+ if (I->is_active()) {
+ I->send_message("scene:runtime_node_select_set_visible", message);
+ }
+ }
+}
+
+void GameViewDebugger::set_select_mode(int p_mode) {
+ select_mode = p_mode;
+
+ Array message;
+ message.append(p_mode);
+
+ for (Ref<EditorDebuggerSession> &I : sessions) {
+ if (I->is_active()) {
+ I->send_message("scene:runtime_node_select_set_mode", message);
+ }
+ }
+}
+
+void GameViewDebugger::set_camera_override(bool p_enabled) {
+ EditorDebuggerNode::get_singleton()->set_camera_override(p_enabled ? camera_override_mode : EditorDebuggerNode::OVERRIDE_NONE);
+}
+
+void GameViewDebugger::set_camera_manipulate_mode(EditorDebuggerNode::CameraOverride p_mode) {
+ camera_override_mode = p_mode;
+
+ if (EditorDebuggerNode::get_singleton()->get_camera_override() != EditorDebuggerNode::OVERRIDE_NONE) {
+ set_camera_override(true);
+ }
+}
+
+void GameViewDebugger::reset_camera_2d_position() {
+ for (Ref<EditorDebuggerSession> &I : sessions) {
+ if (I->is_active()) {
+ I->send_message("scene:runtime_node_select_reset_camera_2d", Array());
+ }
+ }
+}
+
+void GameViewDebugger::reset_camera_3d_position() {
+ for (Ref<EditorDebuggerSession> &I : sessions) {
+ if (I->is_active()) {
+ I->send_message("scene:runtime_node_select_reset_camera_3d", Array());
+ }
+ }
+}
+
+void GameViewDebugger::setup_session(int p_session_id) {
+ Ref<EditorDebuggerSession> session = get_session(p_session_id);
+ ERR_FAIL_COND(session.is_null());
+
+ sessions.append(session);
+
+ session->connect("started", callable_mp(this, &GameViewDebugger::_session_started).bind(session));
+ session->connect("stopped", callable_mp(this, &GameViewDebugger::_session_stopped));
+}
+
+void GameViewDebugger::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("session_started"));
+ ADD_SIGNAL(MethodInfo("session_stopped"));
+}
+
+///////
+
+void GameView::_sessions_changed() {
+ // The debugger session's `session_started/stopped` signal can be unreliable, so count it manually.
+ active_sessions = 0;
+ Array sessions = debugger->get_sessions();
+ for (int i = 0; i < sessions.size(); i++) {
+ if (Object::cast_to<EditorDebuggerSession>(sessions[i])->is_active()) {
+ active_sessions++;
+ }
+ }
+
+ _update_debugger_buttons();
+}
+
+void GameView::_update_debugger_buttons() {
+ bool empty = active_sessions == 0;
+
+ suspend_button->set_disabled(empty);
+ camera_override_button->set_disabled(empty);
+
+ PopupMenu *menu = camera_override_menu->get_popup();
+
+ bool disable_camera_reset = empty || !camera_override_button->is_pressed() || !menu->is_item_checked(menu->get_item_index(CAMERA_MODE_INGAME));
+ menu->set_item_disabled(CAMERA_RESET_2D, disable_camera_reset);
+ menu->set_item_disabled(CAMERA_RESET_3D, disable_camera_reset);
+
+ if (empty) {
+ suspend_button->set_pressed(false);
+ camera_override_button->set_pressed(false);
+ }
+ next_frame_button->set_disabled(!suspend_button->is_pressed());
+}
+
+void GameView::_suspend_button_toggled(bool p_pressed) {
+ _update_debugger_buttons();
+
+ debugger->set_suspend(p_pressed);
+}
+
+void GameView::_node_type_pressed(int p_option) {
+ RuntimeNodeSelect::NodeType type = (RuntimeNodeSelect::NodeType)p_option;
+ for (int i = 0; i < RuntimeNodeSelect::NODE_TYPE_MAX; i++) {
+ node_type_button[i]->set_pressed_no_signal(i == type);
+ }
+
+ _update_debugger_buttons();
+
+ debugger->set_node_type(type);
+}
+
+void GameView::_select_mode_pressed(int p_option) {
+ RuntimeNodeSelect::SelectMode mode = (RuntimeNodeSelect::SelectMode)p_option;
+ for (int i = 0; i < RuntimeNodeSelect::SELECT_MODE_MAX; i++) {
+ select_mode_button[i]->set_pressed_no_signal(i == mode);
+ }
+
+ debugger->set_select_mode(mode);
+}
+
+void GameView::_hide_selection_toggled(bool p_pressed) {
+ hide_selection->set_button_icon(get_editor_theme_icon(p_pressed ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
+
+ debugger->set_selection_visible(!p_pressed);
+}
+
+void GameView::_camera_override_button_toggled(bool p_pressed) {
+ _update_debugger_buttons();
+
+ debugger->set_camera_override(p_pressed);
+}
+
+void GameView::_camera_override_menu_id_pressed(int p_id) {
+ PopupMenu *menu = camera_override_menu->get_popup();
+ if (p_id != CAMERA_RESET_2D && p_id != CAMERA_RESET_3D) {
+ for (int i = 0; i < menu->get_item_count(); i++) {
+ menu->set_item_checked(i, false);
+ }
+ }
+
+ switch (p_id) {
+ case CAMERA_RESET_2D: {
+ debugger->reset_camera_2d_position();
+ } break;
+ case CAMERA_RESET_3D: {
+ debugger->reset_camera_3d_position();
+ } break;
+ case CAMERA_MODE_INGAME: {
+ debugger->set_camera_manipulate_mode(EditorDebuggerNode::OVERRIDE_INGAME);
+ menu->set_item_checked(menu->get_item_index(p_id), true);
+
+ _update_debugger_buttons();
+ } break;
+ case CAMERA_MODE_EDITORS: {
+ debugger->set_camera_manipulate_mode(EditorDebuggerNode::OVERRIDE_EDITORS);
+ menu->set_item_checked(menu->get_item_index(p_id), true);
+
+ _update_debugger_buttons();
+ } break;
+ }
+}
+
+void GameView::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ suspend_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
+ next_frame_button->set_button_icon(get_editor_theme_icon(SNAME("NextFrame")));
+
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_button_icon(get_editor_theme_icon(SNAME("InputEventJoypadMotion")));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_button_icon(get_editor_theme_icon(SNAME("2DNodes")));
+#ifndef _3D_DISABLED
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));
+#endif // _3D_DISABLED
+
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_button_icon(get_editor_theme_icon(SNAME("ListSelect")));
+
+ hide_selection->set_button_icon(get_editor_theme_icon(hide_selection->is_pressed() ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
+
+ camera_override_button->set_button_icon(get_editor_theme_icon(SNAME("Camera")));
+ camera_override_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ } break;
+ }
+}
+
+void GameView::set_state(const Dictionary &p_state) {
+ if (p_state.has("hide_selection")) {
+ hide_selection->set_pressed(p_state["hide_selection"]);
+ _hide_selection_toggled(hide_selection->is_pressed());
+ }
+ if (p_state.has("select_mode")) {
+ _select_mode_pressed(p_state["select_mode"]);
+ }
+ if (p_state.has("camera_override_mode")) {
+ _camera_override_menu_id_pressed(p_state["camera_override_mode"]);
+ }
+}
+
+Dictionary GameView::get_state() const {
+ Dictionary d;
+ d["hide_selection"] = hide_selection->is_pressed();
+
+ for (int i = 0; i < RuntimeNodeSelect::SELECT_MODE_MAX; i++) {
+ if (select_mode_button[i]->is_pressed()) {
+ d["select_mode"] = i;
+ break;
+ }
+ }
+
+ PopupMenu *menu = camera_override_menu->get_popup();
+ for (int i = CAMERA_MODE_INGAME; i < CAMERA_MODE_EDITORS + 1; i++) {
+ if (menu->is_item_checked(menu->get_item_index(i))) {
+ d["camera_override_mode"] = i;
+ break;
+ }
+ }
+
+ return d;
+}
+
+GameView::GameView(Ref<GameViewDebugger> p_debugger) {
+ debugger = p_debugger;
+
+ // Add some margin to the sides for better aesthetics.
+ // This prevents the first button's hover/pressed effect from "touching" the panel's border,
+ // which looks ugly.
+ MarginContainer *toolbar_margin = memnew(MarginContainer);
+ toolbar_margin->add_theme_constant_override("margin_left", 4 * EDSCALE);
+ toolbar_margin->add_theme_constant_override("margin_right", 4 * EDSCALE);
+ add_child(toolbar_margin);
+
+ HBoxContainer *main_menu_hbox = memnew(HBoxContainer);
+ toolbar_margin->add_child(main_menu_hbox);
+
+ suspend_button = memnew(Button);
+ main_menu_hbox->add_child(suspend_button);
+ suspend_button->set_toggle_mode(true);
+ suspend_button->set_theme_type_variation("FlatButton");
+ suspend_button->connect(SceneStringName(toggled), callable_mp(this, &GameView::_suspend_button_toggled));
+ suspend_button->set_tooltip_text(TTR("Suspend"));
+
+ next_frame_button = memnew(Button);
+ main_menu_hbox->add_child(next_frame_button);
+ next_frame_button->set_theme_type_variation("FlatButton");
+ next_frame_button->connect(SceneStringName(pressed), callable_mp(*debugger, &GameViewDebugger::next_frame));
+ next_frame_button->set_tooltip_text(TTR("Next Frame"));
+
+ main_menu_hbox->add_child(memnew(VSeparator));
+
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE] = memnew(Button);
+ main_menu_hbox->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]);
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_text(TTR("Input"));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_toggle_mode(true);
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_pressed(true);
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_theme_type_variation("FlatButton");
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_NONE));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_NONE]->set_tooltip_text(TTR("Allow game input."));
+
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D] = memnew(Button);
+ main_menu_hbox->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]);
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_text(TTR("2D"));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_toggle_mode(true);
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_theme_type_variation("FlatButton");
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_2D));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_2D]->set_tooltip_text(TTR("Disable game input and allow to select Node2Ds, Controls, and manipulate the 2D camera."));
+
+#ifndef _3D_DISABLED
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D] = memnew(Button);
+ main_menu_hbox->add_child(node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]);
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_text(TTR("3D"));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_toggle_mode(true);
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_theme_type_variation("FlatButton");
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_node_type_pressed).bind(RuntimeNodeSelect::NODE_TYPE_3D));
+ node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_tooltip_text(TTR("Disable game input and allow to select Node3Ds and manipulate the 3D camera."));
+#endif // _3D_DISABLED
+
+ main_menu_hbox->add_child(memnew(VSeparator));
+
+ hide_selection = memnew(Button);
+ main_menu_hbox->add_child(hide_selection);
+ hide_selection->set_toggle_mode(true);
+ hide_selection->set_theme_type_variation("FlatButton");
+ hide_selection->connect(SceneStringName(toggled), callable_mp(this, &GameView::_hide_selection_toggled));
+ hide_selection->set_tooltip_text(TTR("Toggle Selection Visibility"));
+
+ main_menu_hbox->add_child(memnew(VSeparator));
+
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE] = memnew(Button);
+ main_menu_hbox->add_child(select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]);
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_toggle_mode(true);
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_pressed(true);
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_theme_type_variation("FlatButton");
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_select_mode_pressed).bind(RuntimeNodeSelect::SELECT_MODE_SINGLE));
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q));
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_shortcut_context(this);
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_SINGLE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Alt+RMB: Show list of all nodes at position clicked."));
+
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST] = memnew(Button);
+ main_menu_hbox->add_child(select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]);
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_toggle_mode(true);
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_theme_type_variation("FlatButton");
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_select_mode_pressed).bind(RuntimeNodeSelect::SELECT_MODE_LIST));
+ select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
+
+ main_menu_hbox->add_child(memnew(VSeparator));
+
+ camera_override_button = memnew(Button);
+ main_menu_hbox->add_child(camera_override_button);
+ camera_override_button->set_toggle_mode(true);
+ camera_override_button->set_theme_type_variation("FlatButton");
+ camera_override_button->connect(SceneStringName(toggled), callable_mp(this, &GameView::_camera_override_button_toggled));
+ camera_override_button->set_tooltip_text(TTR("Override the in-game camera."));
+
+ camera_override_menu = memnew(MenuButton);
+ main_menu_hbox->add_child(camera_override_menu);
+ camera_override_menu->set_flat(false);
+ camera_override_menu->set_theme_type_variation("FlatMenuButton");
+ camera_override_menu->set_h_size_flags(SIZE_SHRINK_END);
+ camera_override_menu->set_tooltip_text(TTR("Camera Override Options"));
+
+ PopupMenu *menu = camera_override_menu->get_popup();
+ menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_camera_override_menu_id_pressed));
+ menu->add_item(TTR("Reset 2D Camera"), CAMERA_RESET_2D);
+ menu->add_item(TTR("Reset 3D Camera"), CAMERA_RESET_3D);
+ menu->add_separator();
+ menu->add_radio_check_item(TTR("Manipulate In-Game"), CAMERA_MODE_INGAME);
+ menu->set_item_checked(menu->get_item_index(CAMERA_MODE_INGAME), true);
+ menu->add_radio_check_item(TTR("Manipulate From Editors"), CAMERA_MODE_EDITORS);
+
+ _update_debugger_buttons();
+
+ panel = memnew(Panel);
+ add_child(panel);
+ panel->set_theme_type_variation("GamePanel");
+ panel->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ p_debugger->connect("session_started", callable_mp(this, &GameView::_sessions_changed));
+ p_debugger->connect("session_stopped", callable_mp(this, &GameView::_sessions_changed));
+}
+
+///////
+
+void GameViewPlugin::make_visible(bool p_visible) {
+ game_view->set_visible(p_visible);
+}
+
+void GameViewPlugin::set_state(const Dictionary &p_state) {
+ game_view->set_state(p_state);
+}
+
+Dictionary GameViewPlugin::get_state() const {
+ return game_view->get_state();
+}
+
+void GameViewPlugin::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ add_debugger_plugin(debugger);
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ remove_debugger_plugin(debugger);
+ } break;
+ }
+}
+
+GameViewPlugin::GameViewPlugin() {
+ debugger.instantiate();
+
+ game_view = memnew(GameView(debugger));
+ game_view->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ EditorNode::get_singleton()->get_editor_main_screen()->get_control()->add_child(game_view);
+ game_view->hide();
+}
+
+GameViewPlugin::~GameViewPlugin() {
+}
diff --git a/editor/plugins/game_view_plugin.h b/editor/plugins/game_view_plugin.h
new file mode 100644
index 0000000000..f8701c3e76
--- /dev/null
+++ b/editor/plugins/game_view_plugin.h
@@ -0,0 +1,152 @@
+/**************************************************************************/
+/* game_view_plugin.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 GAME_VIEW_PLUGIN_H
+#define GAME_VIEW_PLUGIN_H
+
+#include "editor/debugger/editor_debugger_node.h"
+#include "editor/plugins/editor_debugger_plugin.h"
+#include "editor/plugins/editor_plugin.h"
+#include "scene/debugger/scene_debugger.h"
+#include "scene/gui/box_container.h"
+
+class GameViewDebugger : public EditorDebuggerPlugin {
+ GDCLASS(GameViewDebugger, EditorDebuggerPlugin);
+
+private:
+ Vector<Ref<EditorDebuggerSession>> sessions;
+
+ int node_type = RuntimeNodeSelect::NODE_TYPE_NONE;
+ bool selection_visible = true;
+ int select_mode = RuntimeNodeSelect::SELECT_MODE_SINGLE;
+ EditorDebuggerNode::CameraOverride camera_override_mode = EditorDebuggerNode::OVERRIDE_INGAME;
+
+ void _session_started(Ref<EditorDebuggerSession> p_session);
+ void _session_stopped();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_suspend(bool p_enabled);
+ void next_frame();
+
+ void set_node_type(int p_type);
+ void set_select_mode(int p_mode);
+
+ void set_selection_visible(bool p_visible);
+
+ void set_camera_override(bool p_enabled);
+ void set_camera_manipulate_mode(EditorDebuggerNode::CameraOverride p_mode);
+
+ void reset_camera_2d_position();
+ void reset_camera_3d_position();
+
+ virtual void setup_session(int p_session_id) override;
+
+ GameViewDebugger() {}
+};
+
+class GameView : public VBoxContainer {
+ GDCLASS(GameView, VBoxContainer);
+
+ enum {
+ CAMERA_RESET_2D,
+ CAMERA_RESET_3D,
+ CAMERA_MODE_INGAME,
+ CAMERA_MODE_EDITORS,
+ };
+
+ Ref<GameViewDebugger> debugger;
+
+ int active_sessions = 0;
+
+ Button *suspend_button = nullptr;
+ Button *next_frame_button = nullptr;
+
+ Button *node_type_button[RuntimeNodeSelect::NODE_TYPE_MAX];
+ Button *select_mode_button[RuntimeNodeSelect::SELECT_MODE_MAX];
+
+ Button *hide_selection = nullptr;
+
+ Button *camera_override_button = nullptr;
+ MenuButton *camera_override_menu = nullptr;
+
+ Panel *panel = nullptr;
+
+ void _sessions_changed();
+
+ void _update_debugger_buttons();
+
+ void _suspend_button_toggled(bool p_pressed);
+
+ void _node_type_pressed(int p_option);
+ void _select_mode_pressed(int p_option);
+
+ void _hide_selection_toggled(bool p_pressed);
+
+ void _camera_override_button_toggled(bool p_pressed);
+ void _camera_override_menu_id_pressed(int p_id);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void set_state(const Dictionary &p_state);
+ Dictionary get_state() const;
+
+ GameView(Ref<GameViewDebugger> p_debugger);
+};
+
+class GameViewPlugin : public EditorPlugin {
+ GDCLASS(GameViewPlugin, EditorPlugin);
+
+ GameView *game_view = nullptr;
+
+ Ref<GameViewDebugger> debugger;
+
+protected:
+ void _notification(int p_what);
+
+public:
+ virtual String get_name() const override { return "Game"; }
+ bool has_main_screen() const override { return true; }
+ virtual void edit(Object *p_object) override {}
+ virtual bool handles(Object *p_object) const override { return false; }
+ virtual void make_visible(bool p_visible) override;
+
+ virtual void set_state(const Dictionary &p_state) override;
+ virtual Dictionary get_state() const override;
+
+ GameViewPlugin();
+ ~GameViewPlugin();
+};
+
+#endif // GAME_VIEW_PLUGIN_H
diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h
index ad6b534235..c8ed05c6b7 100644
--- a/editor/plugins/gdextension_export_plugin.h
+++ b/editor/plugins/gdextension_export_plugin.h
@@ -77,12 +77,14 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p
HashSet<String> archs;
HashSet<String> features_wo_arch;
+ Vector<String> features_vector;
for (const String &tag : p_features) {
if (all_archs.has(tag)) {
archs.insert(tag);
} else {
features_wo_arch.insert(tag);
}
+ features_vector.append(tag);
}
if (archs.is_empty()) {
@@ -90,11 +92,22 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p
}
HashSet<String> libs_added;
+ struct FoundLibInfo {
+ int count = 0;
+ Vector<String> libs;
+ };
+ HashMap<String, FoundLibInfo> libs_found;
+ for (const String &arch_tag : archs) {
+ if (arch_tag != "universal") {
+ libs_found[arch_tag] = FoundLibInfo();
+ }
+ }
for (const String &arch_tag : archs) {
PackedStringArray tags;
String library_path = GDExtensionLibraryLoader::find_extension_library(
p_path, config, [features_wo_arch, arch_tag](const String &p_feature) { return features_wo_arch.has(p_feature) || (p_feature == arch_tag); }, &tags);
+
if (libs_added.has(library_path)) {
continue; // Universal library, already added for another arch, do not duplicate.
}
@@ -122,15 +135,19 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p
String linker_flags = "-Wl,-U,_" + entry_symbol;
add_ios_linker_flags(linker_flags);
}
- } else {
- Vector<String> features_vector;
- for (const String &E : p_features) {
- features_vector.append(E);
- }
- if (get_export_platform().is_valid()) {
- get_export_platform()->add_message(EditorExportPlatform::EXPORT_MESSAGE_WARNING, TTR("GDExtension"), vformat(TTR("No suitable library found for GDExtension: \"%s\". Possible feature flags for your platform: %s"), p_path, String(", ").join(features_vector)));
+
+ // Update found library info.
+ if (arch_tag == "universal") {
+ for (const String &sub_arch_tag : archs) {
+ if (sub_arch_tag != "universal") {
+ libs_found[sub_arch_tag].count++;
+ libs_found[sub_arch_tag].libs.push_back(library_path);
+ }
+ }
+ } else {
+ libs_found[arch_tag].count++;
+ libs_found[arch_tag].libs.push_back(library_path);
}
- return;
}
Vector<SharedObject> dependencies_shared_objects = GDExtensionLibraryLoader::find_extension_dependencies(p_path, config, [p_features](String p_feature) { return p_features.has(p_feature); });
@@ -138,6 +155,18 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p
_add_shared_object(shared_object);
}
}
+
+ for (const KeyValue<String, FoundLibInfo> &E : libs_found) {
+ if (E.value.count == 0) {
+ if (get_export_platform().is_valid()) {
+ get_export_platform()->add_message(EditorExportPlatform::EXPORT_MESSAGE_WARNING, TTR("GDExtension"), vformat(TTR("No \"%s\" library found for GDExtension: \"%s\". Possible feature flags for your platform: %s"), E.key, p_path, String(", ").join(features_vector)));
+ }
+ } else if (E.value.count > 1) {
+ if (get_export_platform().is_valid()) {
+ get_export_platform()->add_message(EditorExportPlatform::EXPORT_MESSAGE_WARNING, TTR("GDExtension"), vformat(TTR("Multiple \"%s\" libraries found for GDExtension: \"%s\": \"%s\"."), E.key, p_path, String(", ").join(E.value.libs)));
+ }
+ }
+ }
}
#endif // GDEXTENSION_EXPORT_PLUGIN_H
diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
index 01492c1dd0..573c686d57 100644
--- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
@@ -93,7 +93,7 @@ String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
}
if (Object::cast_to<CylinderShape3D>(*s)) {
- return p_id == 0 ? "Radius" : "Height";
+ return helper->cylinder_get_handle_name(p_id);
}
if (Object::cast_to<SeparationRayShape3D>(*s)) {
@@ -219,25 +219,15 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
}
if (Object::cast_to<CylinderShape3D>(*s)) {
- Vector3 axis;
- axis[p_id == 0 ? 0 : 1] = 1.0;
Ref<CylinderShape3D> cs2 = s;
- Vector3 ra, rb;
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = axis.dot(ra);
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001) {
- d = 0.001;
- }
- if (p_id == 0) {
- cs2->set_radius(d);
- } else if (p_id == 1) {
- cs2->set_height(d * 2.0);
- }
+ real_t height = cs2->get_height();
+ real_t radius = cs2->get_radius();
+ Vector3 position;
+ helper->cylinder_set_handle(sg, p_id, height, radius, position);
+ cs2->set_height(height);
+ cs2->set_radius(radius);
+ cs->set_global_position(position);
}
}
@@ -293,31 +283,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
if (Object::cast_to<CylinderShape3D>(*s)) {
Ref<CylinderShape3D> ss = s;
- if (p_cancel) {
- if (p_id == 0) {
- ss->set_radius(p_restore);
- } else {
- ss->set_height(p_restore);
- }
- return;
- }
-
- EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- if (p_id == 0) {
- ur->create_action(TTR("Change Cylinder Shape Radius"));
- ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
- ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
- } else {
- ur->create_action(
- ///
-
- ////////
- TTR("Change Cylinder Shape Height"));
- ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
- ur->add_undo_method(ss.ptr(), "set_height", p_restore);
- }
-
- ur->commit_action();
+ helper->cylinder_commit_handle(p_id, TTR("Change Cylinder Shape Radius"), TTR("Change Cylinder Shape Height"), p_cancel, cs, *ss, *ss);
}
if (Object::cast_to<SeparationRayShape3D>(*s)) {
@@ -534,10 +500,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_segments(collision_segments);
- Vector<Vector3> handles = {
- Vector3(cs2->get_radius(), 0, 0),
- Vector3(0, cs2->get_height() * 0.5, 0)
- };
+ Vector<Vector3> handles = helper->cylinder_get_handles(cs2->get_height(), cs2->get_radius());
p_gizmo->add_handles(handles, handles_material);
}
@@ -575,20 +538,19 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (Object::cast_to<ConvexPolygonShape3D>(*s)) {
Vector<Vector3> points = Object::cast_to<ConvexPolygonShape3D>(*s)->get_points();
- if (points.size() > 3) {
+ if (points.size() > 1) { // Need at least 2 points for a line.
Vector<Vector3> varr = Variant(points);
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
- Vector<Vector3> points2;
- points2.resize(md.edges.size() * 2);
+ Vector<Vector3> lines;
+ lines.resize(md.edges.size() * 2);
for (uint32_t i = 0; i < md.edges.size(); i++) {
- points2.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
- points2.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
+ lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
+ lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
}
-
- p_gizmo->add_lines(points2, material);
- p_gizmo->add_collision_segments(points2);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
}
}
}
diff --git a/editor/plugins/gizmos/gizmo_3d_helper.cpp b/editor/plugins/gizmos/gizmo_3d_helper.cpp
index 1226be90cb..ff1b67aa4a 100644
--- a/editor/plugins/gizmos/gizmo_3d_helper.cpp
+++ b/editor/plugins/gizmos/gizmo_3d_helper.cpp
@@ -139,3 +139,98 @@ void Gizmo3DHelper::box_commit_handle(const String &p_action_name, bool p_cancel
ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());
ur->commit_action();
}
+
+Vector<Vector3> Gizmo3DHelper::cylinder_get_handles(real_t p_height, real_t p_radius) {
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(p_radius, 0, 0));
+ handles.push_back(Vector3(0, p_height * 0.5, 0));
+ handles.push_back(Vector3(0, p_height * -0.5, 0));
+ return handles;
+}
+
+String Gizmo3DHelper::cylinder_get_handle_name(int p_id) const {
+ if (p_id == 0) {
+ return "Radius";
+ } else {
+ return "Height";
+ }
+}
+
+void Gizmo3DHelper::cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position) {
+ int sign = p_id == 2 ? -1 : 1;
+ int axis = p_id == 0 ? 0 : 1;
+
+ Vector3 axis_vector;
+ axis_vector[axis] = sign;
+ Vector3 ra, rb;
+ Geometry3D::get_closest_points_between_segments(axis_vector * -4096, axis_vector * 4096, p_segment[0], p_segment[1], ra, rb);
+ float d = axis_vector.dot(ra);
+
+ // Snap to grid.
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (p_id == 0) {
+ // Adjust radius.
+ if (d < 0.001) {
+ d = 0.001;
+ }
+ r_radius = d;
+ r_cylinder_position = initial_transform.get_origin();
+ } else if (p_id == 1 || p_id == 2) {
+ real_t initial_height = initial_value;
+
+ // Adjust height.
+ if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
+ r_height = d * 2.0;
+ } else {
+ r_height = (initial_height * 0.5) + d;
+ }
+
+ if (r_height < 0.001) {
+ r_height = 0.001;
+ }
+
+ // Adjust position.
+ if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
+ r_cylinder_position = initial_transform.get_origin();
+ } else {
+ Vector3 offset;
+ offset[axis] = (r_height - initial_height) * 0.5 * sign;
+ r_cylinder_position = initial_transform.xform(offset);
+ }
+ }
+}
+
+void Gizmo3DHelper::cylinder_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object, Object *p_radius_object, const StringName &p_position_property, const StringName &p_height_property, const StringName &p_radius_property) {
+ if (!p_height_object) {
+ p_height_object = p_position_object;
+ }
+ if (!p_radius_object) {
+ p_radius_object = p_position_object;
+ }
+
+ if (p_cancel) {
+ if (p_id == 0) {
+ p_radius_object->set(p_radius_property, initial_value);
+ } else {
+ p_height_object->set(p_height_property, initial_value);
+ }
+ p_position_object->set(p_position_property, initial_transform.get_origin());
+ return;
+ }
+
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
+ ur->create_action(p_id == 0 ? p_radius_action_name : p_height_action_name);
+ if (p_id == 0) {
+ ur->add_do_property(p_radius_object, p_radius_property, p_radius_object->get(p_radius_property));
+ ur->add_undo_property(p_radius_object, p_radius_property, initial_value);
+ } else {
+ ur->add_do_property(p_height_object, p_height_property, p_height_object->get(p_height_property));
+ ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property));
+ ur->add_undo_property(p_height_object, p_height_property, initial_value);
+ ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());
+ }
+ ur->commit_action();
+}
diff --git a/editor/plugins/gizmos/gizmo_3d_helper.h b/editor/plugins/gizmos/gizmo_3d_helper.h
index 387ea020b8..6d27e54770 100644
--- a/editor/plugins/gizmos/gizmo_3d_helper.h
+++ b/editor/plugins/gizmos/gizmo_3d_helper.h
@@ -50,6 +50,11 @@ public:
String box_get_handle_name(int p_id) const;
void box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position);
void box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_size_property = "size");
+
+ Vector<Vector3> cylinder_get_handles(real_t p_height, real_t p_radius);
+ String cylinder_get_handle_name(int p_id) const;
+ void cylinder_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position);
+ void cylinder_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object = nullptr, Object *p_radius_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_height_property = "height", const StringName &p_radius_property = "radius");
};
#endif // GIZMO_3D_HELPER_H
diff --git a/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp
index 39ae020d53..5a6527f876 100644
--- a/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp
@@ -36,7 +36,7 @@
#include "scene/3d/marker_3d.h"
Marker3DGizmoPlugin::Marker3DGizmoPlugin() {
- pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ pos3d_mesh.instantiate();
Vector<Vector3> cursor_points;
Vector<Color> cursor_colors;
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
index c21a1b5dd6..4c2a3b60f8 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
@@ -181,7 +181,7 @@ GPUParticlesCollisionSDF3DEditorPlugin::GPUParticlesCollisionSDF3DEditorPlugin()
bake_hb->hide();
bake = memnew(Button);
bake->set_theme_type_variation("FlatButton");
- bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
+ bake->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake SDF"));
bake->connect(SceneStringName(pressed), callable_mp(this, &GPUParticlesCollisionSDF3DEditorPlugin::_bake));
bake_hb->add_child(bake);
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index 1300394ca3..291ffc24d2 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -604,8 +604,8 @@ void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
void GradientEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- reverse_button->set_icon(get_editor_theme_icon(SNAME("ReverseGradient")));
- snap_button->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
+ reverse_button->set_button_icon(get_editor_theme_icon(SNAME("ReverseGradient")));
+ snap_button->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
} break;
case NOTIFICATION_READY: {
Ref<Gradient> gradient = gradient_editor_rect->get_gradient();
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index 5bf1422780..46c9f4501b 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -262,8 +262,8 @@ void GradientTexture2DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- reverse_button->set_icon(get_editor_theme_icon(SNAME("ReverseGradient")));
- snap_button->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
+ reverse_button->set_button_icon(get_editor_theme_icon(SNAME("ReverseGradient")));
+ snap_button->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
} break;
case NOTIFICATION_READY: {
if (texture.is_valid()) {
diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp
index 30debfc14f..0c3ceff977 100644
--- a/editor/plugins/input_event_editor_plugin.cpp
+++ b/editor/plugins/input_event_editor_plugin.cpp
@@ -37,7 +37,7 @@ void InputEventConfigContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- open_config_button->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ open_config_button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
} break;
}
}
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index 429add4540..e3b59f9bfb 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -35,8 +35,8 @@
Ref<OccluderPolygon2D> LightOccluder2DEditor::_ensure_occluder() const {
Ref<OccluderPolygon2D> occluder = node->get_occluder_polygon();
- if (!occluder.is_valid()) {
- occluder = Ref<OccluderPolygon2D>(memnew(OccluderPolygon2D));
+ if (occluder.is_null()) {
+ occluder.instantiate();
node->set_occluder_polygon(occluder);
}
return occluder;
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 854ab7de8f..6e5dfd44d4 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -177,7 +177,7 @@ LightmapGIEditorPlugin::LightmapGIEditorPlugin() {
bake->set_theme_type_variation("FlatButton");
// TODO: Rework this as a dedicated toolbar control so we can hook into theme changes and update it
// when the editor theme updates.
- bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
+ bake->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake Lightmaps"));
#ifdef MODULE_LIGHTMAPPER_RD_ENABLED
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 2702b6c909..8bdc763ebe 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -56,9 +56,15 @@ void MaterialEditor::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
rot.x -= mm->get_relative().y * 0.01;
rot.y -= mm->get_relative().x * 0.01;
-
- rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2);
+ if (quad_instance->is_visible()) {
+ // Clamp rotation so the quad is always visible.
+ const real_t limit = Math::deg_to_rad(80.0);
+ rot = rot.clampf(-limit, limit);
+ } else {
+ rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2);
+ }
_update_rotation();
+ _store_rotation_metadata();
}
}
@@ -70,6 +76,7 @@ void MaterialEditor::_update_theme_item_cache() {
theme_cache.sphere_icon = get_editor_theme_icon(SNAME("MaterialPreviewSphere"));
theme_cache.box_icon = get_editor_theme_icon(SNAME("MaterialPreviewCube"));
+ theme_cache.quad_icon = get_editor_theme_icon(SNAME("MaterialPreviewQuad"));
theme_cache.checkerboard = get_editor_theme_icon(SNAME("Checkerboard"));
}
@@ -77,11 +84,12 @@ void MaterialEditor::_update_theme_item_cache() {
void MaterialEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- light_1_switch->set_icon(theme_cache.light_1_icon);
- light_2_switch->set_icon(theme_cache.light_2_icon);
+ light_1_switch->set_button_icon(theme_cache.light_1_icon);
+ light_2_switch->set_button_icon(theme_cache.light_2_icon);
- sphere_switch->set_icon(theme_cache.sphere_icon);
- box_switch->set_icon(theme_cache.box_icon);
+ sphere_switch->set_button_icon(theme_cache.sphere_icon);
+ box_switch->set_button_icon(theme_cache.box_icon);
+ quad_switch->set_button_icon(theme_cache.quad_icon);
error_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
} break;
@@ -95,6 +103,18 @@ void MaterialEditor::_notification(int p_what) {
}
}
+void MaterialEditor::_set_rotation(real_t p_x_degrees, real_t p_y_degrees) {
+ rot.x = Math::deg_to_rad(p_x_degrees);
+ rot.y = Math::deg_to_rad(p_y_degrees);
+ _update_rotation();
+}
+
+// Store the rotation so it can persist when switching between materials.
+void MaterialEditor::_store_rotation_metadata() {
+ Vector2 rotation_degrees = Vector2(Math::rad_to_deg(rot.x), Math::rad_to_deg(rot.y));
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_rotation", rotation_degrees);
+}
+
void MaterialEditor::_update_rotation() {
Transform3D t;
t.basis.rotate(Vector3(0, 1, 0), -rot.y);
@@ -124,6 +144,7 @@ void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_en
vc->show();
sphere_instance->set_material_override(material);
box_instance->set_material_override(material);
+ quad_instance->set_material_override(material);
break;
default:
layout_error->show();
@@ -136,10 +157,6 @@ 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::_on_light_1_switch_pressed() {
@@ -151,19 +168,36 @@ void MaterialEditor::_on_light_2_switch_pressed() {
}
void MaterialEditor::_on_sphere_switch_pressed() {
- box_instance->hide();
sphere_instance->show();
+ box_instance->hide();
+ quad_instance->hide();
box_switch->set_pressed(false);
- sphere_switch->set_pressed(true);
- EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true);
+ quad_switch->set_pressed(false);
+ _set_rotation(-15.0, 30.0);
+ _store_rotation_metadata();
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_mesh", "sphere");
}
void MaterialEditor::_on_box_switch_pressed() {
+ sphere_instance->hide();
box_instance->show();
+ quad_instance->hide();
+ sphere_switch->set_pressed(false);
+ quad_switch->set_pressed(false);
+ _set_rotation(-15.0, 30.0);
+ _store_rotation_metadata();
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_mesh", "box");
+}
+
+void MaterialEditor::_on_quad_switch_pressed() {
sphere_instance->hide();
- box_switch->set_pressed(true);
+ box_instance->hide();
+ quad_instance->show();
sphere_switch->set_pressed(false);
- EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false);
+ box_switch->set_pressed(false);
+ _set_rotation(0.0, 0.0);
+ _store_rotation_metadata();
+ EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_mesh", "quad");
}
MaterialEditor::MaterialEditor() {
@@ -213,7 +247,7 @@ MaterialEditor::MaterialEditor() {
viewport = memnew(SubViewport);
Ref<World3D> world_3d;
world_3d.instantiate();
- viewport->set_world_3d(world_3d); //use own world
+ viewport->set_world_3d(world_3d); // Use own world.
vc->add_child(viewport);
viewport->set_disable_input(true);
viewport->set_transparent_background(true);
@@ -221,7 +255,7 @@ MaterialEditor::MaterialEditor() {
camera = memnew(Camera3D);
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,
+ // Use low field of view so the sphere/box/quad is fully encompassed within the preview,
// without much distortion.
camera->set_perspective(20, 0.1, 10);
camera->make_current();
@@ -249,13 +283,19 @@ MaterialEditor::MaterialEditor() {
box_instance = memnew(MeshInstance3D);
rotation->add_child(box_instance);
- box_instance->set_transform(Transform3D() * 0.25);
+ quad_instance = memnew(MeshInstance3D);
+ rotation->add_child(quad_instance);
+
sphere_instance->set_transform(Transform3D() * 0.375);
+ box_instance->set_transform(Transform3D() * 0.25);
+ quad_instance->set_transform(Transform3D() * 0.375);
sphere_mesh.instantiate();
sphere_instance->set_mesh(sphere_mesh);
box_mesh.instantiate();
box_instance->set_mesh(box_mesh);
+ quad_mesh.instantiate();
+ quad_instance->set_mesh(quad_mesh);
set_custom_minimum_size(Size2(1, 150) * EDSCALE);
@@ -269,17 +309,21 @@ MaterialEditor::MaterialEditor() {
sphere_switch = memnew(Button);
sphere_switch->set_theme_type_variation("PreviewLightButton");
sphere_switch->set_toggle_mode(true);
- sphere_switch->set_pressed(true);
vb_shape->add_child(sphere_switch);
sphere_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_sphere_switch_pressed));
box_switch = memnew(Button);
box_switch->set_theme_type_variation("PreviewLightButton");
box_switch->set_toggle_mode(true);
- box_switch->set_pressed(false);
vb_shape->add_child(box_switch);
box_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_box_switch_pressed));
+ quad_switch = memnew(Button);
+ quad_switch->set_theme_type_variation("PreviewLightButton");
+ quad_switch->set_toggle_mode(true);
+ vb_shape->add_child(quad_switch);
+ quad_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_quad_switch_pressed));
+
layout_3d->add_spacer();
VBoxContainer *vb_light = memnew(VBoxContainer);
@@ -299,14 +343,23 @@ MaterialEditor::MaterialEditor() {
vb_light->add_child(light_2_switch);
light_2_switch->connect(SceneStringName(pressed), callable_mp(this, &MaterialEditor::_on_light_2_switch_pressed));
- if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) {
+ String shape = EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_mesh", "sphere");
+ if (shape == "sphere") {
box_instance->hide();
+ quad_instance->hide();
+ sphere_switch->set_pressed_no_signal(true);
+ } else if (shape == "box") {
+ sphere_instance->hide();
+ quad_instance->hide();
+ box_switch->set_pressed_no_signal(true);
} else {
- box_instance->show();
sphere_instance->hide();
- box_switch->set_pressed(true);
- sphere_switch->set_pressed(false);
+ box_instance->hide();
+ quad_switch->set_pressed_no_signal(true);
}
+
+ Vector2 stored_rot = EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_rotation", Vector2());
+ _set_rotation(stored_rot.x, stored_rot.y);
}
///////////////////////
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index 28c59d27db..c1b37a5831 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -62,6 +62,7 @@ class MaterialEditor : public Control {
Node3D *rotation = nullptr;
MeshInstance3D *sphere_instance = nullptr;
MeshInstance3D *box_instance = nullptr;
+ MeshInstance3D *quad_instance = nullptr;
DirectionalLight3D *light1 = nullptr;
DirectionalLight3D *light2 = nullptr;
Camera3D *camera = nullptr;
@@ -69,6 +70,7 @@ class MaterialEditor : public Control {
Ref<SphereMesh> sphere_mesh;
Ref<BoxMesh> box_mesh;
+ Ref<QuadMesh> quad_mesh;
VBoxContainer *layout_error = nullptr;
Label *error_label = nullptr;
@@ -80,6 +82,7 @@ class MaterialEditor : public Control {
Button *sphere_switch = nullptr;
Button *box_switch = nullptr;
+ Button *quad_switch = nullptr;
Button *light_1_switch = nullptr;
Button *light_2_switch = nullptr;
@@ -88,6 +91,7 @@ class MaterialEditor : public Control {
Ref<Texture2D> light_2_icon;
Ref<Texture2D> sphere_icon;
Ref<Texture2D> box_icon;
+ Ref<Texture2D> quad_icon;
Ref<Texture2D> checkerboard;
} theme_cache;
@@ -95,11 +99,14 @@ class MaterialEditor : public Control {
void _on_light_2_switch_pressed();
void _on_sphere_switch_pressed();
void _on_box_switch_pressed();
+ void _on_quad_switch_pressed();
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
void gui_input(const Ref<InputEvent> &p_event) override;
+ void _set_rotation(real_t p_x_degrees, real_t p_y_degrees);
+ void _store_rotation_metadata();
void _update_rotation();
public:
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index c8eda600b8..645dd1784e 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -58,8 +58,8 @@ void MeshEditor::_update_theme_item_cache() {
void MeshEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- light_1_switch->set_icon(theme_cache.light_1_icon);
- light_2_switch->set_icon(theme_cache.light_2_icon);
+ light_1_switch->set_button_icon(theme_cache.light_1_icon);
+ light_2_switch->set_button_icon(theme_cache.light_2_icon);
} break;
}
}
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index eda6cdffb1..fdc222e64f 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -40,6 +40,7 @@
#include "scene/3d/physics/collision_shape_3d.h"
#include "scene/3d/physics/physics_body_3d.h"
#include "scene/3d/physics/static_body_3d.h"
+#include "scene/gui/aspect_ratio_container.h"
#include "scene/gui/box_container.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/menu_button.h"
@@ -445,10 +446,43 @@ void MeshInstance3DEditor::_debug_uv_draw() {
}
debug_uv->set_clip_contents(true);
- debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), get_theme_color(SNAME("dark_color_3"), EditorStringName(Editor)));
+ debug_uv->draw_rect(
+ Rect2(Vector2(), debug_uv->get_size()),
+ get_theme_color(SNAME("dark_color_3"), EditorStringName(Editor)));
+
+ // Draw an outline to represent the UV2's beginning and end area (useful on Black OLED theme).
+ // Top-left coordinate needs to be `(1, 1)` to prevent `clip_contents` from clipping the top and left lines.
+ debug_uv->draw_rect(
+ Rect2(Vector2(1, 1), debug_uv->get_size() - Vector2(1, 1)),
+ get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.125),
+ false,
+ Math::round(EDSCALE));
+
+ for (int x = 1; x <= 7; x++) {
+ debug_uv->draw_line(
+ Vector2(debug_uv->get_size().x * 0.125 * x, 0),
+ Vector2(debug_uv->get_size().x * 0.125 * x, debug_uv->get_size().y),
+ get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.125),
+ Math::round(EDSCALE));
+ }
+
+ for (int y = 1; y <= 7; y++) {
+ debug_uv->draw_line(
+ Vector2(0, debug_uv->get_size().y * 0.125 * y),
+ Vector2(debug_uv->get_size().x, debug_uv->get_size().y * 0.125 * y),
+ get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.125),
+ Math::round(EDSCALE));
+ }
+
debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
+
// Use a translucent color to allow overlapping triangles to be visible.
- debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.5));
+ // Divide line width by the drawing scale set above, so that line width is consistent regardless of dialog size.
+ // Aspect ratio is preserved by the parent AspectRatioContainer, so we only need to check the X size which is always equal to Y.
+ debug_uv->draw_multiline(
+ uv_lines,
+ get_theme_color(SNAME("mono_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.5),
+ Math::round(EDSCALE) / debug_uv->get_size().x);
}
void MeshInstance3DEditor::_create_navigation_mesh() {
@@ -527,7 +561,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
void MeshInstance3DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- options->set_icon(get_editor_theme_icon(SNAME("MeshInstance3D")));
+ options->set_button_icon(get_editor_theme_icon(SNAME("MeshInstance3D")));
} break;
}
}
@@ -613,10 +647,14 @@ MeshInstance3DEditor::MeshInstance3DEditor() {
debug_uv_dialog = memnew(AcceptDialog);
debug_uv_dialog->set_title(TTR("UV Channel Debug"));
add_child(debug_uv_dialog);
+
+ debug_uv_arc = memnew(AspectRatioContainer);
+ debug_uv_dialog->add_child(debug_uv_arc);
+
debug_uv = memnew(Control);
debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE);
debug_uv->connect(SceneStringName(draw), callable_mp(this, &MeshInstance3DEditor::_debug_uv_draw));
- debug_uv_dialog->add_child(debug_uv);
+ debug_uv_arc->add_child(debug_uv);
navigation_mesh_dialog = memnew(ConfirmationDialog);
navigation_mesh_dialog->set_title(TTR("Create NavigationMesh"));
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h
index c982df9c5f..569ecd4fff 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.h
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.h
@@ -36,6 +36,7 @@
#include "scene/gui/option_button.h"
class AcceptDialog;
+class AspectRatioContainer;
class ConfirmationDialog;
class MenuButton;
class SpinBox;
@@ -79,6 +80,7 @@ class MeshInstance3DEditor : public Control {
AcceptDialog *err_dialog = nullptr;
AcceptDialog *debug_uv_dialog = nullptr;
+ AspectRatioContainer *debug_uv_arc = nullptr;
Control *debug_uv = nullptr;
Vector<Vector2> uv_lines;
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index d6650bd08f..6f79ab0529 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -260,7 +260,7 @@ MeshLibraryEditor::MeshLibraryEditor() {
Node3DEditor::get_singleton()->add_control_to_menu_panel(menu);
menu->set_position(Point2(1, 1));
menu->set_text(TTR("MeshLibrary"));
- menu->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MeshLibrary"), EditorStringName(EditorIcons)));
+ menu->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MeshLibrary"), EditorStringName(EditorIcons)));
menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM);
menu->get_popup()->add_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM);
menu->get_popup()->add_separator();
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index 729ceccd25..9e686dd689 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -272,7 +272,7 @@ MultiMeshEditor::MultiMeshEditor() {
Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text("MultiMesh");
- options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MultiMeshInstance3D"), EditorStringName(EditorIcons)));
+ options->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MultiMeshInstance3D"), EditorStringName(EditorIcons)));
options->get_popup()->add_item(TTR("Populate Surface"));
options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &MultiMeshEditor::_menu_option));
diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
index 9629a673e9..94ad20f05a 100644
--- a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
+++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
@@ -30,144 +30,502 @@
#include "navigation_obstacle_3d_editor_plugin.h"
-#include "canvas_item_editor_plugin.h"
-#include "core/input/input.h"
-#include "core/io/file_access.h"
+#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
-#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
-#include "node_3d_editor_plugin.h"
-#include "scene/3d/camera_3d.h"
-#include "scene/gui/separator.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/navigation_obstacle_3d.h"
+#include "scene/gui/button.h"
+#include "scene/gui/dialogs.h"
+#include "servers/navigation_server_3d.h"
+
+bool NavigationObstacle3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<NavigationObstacle3D>(p_spatial) != nullptr;
+}
+
+String NavigationObstacle3DGizmoPlugin::get_gizmo_name() const {
+ return "NavigationObstacle3D";
+}
+
+void NavigationObstacle3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ p_gizmo->clear();
+
+ if (!p_gizmo->is_selected() && get_state() == HIDDEN) {
+ return;
+ }
+
+ NavigationObstacle3D *obstacle = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+
+ if (!obstacle) {
+ return;
+ }
+
+ const Vector<Vector3> &vertices = obstacle->get_vertices();
+ if (vertices.is_empty()) {
+ return;
+ }
+
+ float height = obstacle->get_height();
+ Basis gbi = obstacle->get_global_basis().inverse();
+
+ const int vertex_count = vertices.size();
+
+ Vector<Vector3> lines_mesh_vertices;
+ lines_mesh_vertices.resize(vertex_count * 8);
+ Vector3 *lines_mesh_vertices_ptrw = lines_mesh_vertices.ptrw();
+
+ int vertex_index = 0;
+
+ for (int i = 0; i < vertex_count; i++) {
+ Vector3 point = vertices[i];
+ Vector3 next_point = vertices[(i + 1) % vertex_count];
+
+ Vector3 direction = next_point.direction_to(point);
+ Vector3 arrow_dir = direction.cross(Vector3(0.0, 1.0, 0.0));
+ Vector3 edge_middle = point + ((next_point - point) * 0.5);
+
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(edge_middle);
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(edge_middle + (arrow_dir * 0.5));
+
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(point);
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(next_point);
+
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(Vector3(point.x, height, point.z));
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(Vector3(next_point.x, height, next_point.z));
+
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(point);
+ lines_mesh_vertices_ptrw[vertex_index++] = gbi.xform(Vector3(point.x, height, point.z));
+ }
+
+ Vector<Vector2> polygon_2d_vertices;
+ polygon_2d_vertices.resize(vertex_count);
+ for (int i = 0; i < vertex_count; i++) {
+ const Vector3 &vert = vertices[i];
+ polygon_2d_vertices.write[i] = Vector2(vert.x, vert.z);
+ }
+ Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(polygon_2d_vertices);
+
+ NavigationServer3D *ns3d = NavigationServer3D::get_singleton();
+
+ if (triangulated_polygon_2d_indices.is_empty()) {
+ p_gizmo->add_lines(lines_mesh_vertices, ns3d->get_debug_navigation_avoidance_static_obstacle_pushin_edge_material());
+ } else {
+ p_gizmo->add_lines(lines_mesh_vertices, ns3d->get_debug_navigation_avoidance_static_obstacle_pushout_edge_material());
+ }
+ p_gizmo->add_collision_segments(lines_mesh_vertices);
+
+ if (p_gizmo->is_selected()) {
+ NavigationObstacle3DEditorPlugin::singleton->redraw();
+ }
+}
+
+bool NavigationObstacle3DGizmoPlugin::can_be_hidden() const {
+ return true;
+}
+
+int NavigationObstacle3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+int NavigationObstacle3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
+ if (NavigationObstacle3DEditorPlugin::singleton->get_mode() != 1) { // MODE_EDIT
+ return -1;
+ }
+
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL_V(obstacle_node, -1);
+
+ Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
+ const Vector<Vector3> &vertices = obstacle_node->get_vertices();
+
+ for (int idx = 0; idx < vertices.size(); ++idx) {
+ Vector3 pos = gt.xform(vertices[idx]);
+ if (p_camera->unproject_position(pos).distance_to(p_point) < 20) {
+ return idx;
+ }
+ }
+
+ return -1;
+}
+
+Vector<int> NavigationObstacle3DGizmoPlugin::subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const {
+ Vector<int> contained_points;
+ if (NavigationObstacle3DEditorPlugin::singleton->get_mode() != 1) { // MODE_EDIT
+ return contained_points;
+ }
+
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL_V(obstacle_node, contained_points);
+
+ Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
+ const Vector<Vector3> &vertices = obstacle_node->get_vertices();
+
+ for (int idx = 0; idx < vertices.size(); ++idx) {
+ Vector3 pos = gt.xform(vertices[idx]);
+ bool is_contained_in_frustum = true;
+ for (int i = 0; i < p_frustum.size(); ++i) {
+ if (p_frustum[i].distance_to(pos) > 0) {
+ is_contained_in_frustum = false;
+ break;
+ }
+ }
+
+ if (is_contained_in_frustum) {
+ contained_points.push_back(idx);
+ }
+ }
+
+ return contained_points;
+}
+
+Transform3D NavigationObstacle3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL_V(obstacle_node, Transform3D());
+
+ const Vector<Vector3> &vertices = obstacle_node->get_vertices();
+ ERR_FAIL_INDEX_V(p_id, vertices.size(), Transform3D());
+
+ Basis gbi = obstacle_node->get_global_basis().inverse();
+
+ Transform3D subgizmo_transform = Transform3D(Basis(), gbi.xform(vertices[p_id]));
+ return subgizmo_transform;
+}
+
+void NavigationObstacle3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) {
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL(obstacle_node);
+
+ Basis gb = obstacle_node->get_global_basis();
+
+ Vector3 new_vertex_pos = p_transform.origin;
+
+ Vector<Vector3> vertices = obstacle_node->get_vertices();
+ ERR_FAIL_INDEX(p_id, vertices.size());
-void NavigationObstacle3DEditor::_notification(int p_what) {
+ Vector3 vertex = gb.xform(new_vertex_pos);
+ vertex.y = 0.0;
+ vertices.write[p_id] = vertex;
+
+ obstacle_node->set_vertices(vertices);
+}
+
+void NavigationObstacle3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) {
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL(obstacle_node);
+
+ Basis gb = obstacle_node->get_global_basis();
+
+ Vector<Vector3> vertices = obstacle_node->get_vertices();
+ Vector<Vector3> restore_vertices = vertices;
+
+ for (int i = 0; i < p_ids.size(); ++i) {
+ const int idx = p_ids[i];
+ Vector3 vertex = gb.xform(p_restore[i].origin);
+ vertex.y = 0.0;
+ restore_vertices.write[idx] = vertex;
+ }
+
+ if (p_cancel) {
+ obstacle_node->set_vertices(restore_vertices);
+ return;
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Set Obstacle Vertices"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", vertices);
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", restore_vertices);
+ undo_redo->commit_action();
+}
+
+NavigationObstacle3DGizmoPlugin::NavigationObstacle3DGizmoPlugin() {
+ current_state = VISIBLE;
+}
+
+void NavigationObstacle3DEditorPlugin::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_theme();
+ } break;
+
case NOTIFICATION_READY: {
- button_create->set_icon(get_editor_theme_icon(SNAME("Edit")));
- button_edit->set_icon(get_editor_theme_icon(SNAME("MovePoint")));
+ _update_theme();
button_edit->set_pressed(true);
- get_tree()->connect("node_removed", callable_mp(this, &NavigationObstacle3DEditor::_node_removed));
+ get_tree()->connect("node_removed", callable_mp(this, &NavigationObstacle3DEditorPlugin::_node_removed));
+ EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &NavigationObstacle3DEditorPlugin::_update_theme));
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &NavigationObstacle3DEditorPlugin::_node_removed));
+ EditorNode::get_singleton()->get_gui_base()->disconnect(SceneStringName(theme_changed), callable_mp(this, &NavigationObstacle3DEditorPlugin::_update_theme));
} break;
}
}
-void NavigationObstacle3DEditor::_node_removed(Node *p_node) {
- if (p_node == obstacle_node) {
- obstacle_node = nullptr;
- if (point_lines_meshinstance->get_parent() == p_node) {
- p_node->remove_child(point_lines_meshinstance);
+void NavigationObstacle3DEditorPlugin::edit(Object *p_object) {
+ obstacle_node = Object::cast_to<NavigationObstacle3D>(p_object);
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ if (obstacle_node) {
+ if (obstacle_node->get_vertices().is_empty()) {
+ set_mode(MODE_CREATE);
+ } else {
+ set_mode(MODE_EDIT);
}
- hide();
+ wip_vertices.clear();
+ wip_active = false;
+ edited_point = -1;
+
+ rs->instance_set_scenario(point_lines_instance_rid, obstacle_node->get_world_3d()->get_scenario());
+ rs->instance_set_scenario(point_handles_instance_rid, obstacle_node->get_world_3d()->get_scenario());
+
+ redraw();
+
+ } else {
+ obstacle_node = nullptr;
+
+ rs->mesh_clear(point_lines_mesh_rid);
+ rs->mesh_clear(point_handle_mesh_rid);
+ rs->instance_set_scenario(point_lines_instance_rid, RID());
+ rs->instance_set_scenario(point_handles_instance_rid, RID());
}
}
-void NavigationObstacle3DEditor::_menu_option(int p_option) {
- switch (p_option) {
- case MODE_CREATE: {
- mode = MODE_CREATE;
- button_create->set_pressed(true);
- button_edit->set_pressed(false);
- } break;
- case MODE_EDIT: {
- mode = MODE_EDIT;
- button_create->set_pressed(false);
- button_edit->set_pressed(true);
- } break;
+bool NavigationObstacle3DEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<NavigationObstacle3D>(p_object);
+}
+
+void NavigationObstacle3DEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ obstacle_editor->show();
+ } else {
+ obstacle_editor->hide();
+ edit(nullptr);
}
}
-void NavigationObstacle3DEditor::_wip_close() {
- ERR_FAIL_NULL_MSG(obstacle_node, "Edited NavigationObstacle3D is not valid.");
+void NavigationObstacle3DEditorPlugin::action_flip_vertices() {
+ if (!obstacle_node) {
+ return;
+ }
+
+ Vector<Vector3> flipped_vertices = obstacle_node->get_vertices();
+ flipped_vertices.reverse();
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Set NavigationObstacle3D Vertices"));
+ undo_redo->create_action(TTR("Edit Obstacle (Flip Winding)"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", flipped_vertices);
undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->commit_action();
- PackedVector3Array polygon_3d_vertices;
- Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(wip);
+ obstacle_node->update_gizmos();
+}
- if (!triangulated_polygon_2d_indices.is_empty()) {
- polygon_3d_vertices.resize(wip.size());
- Vector3 *polygon_3d_vertices_ptr = polygon_3d_vertices.ptrw();
- for (int i = 0; i < wip.size(); i++) {
- const Vector2 &vert = wip[i];
- polygon_3d_vertices_ptr[i] = Vector3(vert.x, 0.0, vert.y);
- }
+void NavigationObstacle3DEditorPlugin::action_clear_vertices() {
+ if (!obstacle_node) {
+ return;
}
- undo_redo->add_do_method(obstacle_node, "set_vertices", polygon_3d_vertices);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
- wip.clear();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Edit Obstacle (Clear Vertices)"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", Vector<Vector3>());
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->commit_action();
+
+ obstacle_node->update_gizmos();
+ edit(obstacle_node);
+}
+
+void NavigationObstacle3DEditorPlugin::_update_theme() {
+ button_create->set_tooltip_text(TTR("Add Vertex"));
+ button_edit->set_tooltip_text(TTR("Edit Vertex"));
+ button_delete->set_tooltip_text(TTR("Delete Vertex"));
+ button_flip->set_tooltip_text(TTR("Flip Winding"));
+ button_clear->set_tooltip_text(TTR("Clear Vertices"));
+ button_create->set_button_icon(button_create->get_editor_theme_icon(SNAME("CurveCreate")));
+ button_edit->set_button_icon(button_edit->get_editor_theme_icon(SNAME("CurveEdit")));
+ button_delete->set_button_icon(button_delete->get_editor_theme_icon(SNAME("CurveDelete")));
+ button_flip->set_button_icon(button_flip->get_editor_theme_icon(SNAME("FlipWinding")));
+ button_clear->set_button_icon(button_clear->get_editor_theme_icon(SNAME("Clear")));
+}
+
+void NavigationObstacle3DEditorPlugin::_node_removed(Node *p_node) {
+ if (obstacle_node == p_node) {
+ obstacle_node = nullptr;
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+ rs->mesh_clear(point_lines_mesh_rid);
+ rs->mesh_clear(point_handle_mesh_rid);
+
+ obstacle_editor->hide();
+ }
+}
+
+void NavigationObstacle3DEditorPlugin::set_mode(int p_option) {
+ if (p_option == NavigationObstacle3DEditorPlugin::ACTION_FLIP) {
+ button_flip->set_pressed(false);
+ action_flip_vertices();
+ return;
+ }
+
+ if (p_option == NavigationObstacle3DEditorPlugin::ACTION_CLEAR) {
+ button_clear->set_pressed(false);
+ button_clear_dialog->reset_size();
+ button_clear_dialog->popup_centered();
+ return;
+ }
+
+ mode = p_option;
+
+ button_create->set_pressed(p_option == NavigationObstacle3DEditorPlugin::MODE_CREATE);
+ button_edit->set_pressed(p_option == NavigationObstacle3DEditorPlugin::MODE_EDIT);
+ button_delete->set_pressed(p_option == NavigationObstacle3DEditorPlugin::MODE_DELETE);
+ button_flip->set_pressed(false);
+ button_clear->set_pressed(false);
+}
+
+void NavigationObstacle3DEditorPlugin::_wip_cancel() {
+ wip_vertices.clear();
wip_active = false;
- mode = MODE_EDIT;
- button_edit->set_pressed(true);
- button_create->set_pressed(false);
+
edited_point = -1;
- undo_redo->commit_action();
+
+ redraw();
}
-EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+void NavigationObstacle3DEditorPlugin::_wip_close() {
+ ERR_FAIL_NULL_MSG(obstacle_node, "Edited NavigationObstacle3D is not valid.");
+
+ Vector<Vector2> wip_2d_vertices;
+ wip_2d_vertices.resize(wip_vertices.size());
+ for (int i = 0; i < wip_vertices.size(); i++) {
+ const Vector3 &vert = wip_vertices[i];
+ wip_2d_vertices.write[i] = Vector2(vert.x, vert.z);
+ }
+ Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(wip_2d_vertices);
+
+ if (!triangulated_polygon_2d_indices.is_empty()) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Set Obstacle Vertices"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", wip_vertices);
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->commit_action();
+
+ wip_vertices.clear();
+ wip_active = false;
+ //mode = MODE_EDIT;
+ NavigationObstacle3DEditorPlugin::singleton->set_mode(NavigationObstacle3DEditorPlugin::MODE_EDIT);
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ edited_point = -1;
+ }
+}
+
+EditorPlugin::AfterGUIInput NavigationObstacle3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!obstacle_node) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
- Transform3D gt = obstacle_node->get_global_transform();
- Transform3D gi = gt.affine_inverse();
- Plane p(Vector3(0.0, 1.0, 0.0), gt.origin);
+ if (!obstacle_node->is_visible_in_tree()) {
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
+ }
+
+ Ref<InputEventMouse> mouse_event = p_event;
+
+ if (mouse_event.is_null()) {
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
+ }
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- Vector2 gpoint = mb->get_position();
- Vector3 ray_from = p_camera->project_ray_origin(gpoint);
- Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+ Vector2 mouse_position = mb->get_position();
+ Vector3 ray_from = p_camera->project_ray_origin(mouse_position);
+ Vector3 ray_dir = p_camera->project_ray_normal(mouse_position);
+
+ Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
+ Transform3D gi = gt.affine_inverse();
+ Plane projection_plane(Vector3(0.0, 1.0, 0.0), gt.origin);
Vector3 spoint;
- if (!p.intersects_ray(ray_from, ray_dir, &spoint)) {
+ if (!projection_plane.intersects_ray(ray_from, ray_dir, &spoint)) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
spoint = gi.xform(spoint);
- Vector2 cpoint(spoint.x, spoint.z);
-
- //DO NOT snap here, it's confusing in 3D for adding points.
- //Let the snap happen when the point is being moved, instead.
- //cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint);
+ Vector3 cpoint = Vector3(spoint.x, 0.0, spoint.z);
+ Vector<Vector3> obstacle_vertices = obstacle_node->get_vertices();
- PackedVector2Array poly = _get_polygon();
-
- //first check if a point is to be added (segment split)
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
switch (mode) {
case MODE_CREATE: {
if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
+ if (obstacle_vertices.size() >= 3) {
+ int closest_idx = -1;
+ Vector2 closest_edge_point;
+ real_t closest_dist = 1e10;
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
+ Vector2 points[2] = {
+ p_camera->unproject_position(gt.xform(obstacle_vertices[i])),
+ p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]))
+ };
+
+ Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, points);
+ if (cp.distance_squared_to(points[0]) < grab_threshold || cp.distance_squared_to(points[1]) < grab_threshold) {
+ continue; // Skip edge as clicked point is too close to existing vertex.
+ }
+
+ real_t d = cp.distance_to(mouse_position);
+ if (d < closest_dist && d < grab_threshold) {
+ closest_dist = d;
+ closest_edge_point = cp;
+ closest_idx = i;
+ }
+ }
+ if (closest_idx >= 0) {
+ edited_point = -1;
+ Vector3 _ray_from = p_camera->project_ray_origin(closest_edge_point);
+ Vector3 _ray_dir = p_camera->project_ray_normal(closest_edge_point);
+ Vector3 edge_intersection_point;
+ if (projection_plane.intersects_ray(_ray_from, _ray_dir, &edge_intersection_point)) {
+ edge_intersection_point = gi.xform(edge_intersection_point);
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Edit Obstacle (Add Vertex)"));
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_vertices);
+ obstacle_vertices.insert(closest_idx + 1, edge_intersection_point);
+ undo_redo->add_do_method(obstacle_node, "set_vertices", obstacle_vertices);
+ undo_redo->commit_action();
+ redraw();
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
+ }
+ }
+ }
if (!wip_active) {
- wip.clear();
- wip.push_back(cpoint);
+ wip_vertices.clear();
+ wip_vertices.push_back(cpoint);
wip_active = true;
edited_point_pos = cpoint;
snap_ignore = false;
- _polygon_draw();
+ redraw();
edited_point = 1;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
- if (wip.size() > 1 && p_camera->unproject_position(gt.xform(Vector3(wip[0].x, 0.0, wip[0].y))).distance_to(gpoint) < grab_threshold) {
- //wip closed
+ if (wip_vertices.size() > 1 && p_camera->unproject_position(gt.xform(wip_vertices[0])).distance_to(mouse_position) < grab_threshold) {
_wip_close();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
- wip.push_back(cpoint);
- edited_point = wip.size();
+ wip_vertices.push_back(cpoint);
+ edited_point = wip_vertices.size();
snap_ignore = false;
- _polygon_draw();
+ redraw();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
@@ -181,13 +539,11 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (mb->is_ctrl_pressed()) {
- if (poly.size() < 3) {
+ if (obstacle_vertices.size() < 3) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Vertices"));
+ undo_redo->create_action(TTR("Edit Obstacle (Add Vertex)"));
undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
- poly.push_back(cpoint);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
+ obstacle_vertices.push_back(cpoint);
undo_redo->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
@@ -196,18 +552,18 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
int closest_idx = -1;
Vector2 closest_pos;
real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
Vector2 points[2] = {
- p_camera->unproject_position(gt.xform(Vector3(poly[i].x, 0.0, poly[i].y))),
- p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, 0.0, poly[(i + 1) % poly.size()].y)))
+ p_camera->unproject_position(gt.xform(obstacle_vertices[i])),
+ p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]))
};
- Vector2 cp = Geometry2D::get_closest_point_to_segment(gpoint, points);
+ Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, points);
if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) {
continue; //not valid to reuse point
}
- real_t d = cp.distance_to(gpoint);
+ real_t d = cp.distance_to(mouse_position);
if (d < closest_dist && d < grab_threshold) {
closest_dist = d;
closest_pos = cp;
@@ -216,26 +572,24 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
}
if (closest_idx >= 0) {
- pre_move_edit = poly;
- poly.insert(closest_idx + 1, cpoint);
+ pre_move_edit = obstacle_vertices;
+ obstacle_vertices.insert(closest_idx + 1, cpoint);
edited_point = closest_idx + 1;
edited_point_pos = cpoint;
- _set_polygon(poly);
- _polygon_draw();
+ obstacle_node->set_vertices(obstacle_vertices);
+ redraw();
snap_ignore = true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
} else {
- //look for points to move
-
int closest_idx = -1;
Vector2 closest_pos;
real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
- Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, 0.0, poly[i].y)));
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
+ Vector2 cp = p_camera->unproject_position(gt.xform(obstacle_vertices[i]));
- real_t d = cp.distance_to(gpoint);
+ real_t d = cp.distance_to(mouse_position);
if (d < closest_dist && d < grab_threshold) {
closest_dist = d;
closest_pos = cp;
@@ -244,10 +598,10 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
}
if (closest_idx >= 0) {
- pre_move_edit = poly;
+ pre_move_edit = obstacle_vertices;
edited_point = closest_idx;
- edited_point_pos = poly[closest_idx];
- _polygon_draw();
+ edited_point_pos = obstacle_vertices[closest_idx];
+ redraw();
snap_ignore = false;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
@@ -256,16 +610,13 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
snap_ignore = false;
if (edited_point != -1) {
- //apply
+ ERR_FAIL_INDEX_V(edited_point, obstacle_vertices.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
+ obstacle_vertices.write[edited_point] = edited_point_pos;
- ERR_FAIL_INDEX_V(edited_point, poly.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
- poly.write[edited_point] = edited_point_pos;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Poly"));
- //undo_redo->add_do_method(obj, "set_polygon", poly);
- //undo_redo->add_undo_method(obj, "set_polygon", pre_move_edit);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
+ undo_redo->create_action(TTR("Edit Obstacle (Move Vertex)"));
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->add_do_method(obstacle_node, "set_vertices", obstacle_vertices);
undo_redo->commit_action();
edited_point = -1;
@@ -273,30 +624,31 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
}
}
}
- if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && edited_point == -1) {
+
+ } break;
+
+ case MODE_DELETE: {
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
int closest_idx = -1;
- Vector2 closest_pos;
real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
- Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, 0.0, poly[i].y)));
-
- real_t d = cp.distance_to(gpoint);
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
+ Vector2 point = p_camera->unproject_position(gt.xform(obstacle_vertices[i]));
+ real_t d = point.distance_to(mouse_position);
if (d < closest_dist && d < grab_threshold) {
closest_dist = d;
- closest_pos = cp;
closest_idx = i;
}
}
if (closest_idx >= 0) {
+ edited_point = -1;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
- //undo_redo->add_undo_method(obj, "set_polygon", poly);
- poly.remove_at(closest_idx);
- //undo_redo->add_do_method(obj, "set_polygon", poly);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
+ undo_redo->create_action(TTR("Edit Obstacle (Remove Vertex)"));
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_vertices);
+ obstacle_vertices.remove_at(closest_idx);
+ undo_redo->add_do_method(obstacle_node, "set_vertices", obstacle_vertices);
undo_redo->commit_action();
+ redraw();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
@@ -309,20 +661,24 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
if (mm.is_valid()) {
if (edited_point != -1 && (wip_active || mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
- Vector2 gpoint = mm->get_position();
+ Vector2 mouse_position = mm->get_position();
+
+ Vector3 ray_from = p_camera->project_ray_origin(mouse_position);
+ Vector3 ray_dir = p_camera->project_ray_normal(mouse_position);
- Vector3 ray_from = p_camera->project_ray_origin(gpoint);
- Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+ Transform3D gt = Transform3D(Basis(), obstacle_node->get_global_position());
+ Transform3D gi = gt.affine_inverse();
+ Plane projection_plane(Vector3(0.0, 1.0, 0.0), gt.origin);
- Vector3 spoint;
+ Vector3 intersection_point;
- if (!p.intersects_ray(ray_from, ray_dir, &spoint)) {
+ if (!projection_plane.intersects_ray(ray_from, ray_dir, &intersection_point)) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
- spoint = gi.xform(spoint);
+ intersection_point = gi.xform(intersection_point);
- Vector2 cpoint(spoint.x, spoint.z);
+ Vector2 cpoint(intersection_point.x, intersection_point.z);
if (snap_ignore && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
snap_ignore = false;
@@ -331,272 +687,217 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
if (!snap_ignore && Node3DEditor::get_singleton()->is_snap_enabled()) {
cpoint = cpoint.snappedf(Node3DEditor::get_singleton()->get_translate_snap());
}
- edited_point_pos = cpoint;
+ edited_point_pos = Vector3(cpoint.x, 0.0, cpoint.y);
- _polygon_draw();
+ redraw();
}
}
- return EditorPlugin::AFTER_GUI_INPUT_PASS;
-}
+ Ref<InputEventKey> k = p_event;
-PackedVector2Array NavigationObstacle3DEditor::_get_polygon() {
- ERR_FAIL_NULL_V_MSG(obstacle_node, PackedVector2Array(), "Edited object is not valid.");
- return PackedVector2Array(obstacle_node->call("get_polygon"));
-}
+ if (k.is_valid() && k->is_pressed()) {
+ if (wip_active && k->get_keycode() == Key::ENTER) {
+ _wip_close();
+ } else if (wip_active && k->get_keycode() == Key::ESCAPE) {
+ _wip_cancel();
+ }
+ }
-void NavigationObstacle3DEditor::_set_polygon(const PackedVector2Array &p_poly) {
- ERR_FAIL_NULL_MSG(obstacle_node, "Edited object is not valid.");
- obstacle_node->call("set_polygon", p_poly);
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
-void NavigationObstacle3DEditor::_polygon_draw() {
+void NavigationObstacle3DEditorPlugin::redraw() {
if (!obstacle_node) {
return;
}
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ rs->mesh_clear(point_lines_mesh_rid);
+ rs->mesh_clear(point_handle_mesh_rid);
+
+ if (!obstacle_node->is_visible_in_tree()) {
+ return;
+ }
- PackedVector2Array poly;
- PackedVector3Array polygon_3d_vertices;
+ Vector<Vector3> edited_vertices;
if (wip_active) {
- poly = wip;
+ edited_vertices = wip_vertices;
} else {
- poly = _get_polygon();
+ edited_vertices = obstacle_node->get_vertices();
}
- polygon_3d_vertices.resize(poly.size());
- Vector3 *polygon_3d_vertices_ptr = polygon_3d_vertices.ptrw();
- for (int i = 0; i < poly.size(); i++) {
- const Vector2 &vert = poly[i];
- polygon_3d_vertices_ptr[i] = Vector3(vert.x, 0.0, vert.y);
+ if (edited_vertices.is_empty()) {
+ return;
}
- point_handle_mesh->clear_surfaces();
- point_lines_mesh->clear_surfaces();
- point_lines_meshinstance->set_material_override(line_material);
- point_lines_mesh->surface_begin(Mesh::PRIMITIVE_LINES);
+ Array point_lines_mesh_array;
+ point_lines_mesh_array.resize(Mesh::ARRAY_MAX);
- Rect2 rect;
+ Vector<Vector3> point_lines_mesh_vertices;
+ point_lines_mesh_vertices.resize(edited_vertices.size() * 2);
+ Vector3 *point_lines_mesh_vertices_ptr = point_lines_mesh_vertices.ptrw();
- for (int i = 0; i < poly.size(); i++) {
- Vector2 p, p2;
- if (i == edited_point) {
- p = edited_point_pos;
- } else {
- p = poly[i];
- }
+ int vertex_index = 0;
- if ((wip_active && i == poly.size() - 1) || (((i + 1) % poly.size()) == edited_point)) {
- p2 = edited_point_pos;
+ for (int i = 0; i < edited_vertices.size(); i++) {
+ Vector3 point, next_point;
+ if (i == edited_point) {
+ point = edited_point_pos;
} else {
- p2 = poly[(i + 1) % poly.size()];
+ point = edited_vertices[i];
}
- if (i == 0) {
- rect.position = p;
+ if ((wip_active && i == edited_vertices.size() - 1) || (((i + 1) % edited_vertices.size()) == edited_point)) {
+ next_point = edited_point_pos;
} else {
- rect.expand_to(p);
+ next_point = edited_vertices[(i + 1) % edited_vertices.size()];
}
- Vector3 point = Vector3(p.x, 0.0, p.y);
- Vector3 next_point = Vector3(p2.x, 0.0, p2.y);
-
- point_lines_mesh->surface_set_color(Color(1, 0.3, 0.1, 0.8));
- point_lines_mesh->surface_add_vertex(point);
- point_lines_mesh->surface_set_color(Color(1, 0.3, 0.1, 0.8));
- point_lines_mesh->surface_add_vertex(next_point);
-
- //Color col=Color(1,0.3,0.1,0.8);
- //vpc->draw_line(point,next_point,col,2);
- //vpc->draw_texture(handle,point-handle->get_size()*0.5);
- }
-
- rect = rect.grow(1);
-
- AABB r;
- r.position.x = rect.position.x;
- r.position.y = 0.0;
- r.position.z = rect.position.y;
- r.size.x = rect.size.x;
- r.size.y = 0;
- r.size.z = rect.size.y;
-
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position);
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(0.3, 0, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position);
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(0.0, 0.3, 0));
-
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0) - Vector3(0.3, 0, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0) + Vector3(0, 0.3, 0));
-
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0) - Vector3(0, 0.3, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0) + Vector3(0.3, 0, 0));
-
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + r.size);
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + r.size - Vector3(0.3, 0, 0));
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + r.size);
- point_lines_mesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2));
- point_lines_mesh->surface_add_vertex(r.position + r.size - Vector3(0.0, 0.3, 0));
-
- point_lines_mesh->surface_end();
-
- if (poly.size() == 0) {
- return;
+ point_lines_mesh_vertices_ptr[vertex_index++] = point;
+ point_lines_mesh_vertices_ptr[vertex_index++] = next_point;
}
+ point_lines_mesh_array[Mesh::ARRAY_VERTEX] = point_lines_mesh_vertices;
+
+ rs->mesh_add_surface_from_arrays(point_lines_mesh_rid, RS::PRIMITIVE_LINES, point_lines_mesh_array);
+ rs->instance_set_surface_override_material(point_lines_instance_rid, 0, line_material->get_rid());
+ rs->instance_set_transform(point_lines_instance_rid, Transform3D(Basis(), obstacle_node->get_global_position()));
+
Array point_handle_mesh_array;
point_handle_mesh_array.resize(Mesh::ARRAY_MAX);
Vector<Vector3> point_handle_mesh_vertices;
- point_handle_mesh_vertices.resize(poly.size());
+ point_handle_mesh_vertices.resize(edited_vertices.size());
Vector3 *point_handle_mesh_vertices_ptr = point_handle_mesh_vertices.ptrw();
- for (int i = 0; i < poly.size(); i++) {
- Vector2 point_2d;
- Vector2 p2;
+ for (int i = 0; i < edited_vertices.size(); i++) {
+ Vector3 point_handle_3d;
if (i == edited_point) {
- point_2d = edited_point_pos;
+ point_handle_3d = edited_point_pos;
} else {
- point_2d = poly[i];
+ point_handle_3d = edited_vertices[i];
}
- Vector3 point_handle_3d = Vector3(point_2d.x, 0.0, point_2d.y);
point_handle_mesh_vertices_ptr[i] = point_handle_3d;
}
point_handle_mesh_array[Mesh::ARRAY_VERTEX] = point_handle_mesh_vertices;
- point_handle_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, point_handle_mesh_array);
- point_handle_mesh->surface_set_material(0, handle_material);
-}
-
-void NavigationObstacle3DEditor::edit(Node *p_node) {
- obstacle_node = Object::cast_to<NavigationObstacle3D>(p_node);
-
- if (obstacle_node) {
- //Enable the pencil tool if the polygon is empty
- if (_get_polygon().is_empty()) {
- _menu_option(MODE_CREATE);
- }
- wip.clear();
- wip_active = false;
- edited_point = -1;
- if (point_lines_meshinstance->get_parent()) {
- point_lines_meshinstance->reparent(p_node, false);
- } else {
- p_node->add_child(point_lines_meshinstance);
- }
- _polygon_draw();
- } else {
- obstacle_node = nullptr;
-
- if (point_lines_meshinstance->get_parent()) {
- point_lines_meshinstance->get_parent()->remove_child(point_lines_meshinstance);
- }
- }
+ rs->mesh_add_surface_from_arrays(point_handle_mesh_rid, RS::PRIMITIVE_POINTS, point_handle_mesh_array);
+ rs->instance_set_surface_override_material(point_handles_instance_rid, 0, handle_material->get_rid());
+ rs->instance_set_transform(point_handles_instance_rid, Transform3D(Basis(), obstacle_node->get_global_position()));
}
-void NavigationObstacle3DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_polygon_draw"), &NavigationObstacle3DEditor::_polygon_draw);
-}
-
-NavigationObstacle3DEditor::NavigationObstacle3DEditor() {
- obstacle_node = nullptr;
+NavigationObstacle3DEditorPlugin *NavigationObstacle3DEditorPlugin::singleton = nullptr;
- button_create = memnew(Button);
- button_create->set_theme_type_variation("FlatButton");
- add_child(button_create);
- button_create->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditor::_menu_option).bind(MODE_CREATE));
- button_create->set_toggle_mode(true);
-
- button_edit = memnew(Button);
- button_edit->set_theme_type_variation("FlatButton");
- add_child(button_edit);
- button_edit->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditor::_menu_option).bind(MODE_EDIT));
- button_edit->set_toggle_mode(true);
-
- mode = MODE_EDIT;
- wip_active = false;
- point_lines_meshinstance = memnew(MeshInstance3D);
- point_lines_mesh.instantiate();
- point_lines_meshinstance->set_mesh(point_lines_mesh);
- point_lines_meshinstance->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
+NavigationObstacle3DEditorPlugin::NavigationObstacle3DEditorPlugin() {
+ singleton = this;
line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
line_material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
- line_material->set_albedo(Color(1, 1, 1));
+ line_material->set_albedo(Color(1, 0.3, 0.1, 0.8));
+ line_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
handle_material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
Ref<Texture2D> handle = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Editor3DHandle"), EditorStringName(EditorIcons));
handle_material->set_point_size(handle->get_width());
handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle);
+ handle_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
- point_handles_meshinstance = memnew(MeshInstance3D);
- point_lines_meshinstance->add_child(point_handles_meshinstance);
- point_handle_mesh.instantiate();
- point_handles_meshinstance->set_mesh(point_handle_mesh);
- point_handles_meshinstance->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
+ RenderingServer *rs = RenderingServer::get_singleton();
- snap_ignore = false;
-}
+ point_lines_mesh_rid = rs->mesh_create();
+ point_handle_mesh_rid = rs->mesh_create();
-NavigationObstacle3DEditor::~NavigationObstacle3DEditor() {
- memdelete(point_lines_meshinstance);
-}
+ point_lines_instance_rid = rs->instance_create();
+ point_handles_instance_rid = rs->instance_create();
-void NavigationObstacle3DEditorPlugin::edit(Object *p_object) {
- obstacle_editor->edit(Object::cast_to<Node>(p_object));
-}
+ rs->instance_set_base(point_lines_instance_rid, point_lines_mesh_rid);
+ rs->instance_set_base(point_handles_instance_rid, point_handle_mesh_rid);
-bool NavigationObstacle3DEditorPlugin::handles(Object *p_object) const {
- return Object::cast_to<NavigationObstacle3D>(p_object);
-}
+ obstacle_editor = memnew(HBoxContainer);
+ obstacle_editor->hide();
-void NavigationObstacle3DEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- obstacle_editor->show();
- } else {
- obstacle_editor->hide();
- obstacle_editor->edit(nullptr);
- }
-}
+ Ref<ButtonGroup> bg;
+ bg.instantiate();
+
+ button_create = memnew(Button);
+ button_create->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_create);
+ button_create->set_tooltip_text(TTR("Add Vertex"));
+ button_create->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::MODE_CREATE));
+ button_create->set_toggle_mode(true);
+ button_create->set_button_group(bg);
+
+ button_edit = memnew(Button);
+ button_edit->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_edit);
+ button_edit->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::MODE_EDIT));
+ button_edit->set_toggle_mode(true);
+ button_edit->set_button_group(bg);
+
+ button_delete = memnew(Button);
+ button_delete->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_delete);
+ button_delete->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::MODE_DELETE));
+ button_delete->set_toggle_mode(true);
+ button_delete->set_button_group(bg);
+
+ button_flip = memnew(Button);
+ button_flip->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_flip);
+ button_flip->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::ACTION_FLIP));
+ button_flip->set_toggle_mode(true);
+
+ button_clear = memnew(Button);
+ button_clear->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_clear);
+ button_clear->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::ACTION_CLEAR));
+ button_clear->set_toggle_mode(true);
+
+ button_clear_dialog = memnew(ConfirmationDialog);
+ button_clear_dialog->set_title(TTR("Please Confirm..."));
+ button_clear_dialog->set_text(TTR("Remove all vertices?"));
+ button_clear_dialog->connect(SceneStringName(confirmed), callable_mp(NavigationObstacle3DEditorPlugin::singleton, &NavigationObstacle3DEditorPlugin::action_clear_vertices));
+ obstacle_editor->add_child(button_clear_dialog);
-NavigationObstacle3DEditorPlugin::NavigationObstacle3DEditorPlugin() {
- obstacle_editor = memnew(NavigationObstacle3DEditor);
Node3DEditor::get_singleton()->add_control_to_menu_panel(obstacle_editor);
- obstacle_editor->hide();
+ Ref<NavigationObstacle3DGizmoPlugin> gizmo_plugin = memnew(NavigationObstacle3DGizmoPlugin());
+ obstacle_3d_gizmo_plugin = gizmo_plugin;
+ Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
}
NavigationObstacle3DEditorPlugin::~NavigationObstacle3DEditorPlugin() {
+ RenderingServer *rs = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rs);
+
+ if (point_lines_instance_rid.is_valid()) {
+ rs->free(point_lines_instance_rid);
+ point_lines_instance_rid = RID();
+ }
+ if (point_lines_mesh_rid.is_valid()) {
+ rs->free(point_lines_mesh_rid);
+ point_lines_mesh_rid = RID();
+ }
+
+ if (point_handles_instance_rid.is_valid()) {
+ rs->free(point_handles_instance_rid);
+ point_handles_instance_rid = RID();
+ }
+ if (point_handle_mesh_rid.is_valid()) {
+ rs->free(point_handle_mesh_rid);
+ point_handle_mesh_rid = RID();
+ }
}
diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.h b/editor/plugins/navigation_obstacle_3d_editor_plugin.h
index c62a5a281b..b6f3a11cf6 100644
--- a/editor/plugins/navigation_obstacle_3d_editor_plugin.h
+++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.h
@@ -32,79 +32,99 @@
#define NAVIGATION_OBSTACLE_3D_EDITOR_PLUGIN_H
#include "editor/plugins/editor_plugin.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/physics/collision_polygon_3d.h"
+#include "editor/plugins/node_3d_editor_gizmos.h"
#include "scene/gui/box_container.h"
-#include "scene/resources/immediate_mesh.h"
-#include "scene/3d/navigation_obstacle_3d.h"
+class Button;
+class ConfirmationDialog;
+class NavigationObstacle3D;
-class CanvasItemEditor;
-class MenuButton;
+class NavigationObstacle3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(NavigationObstacle3DGizmoPlugin, EditorNode3DGizmoPlugin);
-class NavigationObstacle3DEditor : public HBoxContainer {
- GDCLASS(NavigationObstacle3DEditor, HBoxContainer);
+public:
+ virtual bool has_gizmo(Node3D *p_spatial) override;
+ virtual String get_gizmo_name() const override;
- enum Mode {
- MODE_CREATE,
- MODE_EDIT,
+ virtual void redraw(EditorNode3DGizmo *p_gizmo) override;
- };
+ bool can_be_hidden() const override;
+ int get_priority() const override;
- Mode mode;
+ virtual int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const override;
+ virtual Vector<int> subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const override;
+ virtual Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
+ virtual void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) override;
+ virtual void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false) override;
- Button *button_create = nullptr;
- Button *button_edit = nullptr;
+ NavigationObstacle3DGizmoPlugin();
+};
+
+class NavigationObstacle3DEditorPlugin : public EditorPlugin {
+ GDCLASS(NavigationObstacle3DEditorPlugin, EditorPlugin);
+
+ Ref<NavigationObstacle3DGizmoPlugin> obstacle_3d_gizmo_plugin;
+
+ NavigationObstacle3D *obstacle_node = nullptr;
Ref<StandardMaterial3D> line_material;
Ref<StandardMaterial3D> handle_material;
- Panel *panel = nullptr;
- NavigationObstacle3D *obstacle_node = nullptr;
- Ref<ImmediateMesh> point_lines_mesh;
- MeshInstance3D *point_lines_meshinstance = nullptr;
- MeshInstance3D *point_handles_meshinstance = nullptr;
- Ref<ArrayMesh> point_handle_mesh;
+ RID point_lines_mesh_rid;
+ RID point_lines_instance_rid;
+ RID point_handle_mesh_rid;
+ RID point_handles_instance_rid;
- MenuButton *options = nullptr;
+public:
+ enum Mode {
+ MODE_CREATE = 0,
+ MODE_EDIT,
+ MODE_DELETE,
+ ACTION_FLIP,
+ ACTION_CLEAR,
+ };
- int edited_point = 0;
- Vector2 edited_point_pos;
- PackedVector2Array pre_move_edit;
- PackedVector2Array wip;
- bool wip_active;
- bool snap_ignore;
+private:
+ int mode = MODE_EDIT;
- float prev_depth = 0.0f;
+ int edited_point = 0;
+ Vector3 edited_point_pos;
+ Vector<Vector3> pre_move_edit;
+ Vector<Vector3> wip_vertices;
+ bool wip_active = false;
+ bool snap_ignore = false;
void _wip_close();
- void _polygon_draw();
- void _menu_option(int p_option);
+ void _wip_cancel();
+ void _update_theme();
+
+ Button *button_create = nullptr;
+ Button *button_edit = nullptr;
+ Button *button_delete = nullptr;
+ Button *button_flip = nullptr;
+ Button *button_clear = nullptr;
- PackedVector2Array _get_polygon();
- void _set_polygon(const PackedVector2Array &p_poly);
+ ConfirmationDialog *button_clear_dialog = nullptr;
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
- static void _bind_methods();
public:
- virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
- void edit(Node *p_node);
- NavigationObstacle3DEditor();
- ~NavigationObstacle3DEditor();
-};
+ HBoxContainer *obstacle_editor = nullptr;
+ static NavigationObstacle3DEditorPlugin *singleton;
-class NavigationObstacle3DEditorPlugin : public EditorPlugin {
- GDCLASS(NavigationObstacle3DEditorPlugin, EditorPlugin);
+ void redraw();
- NavigationObstacle3DEditor *obstacle_editor = nullptr;
+ void set_mode(int p_mode);
+ int get_mode() { return mode; }
-public:
- virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return obstacle_editor->forward_3d_gui_input(p_camera, p_event); }
+ void action_flip_vertices();
+ void action_clear_vertices();
+
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
- virtual String get_name() const override { return "NavigationObstacle3DEditor"; }
+ virtual String get_name() const override { return "NavigationObstacle3D"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index ec59bbb543..c11a7cf20e 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -38,8 +38,8 @@
Ref<NavigationPolygon> NavigationPolygonEditor::_ensure_navpoly() const {
Ref<NavigationPolygon> navpoly = node->get_navigation_polygon();
- if (!navpoly.is_valid()) {
- navpoly = Ref<NavigationPolygon>(memnew(NavigationPolygon));
+ if (navpoly.is_null()) {
+ navpoly.instantiate();
node->set_navigation_polygon(navpoly);
}
return navpoly;
@@ -177,8 +177,8 @@ NavigationPolygonEditor::NavigationPolygonEditor() {
void NavigationPolygonEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- button_bake->set_icon(get_editor_theme_icon(SNAME("Bake")));
- button_reset->set_icon(get_editor_theme_icon(SNAME("Reload")));
+ button_bake->set_button_icon(get_editor_theme_icon(SNAME("Bake")));
+ button_reset->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
if (rebake_timer) {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 0df0274495..810d1674ca 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1692,7 +1692,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
- emit_signal(SNAME("clicked"), this);
+ emit_signal(SNAME("clicked"));
ViewportNavMouseButton orbit_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/orbit_mouse_button").operator int();
ViewportNavMouseButton pan_mouse_preference = (ViewportNavMouseButton)EDITOR_GET("editors/3d/navigation/pan_mouse_button").operator int();
@@ -3139,8 +3139,8 @@ void Node3DEditorViewport::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- view_menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
- preview_camera->set_icon(get_editor_theme_icon(SNAME("Camera3D")));
+ view_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ preview_camera->set_button_icon(get_editor_theme_icon(SNAME("Camera3D")));
Control *gui_base = EditorNode::get_singleton()->get_gui_base();
const Ref<StyleBox> &information_3d_stylebox = gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles));
@@ -4210,7 +4210,7 @@ Dictionary Node3DEditorViewport::get_state() const {
void Node3DEditorViewport::_bind_methods() {
ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
- ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
+ ADD_SIGNAL(MethodInfo("clicked"));
}
void Node3DEditorViewport::reset() {
@@ -6572,18 +6572,6 @@ void Node3DEditor::_menu_item_toggled(bool pressed, int p_option) {
tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed);
snap_enabled = pressed;
} break;
-
- case MENU_TOOL_OVERRIDE_CAMERA: {
- EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
-
- using Override = EditorDebuggerNode::CameraOverride;
- if (pressed) {
- debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
- } else {
- debugger->set_camera_override(Override::OVERRIDE_NONE);
- }
-
- } break;
}
}
@@ -6610,36 +6598,6 @@ void Node3DEditor::_menu_gizmo_toggled(int p_option) {
update_all_gizmos();
}
-void Node3DEditor::_update_camera_override_button(bool p_game_running) {
- Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA];
-
- if (p_game_running) {
- button->set_disabled(false);
- button->set_tooltip_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_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
- }
-}
-
-void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) {
- Node3DEditorViewport *current_viewport = Object::cast_to<Node3DEditorViewport>(p_viewport);
-
- if (!current_viewport) {
- return;
- }
-
- EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton();
-
- camera_override_viewport_id = current_viewport->index;
- if (debugger->get_camera_override() >= EditorDebuggerNode::OVERRIDE_3D_1) {
- using Override = EditorDebuggerNode::CameraOverride;
-
- debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
- }
-}
-
void Node3DEditor::_menu_item_pressed(int p_option) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
@@ -6670,6 +6628,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
} break;
case MENU_VIEW_USE_1_VIEWPORT: {
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_1_VIEWPORT);
+ if (last_used_viewport > 0) {
+ last_used_viewport = 0;
+ }
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
@@ -6681,6 +6642,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
} break;
case MENU_VIEW_USE_2_VIEWPORTS: {
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS);
+ if (last_used_viewport > 1) {
+ last_used_viewport = 0;
+ }
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true);
@@ -6692,6 +6656,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
} break;
case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS_ALT);
+ if (last_used_viewport > 1) {
+ last_used_viewport = 0;
+ }
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
@@ -6703,6 +6670,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
} break;
case MENU_VIEW_USE_3_VIEWPORTS: {
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS);
+ if (last_used_viewport > 2) {
+ last_used_viewport = 0;
+ }
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
@@ -6714,6 +6684,9 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
} break;
case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS_ALT);
+ if (last_used_viewport > 2) {
+ last_used_viewport = 0;
+ }
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
@@ -7077,12 +7050,12 @@ void fragment() {
col.a = EDITOR_GET("editors/3d/manipulator_gizmo_opacity");
- move_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
- axis_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
+ move_gizmo[i].instantiate();
+ move_plane_gizmo[i].instantiate();
+ rotate_gizmo[i].instantiate();
+ scale_gizmo[i].instantiate();
+ scale_plane_gizmo[i].instantiate();
+ axis_gizmo[i].instantiate();
Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@@ -7313,7 +7286,7 @@ void fragment() {
border_mat->set_shader(border_shader);
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].instantiate();
rotate_gizmo[3]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
rotate_gizmo[3]->surface_set_material(0, border_mat);
}
@@ -8021,19 +7994,18 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
}
void Node3DEditor::_update_theme() {
- tool_button[TOOL_MODE_SELECT]->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
- tool_button[TOOL_MODE_MOVE]->set_icon(get_editor_theme_icon(SNAME("ToolMove")));
- tool_button[TOOL_MODE_ROTATE]->set_icon(get_editor_theme_icon(SNAME("ToolRotate")));
- tool_button[TOOL_MODE_SCALE]->set_icon(get_editor_theme_icon(SNAME("ToolScale")));
- tool_button[TOOL_MODE_LIST_SELECT]->set_icon(get_editor_theme_icon(SNAME("ListSelect")));
- tool_button[TOOL_LOCK_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Lock")));
- tool_button[TOOL_UNLOCK_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Unlock")));
- tool_button[TOOL_GROUP_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Group")));
- tool_button[TOOL_UNGROUP_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Ungroup")));
-
- tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_icon(get_editor_theme_icon(SNAME("Object")));
- tool_option_button[TOOL_OPT_USE_SNAP]->set_icon(get_editor_theme_icon(SNAME("Snap")));
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_editor_theme_icon(SNAME("Camera3D")));
+ tool_button[TOOL_MODE_SELECT]->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
+ tool_button[TOOL_MODE_MOVE]->set_button_icon(get_editor_theme_icon(SNAME("ToolMove")));
+ tool_button[TOOL_MODE_ROTATE]->set_button_icon(get_editor_theme_icon(SNAME("ToolRotate")));
+ tool_button[TOOL_MODE_SCALE]->set_button_icon(get_editor_theme_icon(SNAME("ToolScale")));
+ tool_button[TOOL_MODE_LIST_SELECT]->set_button_icon(get_editor_theme_icon(SNAME("ListSelect")));
+ tool_button[TOOL_LOCK_SELECTED]->set_button_icon(get_editor_theme_icon(SNAME("Lock")));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_button_icon(get_editor_theme_icon(SNAME("Unlock")));
+ tool_button[TOOL_GROUP_SELECTED]->set_button_icon(get_editor_theme_icon(SNAME("Group")));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_button_icon(get_editor_theme_icon(SNAME("Ungroup")));
+
+ tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_button_icon(get_editor_theme_icon(SNAME("Object")));
+ tool_option_button[TOOL_OPT_USE_SNAP]->set_button_icon(get_editor_theme_icon(SNAME("Snap")));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_editor_theme_icon(SNAME("Panels1")));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_editor_theme_icon(SNAME("Panels2")));
@@ -8042,9 +8014,9 @@ void Node3DEditor::_update_theme() {
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_editor_theme_icon(SNAME("Panels3Alt")));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_editor_theme_icon(SNAME("Panels4")));
- sun_button->set_icon(get_editor_theme_icon(SNAME("PreviewSun")));
- environ_button->set_icon(get_editor_theme_icon(SNAME("PreviewEnvironment")));
- sun_environ_settings->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ sun_button->set_button_icon(get_editor_theme_icon(SNAME("PreviewSun")));
+ environ_button->set_button_icon(get_editor_theme_icon(SNAME("PreviewEnvironment")));
+ sun_environ_settings->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
sun_title->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("title_font"), SNAME("Window")));
environ_title->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("title_font"), SNAME("Window")));
@@ -8068,9 +8040,6 @@ void Node3DEditor::_notification(int p_what) {
SceneTreeDock::get_singleton()->get_tree_editor()->connect("node_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons));
editor_selection->connect("selection_changed", callable_mp(this, &Node3DEditor::_selection_changed));
- EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button).bind(false));
- EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button).bind(true));
-
_update_preview_environment();
sun_state->set_custom_minimum_size(sun_vb->get_combined_minimum_size());
@@ -8106,15 +8075,6 @@ void Node3DEditor::_notification(int p_what) {
}
} break;
- case NOTIFICATION_VISIBILITY_CHANGED: {
- if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
- EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
-
- debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
- }
- } break;
-
case NOTIFICATION_PHYSICS_PROCESS: {
if (do_snap_selected_nodes_to_floor) {
_snap_selected_nodes_to_floor();
@@ -8216,6 +8176,10 @@ VSplitContainer *Node3DEditor::get_shader_split() {
return shader_split;
}
+Node3DEditorViewport *Node3DEditor::get_last_used_viewport() {
+ return viewports[last_used_viewport];
+}
+
void Node3DEditor::add_control_to_left_panel(Control *p_control) {
left_panel_split->add_child(p_control);
left_panel_split->move_child(p_control, 0);
@@ -8393,6 +8357,10 @@ void Node3DEditor::_toggle_maximize_view(Object *p_viewport) {
}
}
+void Node3DEditor::_viewport_clicked(int p_viewport_idx) {
+ last_used_viewport = p_viewport_idx;
+}
+
void Node3DEditor::_node_added(Node *p_node) {
if (EditorNode::get_singleton()->get_scene_root()->is_ancestor_of(p_node)) {
if (Object::cast_to<WorldEnvironment>(p_node)) {
@@ -8512,7 +8480,7 @@ void Node3DEditor::clear() {
}
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
- viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(Node3DEditorViewport::VIEW_AUDIO_LISTENER), i == 0);
+ viewports[i]->view_menu->get_popup()->set_item_checked(viewports[i]->view_menu->get_popup()->get_item_index(Node3DEditorViewport::VIEW_AUDIO_LISTENER), i == 0);
viewports[i]->viewport->set_as_audio_listener_3d(i == 0);
}
@@ -8671,7 +8639,7 @@ Node3DEditor::Node3DEditor() {
gizmo.visible = true;
gizmo.scale = 1.0;
- viewport_environment = Ref<Environment>(memnew(Environment));
+ viewport_environment.instantiate();
VBoxContainer *vbc = this;
custom_camera = nullptr;
@@ -8684,8 +8652,6 @@ Node3DEditor::Node3DEditor() {
snap_key_enabled = false;
tool_mode = TOOL_MODE_SELECT;
- camera_override_viewport_id = 0;
-
// Add some margin to the sides for better aesthetics.
// This prevents the first button's hover/pressed effect from "touching" the panel's border,
// which looks ugly.
@@ -8803,16 +8769,6 @@ Node3DEditor::Node3DEditor() {
tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut_context(this);
main_menu_hbox->add_child(memnew(VSeparator));
-
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(Button);
- main_menu_hbox->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_theme_type_variation("FlatButton");
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
- tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect(SceneStringName(toggled), callable_mp(this, &Node3DEditor::_menu_item_toggled).bind(MENU_TOOL_OVERRIDE_CAMERA));
- _update_camera_override_button(false);
-
- main_menu_hbox->add_child(memnew(VSeparator));
sun_button = memnew(Button);
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);
@@ -8955,7 +8911,7 @@ Node3DEditor::Node3DEditor() {
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
viewports[i] = memnew(Node3DEditorViewport(this, i));
viewports[i]->connect("toggle_maximize_view", callable_mp(this, &Node3DEditor::_toggle_maximize_view));
- viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_update_camera_override_viewport));
+ viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_viewport_clicked).bind(i));
viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
viewport_base->add_child(viewports[i]);
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 1b03362606..d35fcb7653 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -622,7 +622,6 @@ public:
enum ToolOptions {
TOOL_OPT_LOCAL_COORDS,
TOOL_OPT_USE_SNAP,
- TOOL_OPT_OVERRIDE_CAMERA,
TOOL_OPT_MAX
};
@@ -632,6 +631,8 @@ private:
Node3DEditorViewportContainer *viewport_base = nullptr;
Node3DEditorViewport *viewports[VIEWPORTS_COUNT];
+ int last_used_viewport = 0;
+
VSplitContainer *shader_split = nullptr;
HSplitContainer *left_panel_split = nullptr;
HSplitContainer *right_panel_split = nullptr;
@@ -704,7 +705,6 @@ private:
MENU_TOOL_LIST_SELECT,
MENU_TOOL_LOCAL_COORDS,
MENU_TOOL_USE_SNAP,
- MENU_TOOL_OVERRIDE_CAMERA,
MENU_TRANSFORM_CONFIGURE_SNAP,
MENU_TRANSFORM_DIALOG,
MENU_VIEW_USE_1_VIEWPORT,
@@ -759,8 +759,6 @@ private:
void _menu_item_pressed(int p_option);
void _menu_item_toggled(bool pressed, int p_option);
void _menu_gizmo_toggled(int p_option);
- void _update_camera_override_button(bool p_game_running);
- void _update_camera_override_viewport(Object *p_viewport);
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
PanelContainer *context_toolbar_panel = nullptr;
@@ -771,8 +769,6 @@ private:
void _generate_selection_boxes();
- int camera_override_viewport_id;
-
void _init_indicators();
void _update_gizmos_menu();
void _update_gizmos_menu_theme();
@@ -781,6 +777,7 @@ private:
void _finish_grid();
void _toggle_maximize_view(Object *p_viewport);
+ void _viewport_clicked(int p_viewport_idx);
Node *custom_camera = nullptr;
@@ -967,6 +964,7 @@ public:
ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), nullptr);
return viewports[p_idx];
}
+ Node3DEditorViewport *get_last_used_viewport();
void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
index c14d9e02aa..b9c884178f 100644
--- a/editor/plugins/occluder_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
@@ -105,7 +105,7 @@ void OccluderInstance3DEditorPlugin::_bind_methods() {
OccluderInstance3DEditorPlugin::OccluderInstance3DEditorPlugin() {
bake = memnew(Button);
bake->set_theme_type_variation("FlatButton");
- bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
+ bake->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake Occluders"));
bake->hide();
bake->connect(SceneStringName(pressed), Callable(this, "_bake"));
diff --git a/editor/plugins/packed_scene_editor_plugin.cpp b/editor/plugins/packed_scene_editor_plugin.cpp
index c2d9851c17..4684c5a456 100644
--- a/editor/plugins/packed_scene_editor_plugin.cpp
+++ b/editor/plugins/packed_scene_editor_plugin.cpp
@@ -43,7 +43,7 @@ void PackedSceneEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- open_scene_button->set_icon(get_editor_theme_icon(SNAME("PackedScene")));
+ open_scene_button->set_button_icon(get_editor_theme_icon(SNAME("PackedScene")));
} break;
}
}
diff --git a/editor/plugins/parallax_background_editor_plugin.cpp b/editor/plugins/parallax_background_editor_plugin.cpp
index 6c55fd2753..e802f42596 100644
--- a/editor/plugins/parallax_background_editor_plugin.cpp
+++ b/editor/plugins/parallax_background_editor_plugin.cpp
@@ -119,7 +119,7 @@ void ParallaxBackgroundEditorPlugin::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &ParallaxBackgroundEditorPlugin::_menu_callback));
- menu->set_icon(menu->get_editor_theme_icon(SNAME("ParallaxBackground")));
+ menu->set_button_icon(menu->get_editor_theme_icon(SNAME("ParallaxBackground")));
} break;
}
}
diff --git a/editor/plugins/particle_process_material_editor_plugin.cpp b/editor/plugins/particle_process_material_editor_plugin.cpp
index 67c9403aaf..7b46653ac7 100644
--- a/editor/plugins/particle_process_material_editor_plugin.cpp
+++ b/editor/plugins/particle_process_material_editor_plugin.cpp
@@ -346,7 +346,7 @@ float ParticleProcessMaterialMinMaxPropertyEditor::_get_max_spread() const {
void ParticleProcessMaterialMinMaxPropertyEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- toggle_mode_button->set_icon(get_editor_theme_icon(SNAME("Anchor")));
+ toggle_mode_button->set_button_icon(get_editor_theme_icon(SNAME("Anchor")));
range_slider_left_icon = get_editor_theme_icon(SNAME("RangeSliderLeft"));
range_slider_right_icon = get_editor_theme_icon(SNAME("RangeSliderRight"));
diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp
index 34f5dcf963..36a2d7acad 100644
--- a/editor/plugins/particles_editor_plugin.cpp
+++ b/editor/plugins/particles_editor_plugin.cpp
@@ -60,7 +60,7 @@ void ParticlesEditorPlugin::_notification(int p_what) {
DEV_ASSERT(false);
}
- menu->set_icon(menu->get_editor_theme_icon(handled_type));
+ menu->set_button_icon(menu->get_editor_theme_icon(handled_type));
menu->set_text(handled_type);
PopupMenu *popup = menu->get_popup();
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index c96f23869e..96e022e230 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -43,14 +43,14 @@
void Path2DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- curve_edit->set_icon(get_editor_theme_icon(SNAME("CurveEdit")));
- curve_edit_curve->set_icon(get_editor_theme_icon(SNAME("CurveCurve")));
- curve_create->set_icon(get_editor_theme_icon(SNAME("CurveCreate")));
- curve_del->set_icon(get_editor_theme_icon(SNAME("CurveDelete")));
- curve_close->set_icon(get_editor_theme_icon(SNAME("CurveClose")));
- curve_clear_points->set_icon(get_editor_theme_icon(SNAME("Clear")));
-
- create_curve_button->set_icon(get_editor_theme_icon(SNAME("Curve2D")));
+ curve_edit->set_button_icon(get_editor_theme_icon(SNAME("CurveEdit")));
+ curve_edit_curve->set_button_icon(get_editor_theme_icon(SNAME("CurveCurve")));
+ curve_create->set_button_icon(get_editor_theme_icon(SNAME("CurveCreate")));
+ curve_del->set_button_icon(get_editor_theme_icon(SNAME("CurveDelete")));
+ curve_close->set_button_icon(get_editor_theme_icon(SNAME("CurveClose")));
+ curve_clear_points->set_button_icon(get_editor_theme_icon(SNAME("Clear")));
+
+ create_curve_button->set_button_icon(get_editor_theme_icon(SNAME("Curve2D")));
} break;
}
}
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 4fdcb79696..3a4b3a0ea2 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -790,14 +790,14 @@ void Path3DEditorPlugin::_restore_curve_points(const PackedVector3Array &p_point
}
void Path3DEditorPlugin::_update_theme() {
- curve_edit->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveEdit")));
- curve_edit_curve->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCurve")));
- curve_edit_tilt->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveTilt")));
- curve_create->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCreate")));
- curve_del->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveDelete")));
- curve_close->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveClose")));
- curve_clear_points->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("Clear")));
- create_curve_button->set_icon(topmenu_bar->get_editor_theme_icon(SNAME("Curve3D")));
+ curve_edit->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveEdit")));
+ curve_edit_curve->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCurve")));
+ curve_edit_tilt->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveTilt")));
+ curve_create->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCreate")));
+ curve_del->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveDelete")));
+ curve_close->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveClose")));
+ curve_clear_points->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("Clear")));
+ create_curve_button->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("Curve3D")));
}
void Path3DEditorPlugin::_update_toolbar() {
@@ -922,7 +922,7 @@ Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {
Path3D *path = Object::cast_to<Path3D>(p_spatial);
if (path) {
- ref = Ref<Path3DGizmo>(memnew(Path3DGizmo(path, disk_size)));
+ ref.instantiate(path, disk_size);
}
return ref;
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp
index c858fa8606..15a957d5c4 100644
--- a/editor/plugins/physical_bone_3d_editor_plugin.cpp
+++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp
@@ -60,7 +60,7 @@ PhysicalBone3DEditor::PhysicalBone3DEditor() {
button_transform_joint->set_text(TTR("Move Joint"));
// TODO: Rework this as a dedicated toolbar control so we can hook into theme changes and update it
// when the editor theme updates.
- button_transform_joint->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("PhysicalBone3D"), EditorStringName(EditorIcons)));
+ button_transform_joint->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("PhysicalBone3D"), EditorStringName(EditorIcons)));
button_transform_joint->set_toggle_mode(true);
button_transform_joint->connect(SceneStringName(toggled), callable_mp(this, &PhysicalBone3DEditor::_on_toggle_button_transform_joint));
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 842142db79..8ab08ff28f 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -111,22 +111,22 @@ void Polygon2DEditor::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- button_uv->set_icon(get_editor_theme_icon(SNAME("Uv")));
-
- uv_button[UV_MODE_CREATE]->set_icon(get_editor_theme_icon(SNAME("Edit")));
- uv_button[UV_MODE_CREATE_INTERNAL]->set_icon(get_editor_theme_icon(SNAME("EditInternal")));
- uv_button[UV_MODE_REMOVE_INTERNAL]->set_icon(get_editor_theme_icon(SNAME("RemoveInternal")));
- uv_button[UV_MODE_EDIT_POINT]->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
- uv_button[UV_MODE_MOVE]->set_icon(get_editor_theme_icon(SNAME("ToolMove")));
- uv_button[UV_MODE_ROTATE]->set_icon(get_editor_theme_icon(SNAME("ToolRotate")));
- uv_button[UV_MODE_SCALE]->set_icon(get_editor_theme_icon(SNAME("ToolScale")));
- uv_button[UV_MODE_ADD_POLYGON]->set_icon(get_editor_theme_icon(SNAME("Edit")));
- uv_button[UV_MODE_REMOVE_POLYGON]->set_icon(get_editor_theme_icon(SNAME("Close")));
- uv_button[UV_MODE_PAINT_WEIGHT]->set_icon(get_editor_theme_icon(SNAME("Bucket")));
- uv_button[UV_MODE_CLEAR_WEIGHT]->set_icon(get_editor_theme_icon(SNAME("Clear")));
-
- b_snap_grid->set_icon(get_editor_theme_icon(SNAME("Grid")));
- b_snap_enable->set_icon(get_editor_theme_icon(SNAME("SnapGrid")));
+ button_uv->set_button_icon(get_editor_theme_icon(SNAME("Uv")));
+
+ uv_button[UV_MODE_CREATE]->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
+ uv_button[UV_MODE_CREATE_INTERNAL]->set_button_icon(get_editor_theme_icon(SNAME("EditInternal")));
+ uv_button[UV_MODE_REMOVE_INTERNAL]->set_button_icon(get_editor_theme_icon(SNAME("RemoveInternal")));
+ uv_button[UV_MODE_EDIT_POINT]->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
+ uv_button[UV_MODE_MOVE]->set_button_icon(get_editor_theme_icon(SNAME("ToolMove")));
+ uv_button[UV_MODE_ROTATE]->set_button_icon(get_editor_theme_icon(SNAME("ToolRotate")));
+ uv_button[UV_MODE_SCALE]->set_button_icon(get_editor_theme_icon(SNAME("ToolScale")));
+ uv_button[UV_MODE_ADD_POLYGON]->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
+ uv_button[UV_MODE_REMOVE_POLYGON]->set_button_icon(get_editor_theme_icon(SNAME("Close")));
+ uv_button[UV_MODE_PAINT_WEIGHT]->set_button_icon(get_editor_theme_icon(SNAME("Bucket")));
+ uv_button[UV_MODE_CLEAR_WEIGHT]->set_button_icon(get_editor_theme_icon(SNAME("Clear")));
+
+ b_snap_grid->set_button_icon(get_editor_theme_icon(SNAME("Grid")));
+ b_snap_enable->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
uv_vscroll->set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
uv_hscroll->set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
@@ -275,7 +275,11 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
uv_button[UV_MODE_REMOVE_POLYGON]->hide();
uv_button[UV_MODE_PAINT_WEIGHT]->hide();
uv_button[UV_MODE_CLEAR_WEIGHT]->hide();
- _uv_mode(UV_MODE_EDIT_POINT);
+ if (node->get_polygon().is_empty()) {
+ _uv_mode(UV_MODE_CREATE);
+ } else {
+ _uv_mode(UV_MODE_EDIT_POINT);
+ }
bone_scroll_main_vb->hide();
bone_paint_strength->hide();
@@ -317,9 +321,16 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
uv_edit_draw->queue_redraw();
}
+void Polygon2DEditor::_uv_edit_popup_show() {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->connect("version_changed", callable_mp(this, &Polygon2DEditor::_update_available_modes));
+}
+
void Polygon2DEditor::_uv_edit_popup_hide() {
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "uv_editor", Rect2(uv_edit->get_position(), uv_edit->get_size()));
_cancel_editing();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->disconnect("version_changed", callable_mp(this, &Polygon2DEditor::_update_available_modes));
}
void Polygon2DEditor::_menu_option(int p_option) {
@@ -346,6 +357,7 @@ void Polygon2DEditor::_menu_option(int p_option) {
uv_edit->popup_centered_ratio(0.85);
}
_update_bone_list();
+ _update_available_modes();
get_tree()->connect("process_frame", callable_mp(this, &Polygon2DEditor::_center_view), CONNECT_ONE_SHOT);
} break;
case UVEDIT_POLYGON_TO_UV: {
@@ -408,6 +420,7 @@ void Polygon2DEditor::_cancel_editing() {
node->set_polygons(polygons_prev);
_update_polygon_editing_state();
+ _update_available_modes();
} else if (uv_drag) {
uv_drag = false;
if (uv_edit_mode[0]->is_pressed()) { // Edit UV.
@@ -566,6 +579,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_drag = false;
uv_create = false;
+ _update_available_modes();
_uv_mode(UV_MODE_EDIT_POINT);
_menu_option(MODE_EDIT);
} else {
@@ -973,6 +987,23 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
}
+void Polygon2DEditor::_update_available_modes() {
+ // Force point editing mode if there's no polygon yet.
+ if (node->get_polygon().is_empty()) {
+ if (!uv_edit_mode[1]->is_pressed()) {
+ uv_edit_mode[1]->set_pressed(true);
+ _uv_edit_mode_select(1);
+ }
+ uv_edit_mode[0]->set_disabled(true);
+ uv_edit_mode[2]->set_disabled(true);
+ uv_edit_mode[3]->set_disabled(true);
+ } else {
+ uv_edit_mode[0]->set_disabled(false);
+ uv_edit_mode[2]->set_disabled(false);
+ uv_edit_mode[3]->set_disabled(false);
+ }
+}
+
void Polygon2DEditor::_center_view() {
Size2 texture_size;
if (node->get_texture().is_valid()) {
@@ -1324,6 +1355,7 @@ Polygon2DEditor::Polygon2DEditor() {
add_child(uv_edit);
uv_edit->connect(SceneStringName(confirmed), callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
uv_edit->connect("canceled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
+ uv_edit->connect("about_to_popup", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_show));
VBoxContainer *uv_main_vb = memnew(VBoxContainer);
uv_edit->add_child(uv_main_vb);
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index 164aa3eccc..4e1cd7172e 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -142,6 +142,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
void _cancel_editing();
void _update_polygon_editing_state();
+ void _update_available_modes();
void _center_view();
void _update_zoom_and_pan(bool p_zoom_at_center);
@@ -157,6 +158,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
void _set_snap_step_y(real_t p_val);
void _uv_edit_mode_select(int p_mode);
+ void _uv_edit_popup_show();
void _uv_edit_popup_hide();
void _bone_paint_selected(int p_index);
@@ -168,7 +170,7 @@ protected:
virtual Vector2 _get_offset(int p_idx) const override;
- virtual bool _has_uv() const override { return true; };
+ virtual bool _has_uv() const override { return true; }
virtual void _commit_action() override;
void _notification(int p_what);
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 56baa4a839..017504f0d6 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -46,8 +46,8 @@
void Polygon3DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- button_create->set_icon(get_editor_theme_icon(SNAME("Edit")));
- button_edit->set_icon(get_editor_theme_icon(SNAME("MovePoint")));
+ button_create->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
+ button_edit->set_button_icon(get_editor_theme_icon(SNAME("MovePoint")));
button_edit->set_pressed(true);
get_tree()->connect("node_removed", callable_mp(this, &Polygon3DEditor::_node_removed));
@@ -554,7 +554,7 @@ Polygon3DEditor::Polygon3DEditor() {
imgeom->set_mesh(imesh);
imgeom->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
- line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+ line_material.instantiate();
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
@@ -562,7 +562,7 @@ Polygon3DEditor::Polygon3DEditor() {
line_material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
line_material->set_albedo(Color(1, 1, 1));
- handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+ handle_material.instantiate();
handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index ba6699fcc4..bb0607a3c6 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -45,7 +45,7 @@ void ResourcePreloaderEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- load->set_icon(get_editor_theme_icon(SNAME("Folder")));
+ load->set_button_icon(get_editor_theme_icon(SNAME("Folder")));
} break;
}
}
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index cd422fc291..0a4e3d78c8 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -169,13 +169,13 @@ void EditorPropertyRootMotion::update_property() {
NodePath p = get_edited_property_value();
assign->set_tooltip_text(p);
if (p == NodePath()) {
- assign->set_icon(Ref<Texture2D>());
+ assign->set_button_icon(Ref<Texture2D>());
assign->set_text(TTR("Assign..."));
assign->set_flat(false);
return;
}
- assign->set_icon(Ref<Texture2D>());
+ assign->set_button_icon(Ref<Texture2D>());
assign->set_text(p);
}
@@ -188,7 +188,7 @@ void EditorPropertyRootMotion::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
Ref<Texture2D> t = get_editor_theme_icon(SNAME("Clear"));
- clear->set_icon(t);
+ clear->set_button_icon(t);
} break;
}
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 7e0331d15c..8c3979918d 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -261,6 +261,52 @@ Ref<EditorSyntaxHighlighter> EditorJSONSyntaxHighlighter::_create() const {
return syntax_highlighter;
}
+////
+
+void EditorMarkdownSyntaxHighlighter::_update_cache() {
+ highlighter->set_text_edit(text_edit);
+ highlighter->clear_keyword_colors();
+ highlighter->clear_member_keyword_colors();
+ highlighter->clear_color_regions();
+
+ // Disable automatic symbolic highlights, as these don't make sense for prose.
+ highlighter->set_symbol_color(EDITOR_GET("text_editor/theme/highlighting/text_color"));
+ highlighter->set_number_color(EDITOR_GET("text_editor/theme/highlighting/text_color"));
+ highlighter->set_member_variable_color(EDITOR_GET("text_editor/theme/highlighting/text_color"));
+ highlighter->set_function_color(EDITOR_GET("text_editor/theme/highlighting/text_color"));
+
+ // Headings (any level).
+ const Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");
+ highlighter->add_color_region("#", "", function_color);
+
+ // Bold.
+ highlighter->add_color_region("**", "**", function_color);
+ // `__bold__` syntax is not supported as color regions must begin with a symbol,
+ // not a character that is valid in an identifier.
+
+ // Code (both inline code and triple-backticks code blocks).
+ const Color code_color = EDITOR_GET("text_editor/theme/highlighting/engine_type_color");
+ highlighter->add_color_region("`", "`", code_color);
+
+ // Link (both references and inline links with URLs). The URL is not highlighted.
+ const Color link_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
+ highlighter->add_color_region("[", "]", link_color);
+
+ // Quote.
+ const Color quote_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
+ highlighter->add_color_region(">", "", quote_color, true);
+
+ // HTML comment, which is also supported in Markdown.
+ const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
+ highlighter->add_color_region("<!--", "-->", comment_color);
+}
+
+Ref<EditorSyntaxHighlighter> EditorMarkdownSyntaxHighlighter::_create() const {
+ Ref<EditorMarkdownSyntaxHighlighter> syntax_highlighter;
+ syntax_highlighter.instantiate();
+ return syntax_highlighter;
+}
+
////////////////////////////////////////////////////////////////////////////////
/*** SCRIPT EDITOR ****/
@@ -1734,18 +1780,18 @@ void ScriptEditor::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
tab_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("ScriptEditor"), EditorStringName(EditorStyles)));
- help_search->set_icon(get_editor_theme_icon(SNAME("HelpSearch")));
- site_search->set_icon(get_editor_theme_icon(SNAME("ExternalLink")));
+ help_search->set_button_icon(get_editor_theme_icon(SNAME("HelpSearch")));
+ site_search->set_button_icon(get_editor_theme_icon(SNAME("ExternalLink")));
if (is_layout_rtl()) {
- script_forward->set_icon(get_editor_theme_icon(SNAME("Back")));
- script_back->set_icon(get_editor_theme_icon(SNAME("Forward")));
+ script_forward->set_button_icon(get_editor_theme_icon(SNAME("Back")));
+ script_back->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
} else {
- script_forward->set_icon(get_editor_theme_icon(SNAME("Forward")));
- script_back->set_icon(get_editor_theme_icon(SNAME("Back")));
+ script_forward->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
+ script_back->set_button_icon(get_editor_theme_icon(SNAME("Back")));
}
- members_overview_alphabeta_sort_button->set_icon(get_editor_theme_icon(SNAME("Sort")));
+ members_overview_alphabeta_sort_button->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
filter_scripts->set_right_icon(get_editor_theme_icon(SNAME("Search")));
filter_methods->set_right_icon(get_editor_theme_icon(SNAME("Search")));
@@ -2139,8 +2185,6 @@ void ScriptEditor::_update_script_colors() {
continue;
}
- script_list->set_item_custom_bg_color(i, Color(0, 0, 0, 0));
-
if (script_temperature_enabled) {
int pass = n->get_meta("__editor_pass", -1);
if (pass < 0) {
@@ -2166,7 +2210,7 @@ void ScriptEditor::_update_script_names() {
HashSet<Ref<Script>> used;
Node *edited = EditorNode::get_singleton()->get_edited_scene();
- if (edited) {
+ if (edited && EDITOR_GET("text_editor/script_list/highlight_scene_scripts")) {
_find_scripts(edited, edited, used);
}
@@ -2336,7 +2380,7 @@ void ScriptEditor::_update_script_names() {
script_list->set_item_tooltip(index, sedata_filtered[i].tooltip);
script_list->set_item_metadata(index, sedata_filtered[i].index); /* Saving as metadata the script's index in the tab container and not the filtered one */
if (sedata_filtered[i].used) {
- script_list->set_item_custom_bg_color(index, Color(88 / 255.0, 88 / 255.0, 60 / 255.0));
+ script_list->set_item_custom_bg_color(index, Color(.5, .5, .5, .125));
}
if (tab_container->get_current_tab() == sedata_filtered[i].index) {
script_list->select(index);
@@ -4414,6 +4458,10 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
json_syntax_highlighter.instantiate();
register_syntax_highlighter(json_syntax_highlighter);
+ Ref<EditorMarkdownSyntaxHighlighter> markdown_syntax_highlighter;
+ markdown_syntax_highlighter.instantiate();
+ register_syntax_highlighter(markdown_syntax_highlighter);
+
_update_online_doc();
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 8e82d60605..5de0aaa1e9 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -120,6 +120,24 @@ public:
EditorJSONSyntaxHighlighter() { highlighter.instantiate(); }
};
+class EditorMarkdownSyntaxHighlighter : public EditorSyntaxHighlighter {
+ GDCLASS(EditorMarkdownSyntaxHighlighter, EditorSyntaxHighlighter)
+
+private:
+ Ref<CodeHighlighter> highlighter;
+
+public:
+ virtual void _update_cache() override;
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override { return highlighter->get_line_syntax_highlighting(p_line); }
+
+ virtual PackedStringArray _get_supported_languages() const override { return PackedStringArray{ "md", "markdown" }; }
+ virtual String _get_name() const override { return TTR("Markdown"); }
+
+ virtual Ref<EditorSyntaxHighlighter> _create() const override;
+
+ EditorMarkdownSyntaxHighlighter() { highlighter.instantiate(); }
+};
+
///////////////////////////////////////////////////////////////////////////////
class ScriptEditorQuickOpen : public ConfirmationDialog {
diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp
index d732d51f69..d2fd9b1cc0 100644
--- a/editor/plugins/shader_file_editor_plugin.cpp
+++ b/editor/plugins/shader_file_editor_plugin.cpp
@@ -63,7 +63,7 @@ void ShaderFileEditor::_version_selected(int p_option) {
for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) {
if (bytecode->get_stage_bytecode(RD::ShaderStage(i)).is_empty() && bytecode->get_stage_compile_error(RD::ShaderStage(i)) == String()) {
- stages[i]->set_icon(Ref<Texture2D>());
+ stages[i]->set_button_icon(Ref<Texture2D>());
continue;
}
@@ -73,7 +73,7 @@ void ShaderFileEditor::_version_selected(int p_option) {
} else {
icon = get_editor_theme_icon(SNAME("ImportCheck"));
}
- stages[i]->set_icon(icon);
+ stages[i]->set_button_icon(icon);
if (first_found == -1) {
first_found = i;
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index 8f54641dcb..97ad0ff640 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -96,7 +96,7 @@ Skeleton2DEditor::Skeleton2DEditor() {
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text(TTR("Skeleton2D"));
- options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Skeleton2D"), EditorStringName(EditorIcons)));
+ options->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Skeleton2D"), EditorStringName(EditorIcons)));
options->get_popup()->add_item(TTR("Reset to Rest Pose"), MENU_OPTION_SET_REST);
options->get_popup()->add_separator();
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 81beaf6f91..369a1fc864 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -123,7 +123,7 @@ void BonePropertiesEditor::_notification(int p_what) {
const Color section_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
section->set_bg_color(section_color);
rest_section->set_bg_color(section_color);
- add_metadata_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_metadata_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
}
}
@@ -351,12 +351,12 @@ void Skeleton3DEditor::set_keyable(const bool p_keyable) {
} else {
animation_hb->hide();
}
-};
+}
void Skeleton3DEditor::set_bone_options_enabled(const bool 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);
-};
+}
void Skeleton3DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_all"), &Skeleton3DEditor::update_all);
@@ -1136,13 +1136,13 @@ void Skeleton3DEditor::_notification(int p_what) {
add_theme_constant_override("separation", 0);
} break;
case NOTIFICATION_THEME_CHANGED: {
- skeleton_options->set_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
- edit_mode_button->set_icon(get_editor_theme_icon(SNAME("ToolBoneSelect")));
- key_loc_button->set_icon(get_editor_theme_icon(SNAME("KeyPosition")));
- key_rot_button->set_icon(get_editor_theme_icon(SNAME("KeyRotation")));
- key_scale_button->set_icon(get_editor_theme_icon(SNAME("KeyScale")));
- key_insert_button->set_icon(get_editor_theme_icon(SNAME("Key")));
- key_insert_all_button->set_icon(get_editor_theme_icon(SNAME("NewKey")));
+ skeleton_options->set_button_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
+ edit_mode_button->set_button_icon(get_editor_theme_icon(SNAME("ToolBoneSelect")));
+ key_loc_button->set_button_icon(get_editor_theme_icon(SNAME("KeyPosition")));
+ key_rot_button->set_button_icon(get_editor_theme_icon(SNAME("KeyRotation")));
+ key_scale_button->set_button_icon(get_editor_theme_icon(SNAME("KeyScale")));
+ key_insert_button->set_button_icon(get_editor_theme_icon(SNAME("Key")));
+ key_insert_all_button->set_button_icon(get_editor_theme_icon(SNAME("NewKey")));
bones_section->set_bg_color(get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)));
update_joint_tree();
@@ -1186,8 +1186,8 @@ Skeleton3DEditor::Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, Skel
singleton = this;
// Handle.
- handle_material = Ref<ShaderMaterial>(memnew(ShaderMaterial));
- handle_shader = Ref<Shader>(memnew(Shader));
+ handle_material.instantiate();
+ handle_shader.instantiate();
handle_shader->set_code(R"(
// Skeleton 3D gizmo handle shader.
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 0265183dfa..c6f8c5d357 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -228,14 +228,14 @@ public:
void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx);
- Skeleton3D *get_skeleton() const { return skeleton; };
+ Skeleton3D *get_skeleton() const { return skeleton; }
bool is_edit_mode() const { return edit_mode; }
void update_bone_original();
- Vector3 get_bone_original_position() const { return bone_original_position; };
- Quaternion get_bone_original_rotation() const { return bone_original_rotation; };
- Vector3 get_bone_original_scale() const { return bone_original_scale; };
+ Vector3 get_bone_original_position() const { return bone_original_position; }
+ Quaternion get_bone_original_rotation() const { return bone_original_rotation; }
+ Vector3 get_bone_original_scale() const { return bone_original_scale; }
Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, Skeleton3D *skeleton);
~Skeleton3DEditor();
diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
index 9b98b6ffa2..d0c8744dc2 100644
--- a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
@@ -75,7 +75,7 @@ void SkeletonIK3DEditorPlugin::make_visible(bool p_visible) {
SkeletonIK3DEditorPlugin::SkeletonIK3DEditorPlugin() {
play_btn = memnew(Button);
- play_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Play"), EditorStringName(EditorIcons)));
+ play_btn->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Play"), EditorStringName(EditorIcons)));
play_btn->set_text(TTR("Play IK"));
play_btn->set_toggle_mode(true);
play_btn->hide();
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index c7db243662..c365ad6133 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -560,7 +560,7 @@ void Sprite2DEditor::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- options->set_icon(get_editor_theme_icon(SNAME("Sprite2D")));
+ options->set_button_icon(get_editor_theme_icon(SNAME("Sprite2D")));
options->get_popup()->set_item_icon(MENU_OPTION_CONVERT_TO_MESH_2D, get_editor_theme_icon(SNAME("MeshInstance2D")));
options->get_popup()->set_item_icon(MENU_OPTION_CONVERT_TO_POLYGON_2D, get_editor_theme_icon(SNAME("Polygon2D")));
@@ -593,12 +593,12 @@ Sprite2DEditor::Sprite2DEditor() {
add_child(err_dialog);
debug_uv_dialog = memnew(ConfirmationDialog);
+ debug_uv_dialog->set_size(Size2(960, 540) * EDSCALE);
VBoxContainer *vb = memnew(VBoxContainer);
debug_uv_dialog->add_child(vb);
debug_uv = memnew(Panel);
debug_uv->connect(SceneStringName(gui_input), callable_mp(this, &Sprite2DEditor::_debug_uv_input));
debug_uv->connect(SceneStringName(draw), callable_mp(this, &Sprite2DEditor::_debug_uv_draw));
- debug_uv->set_custom_minimum_size(Size2(800, 500) * EDSCALE);
debug_uv->set_clip_contents(true);
vb->add_margin_child(TTR("Preview:"), debug_uv, true);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 168a3b3ac2..f29ace1d15 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -498,9 +498,9 @@ void SpriteFramesEditor::_toggle_show_settings() {
void SpriteFramesEditor::_update_show_settings() {
if (is_layout_rtl()) {
- toggle_settings_button->set_icon(get_editor_theme_icon(split_sheet_settings_vb->is_visible() ? SNAME("Back") : SNAME("Forward")));
+ toggle_settings_button->set_button_icon(get_editor_theme_icon(split_sheet_settings_vb->is_visible() ? SNAME("Back") : SNAME("Forward")));
} else {
- toggle_settings_button->set_icon(get_editor_theme_icon(split_sheet_settings_vb->is_visible() ? SNAME("Forward") : SNAME("Back")));
+ toggle_settings_button->set_button_icon(get_editor_theme_icon(split_sheet_settings_vb->is_visible() ? SNAME("Forward") : SNAME("Back")));
}
}
@@ -639,32 +639,32 @@ void SpriteFramesEditor::_notification(int p_what) {
pause_icon = get_editor_theme_icon(SNAME("Pause"));
_update_stop_icon();
- autoplay->set_icon(get_editor_theme_icon(SNAME("AutoPlay")));
- anim_loop->set_icon(get_editor_theme_icon(SNAME("Loop")));
- play->set_icon(get_editor_theme_icon(SNAME("PlayStart")));
- play_from->set_icon(get_editor_theme_icon(SNAME("Play")));
- play_bw->set_icon(get_editor_theme_icon(SNAME("PlayStartBackwards")));
- play_bw_from->set_icon(get_editor_theme_icon(SNAME("PlayBackwards")));
-
- load->set_icon(get_editor_theme_icon(SNAME("Load")));
- load_sheet->set_icon(get_editor_theme_icon(SNAME("SpriteSheet")));
- copy->set_icon(get_editor_theme_icon(SNAME("ActionCopy")));
- paste->set_icon(get_editor_theme_icon(SNAME("ActionPaste")));
- empty_before->set_icon(get_editor_theme_icon(SNAME("InsertBefore")));
- empty_after->set_icon(get_editor_theme_icon(SNAME("InsertAfter")));
- move_up->set_icon(get_editor_theme_icon(SNAME("MoveLeft")));
- move_down->set_icon(get_editor_theme_icon(SNAME("MoveRight")));
- delete_frame->set_icon(get_editor_theme_icon(SNAME("Remove")));
- zoom_out->set_icon(get_editor_theme_icon(SNAME("ZoomLess")));
- zoom_reset->set_icon(get_editor_theme_icon(SNAME("ZoomReset")));
- zoom_in->set_icon(get_editor_theme_icon(SNAME("ZoomMore")));
- add_anim->set_icon(get_editor_theme_icon(SNAME("New")));
- duplicate_anim->set_icon(get_editor_theme_icon(SNAME("Duplicate")));
- delete_anim->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ autoplay->set_button_icon(get_editor_theme_icon(SNAME("AutoPlay")));
+ anim_loop->set_button_icon(get_editor_theme_icon(SNAME("Loop")));
+ play->set_button_icon(get_editor_theme_icon(SNAME("PlayStart")));
+ play_from->set_button_icon(get_editor_theme_icon(SNAME("Play")));
+ play_bw->set_button_icon(get_editor_theme_icon(SNAME("PlayStartBackwards")));
+ play_bw_from->set_button_icon(get_editor_theme_icon(SNAME("PlayBackwards")));
+
+ load->set_button_icon(get_editor_theme_icon(SNAME("Load")));
+ load_sheet->set_button_icon(get_editor_theme_icon(SNAME("SpriteSheet")));
+ copy->set_button_icon(get_editor_theme_icon(SNAME("ActionCopy")));
+ paste->set_button_icon(get_editor_theme_icon(SNAME("ActionPaste")));
+ empty_before->set_button_icon(get_editor_theme_icon(SNAME("InsertBefore")));
+ empty_after->set_button_icon(get_editor_theme_icon(SNAME("InsertAfter")));
+ move_up->set_button_icon(get_editor_theme_icon(SNAME("MoveLeft")));
+ move_down->set_button_icon(get_editor_theme_icon(SNAME("MoveRight")));
+ delete_frame->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
+ zoom_out->set_button_icon(get_editor_theme_icon(SNAME("ZoomLess")));
+ zoom_reset->set_button_icon(get_editor_theme_icon(SNAME("ZoomReset")));
+ zoom_in->set_button_icon(get_editor_theme_icon(SNAME("ZoomMore")));
+ add_anim->set_button_icon(get_editor_theme_icon(SNAME("New")));
+ duplicate_anim->set_button_icon(get_editor_theme_icon(SNAME("Duplicate")));
+ delete_anim->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
anim_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- split_sheet_zoom_out->set_icon(get_editor_theme_icon(SNAME("ZoomLess")));
- split_sheet_zoom_reset->set_icon(get_editor_theme_icon(SNAME("ZoomReset")));
- split_sheet_zoom_in->set_icon(get_editor_theme_icon(SNAME("ZoomMore")));
+ split_sheet_zoom_out->set_button_icon(get_editor_theme_icon(SNAME("ZoomLess")));
+ split_sheet_zoom_reset->set_button_icon(get_editor_theme_icon(SNAME("ZoomReset")));
+ split_sheet_zoom_in->set_button_icon(get_editor_theme_icon(SNAME("ZoomMore")));
split_sheet_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
_update_show_settings();
@@ -1740,9 +1740,9 @@ void SpriteFramesEditor::_update_stop_icon() {
is_playing = animated_sprite->call("is_playing");
}
if (is_playing) {
- stop->set_icon(pause_icon);
+ stop->set_button_icon(pause_icon);
} else {
- stop->set_icon(stop_icon);
+ stop->set_button_icon(stop_icon);
}
}
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index 0b53c10fab..2d71c617de 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -58,7 +58,7 @@ void StyleBoxPreview::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
set_texture(get_editor_theme_icon(SNAME("Checkerboard")));
- grid_preview->set_icon(get_editor_theme_icon(SNAME("StyleBoxGrid")));
+ grid_preview->set_button_icon(get_editor_theme_icon(SNAME("StyleBoxGrid")));
} break;
case NOTIFICATION_DRAW: {
_redraw();
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index a812633480..bd653e4eed 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -845,9 +845,9 @@ void TextureRegionEditor::_notification(int p_what) {
texture_preview->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("TextureRegionPreviewBG"), EditorStringName(EditorStyles)));
texture_overlay->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("TextureRegionPreviewFG"), EditorStringName(EditorStyles)));
- zoom_out->set_icon(get_editor_theme_icon(SNAME("ZoomLess")));
- zoom_reset->set_icon(get_editor_theme_icon(SNAME("ZoomReset")));
- zoom_in->set_icon(get_editor_theme_icon(SNAME("ZoomMore")));
+ zoom_out->set_button_icon(get_editor_theme_icon(SNAME("ZoomLess")));
+ zoom_reset->set_button_icon(get_editor_theme_icon(SNAME("ZoomReset")));
+ zoom_in->set_button_icon(get_editor_theme_icon(SNAME("ZoomMore")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -1270,7 +1270,7 @@ bool EditorInspectorPluginTextureRegion::parse_property(Object *p_object, const
if ((p_type == Variant::RECT2 || p_type == Variant::RECT2I)) {
if (((Object::cast_to<Sprite2D>(p_object) || Object::cast_to<Sprite3D>(p_object) || Object::cast_to<NinePatchRect>(p_object) || Object::cast_to<StyleBoxTexture>(p_object)) && p_path == "region_rect") || (Object::cast_to<AtlasTexture>(p_object) && p_path == "region")) {
Button *button = EditorInspector::create_inspector_action_button(TTR("Edit Region"));
- button->set_icon(texture_region_editor->get_editor_theme_icon(SNAME("RegionEdit")));
+ button->set_button_icon(texture_region_editor->get_editor_theme_icon(SNAME("RegionEdit")));
button->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorPluginTextureRegion::_region_edit).bind(p_object));
add_property_editor(p_path, button, true);
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index cc488ff340..de75ed8c12 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -861,43 +861,43 @@ void ThemeItemImportTree::_notification(int p_what) {
import_items_filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));
// Bottom panel buttons.
- import_collapse_types_button->set_icon(get_editor_theme_icon(SNAME("CollapseTree")));
- import_expand_types_button->set_icon(get_editor_theme_icon(SNAME("ExpandTree")));
+ import_collapse_types_button->set_button_icon(get_editor_theme_icon(SNAME("CollapseTree")));
+ import_expand_types_button->set_button_icon(get_editor_theme_icon(SNAME("ExpandTree")));
- import_select_all_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
- import_select_full_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
- import_deselect_all_button->set_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
+ import_select_all_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
+ import_select_full_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
+ import_deselect_all_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
// Side panel buttons.
select_colors_icon->set_texture(get_editor_theme_icon(SNAME("Color")));
- deselect_all_colors_button->set_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
- select_all_colors_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
- select_full_colors_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
+ deselect_all_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
+ select_all_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
+ select_full_colors_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
select_constants_icon->set_texture(get_editor_theme_icon(SNAME("MemberConstant")));
- deselect_all_constants_button->set_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
- select_all_constants_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
- select_full_constants_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
+ deselect_all_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
+ select_all_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
+ select_full_constants_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
select_fonts_icon->set_texture(get_editor_theme_icon(SNAME("FontItem")));
- deselect_all_fonts_button->set_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
- select_all_fonts_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
- select_full_fonts_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
+ deselect_all_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
+ select_all_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
+ select_full_fonts_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
select_font_sizes_icon->set_texture(get_editor_theme_icon(SNAME("FontSize")));
- deselect_all_font_sizes_button->set_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
- select_all_font_sizes_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
- select_full_font_sizes_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
+ deselect_all_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
+ select_all_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
+ select_full_font_sizes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
select_icons_icon->set_texture(get_editor_theme_icon(SNAME("ImageTexture")));
- deselect_all_icons_button->set_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
- select_all_icons_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
- select_full_icons_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
+ deselect_all_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
+ select_all_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
+ select_full_icons_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
select_styleboxes_icon->set_texture(get_editor_theme_icon(SNAME("StyleBoxFlat")));
- deselect_all_styleboxes_button->set_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
- select_all_styleboxes_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
- select_full_styleboxes_button->set_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
+ deselect_all_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeDeselectAll")));
+ select_all_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectAll")));
+ select_full_styleboxes_button->set_button_icon(get_editor_theme_icon(SNAME("ThemeSelectFull")));
} break;
}
}
@@ -1877,20 +1877,20 @@ void ThemeItemEditorDialog::_notification(int p_what) {
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
- edit_items_add_color->set_icon(get_editor_theme_icon(SNAME("Color")));
- edit_items_add_constant->set_icon(get_editor_theme_icon(SNAME("MemberConstant")));
- edit_items_add_font->set_icon(get_editor_theme_icon(SNAME("FontItem")));
- edit_items_add_font_size->set_icon(get_editor_theme_icon(SNAME("FontSize")));
- edit_items_add_icon->set_icon(get_editor_theme_icon(SNAME("ImageTexture")));
- edit_items_add_stylebox->set_icon(get_editor_theme_icon(SNAME("StyleBoxFlat")));
+ edit_items_add_color->set_button_icon(get_editor_theme_icon(SNAME("Color")));
+ edit_items_add_constant->set_button_icon(get_editor_theme_icon(SNAME("MemberConstant")));
+ edit_items_add_font->set_button_icon(get_editor_theme_icon(SNAME("FontItem")));
+ edit_items_add_font_size->set_button_icon(get_editor_theme_icon(SNAME("FontSize")));
+ edit_items_add_icon->set_button_icon(get_editor_theme_icon(SNAME("ImageTexture")));
+ edit_items_add_stylebox->set_button_icon(get_editor_theme_icon(SNAME("StyleBoxFlat")));
- edit_items_remove_class->set_icon(get_editor_theme_icon(SNAME("Control")));
- edit_items_remove_custom->set_icon(get_editor_theme_icon(SNAME("ThemeRemoveCustomItems")));
- edit_items_remove_all->set_icon(get_editor_theme_icon(SNAME("ThemeRemoveAllItems")));
+ edit_items_remove_class->set_button_icon(get_editor_theme_icon(SNAME("Control")));
+ edit_items_remove_custom->set_button_icon(get_editor_theme_icon(SNAME("ThemeRemoveCustomItems")));
+ edit_items_remove_all->set_button_icon(get_editor_theme_icon(SNAME("ThemeRemoveAllItems")));
- edit_add_type_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ edit_add_type_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
- import_another_theme_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
+ import_another_theme_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));
} break;
}
}
@@ -2481,21 +2481,21 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
item_name_edit->hide();
Button *item_rename_button = memnew(Button);
- item_rename_button->set_icon(get_editor_theme_icon(SNAME("Edit")));
+ item_rename_button->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
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(SceneStringName(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_editor_theme_icon(SNAME("Remove")));
+ item_remove_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
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(SceneStringName(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_editor_theme_icon(SNAME("ImportCheck")));
+ item_rename_confirm_button->set_button_icon(get_editor_theme_icon(SNAME("ImportCheck")));
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);
@@ -2503,7 +2503,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
item_rename_confirm_button->hide();
Button *item_rename_cancel_button = memnew(Button);
- item_rename_cancel_button->set_icon(get_editor_theme_icon(SNAME("ImportFail")));
+ item_rename_cancel_button->set_button_icon(get_editor_theme_icon(SNAME("ImportFail")));
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);
@@ -2513,7 +2513,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
item_name->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
Button *item_override_button = memnew(Button);
- item_override_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ item_override_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
item_override_button->set_tooltip_text(TTR("Override Item"));
item_override_button->set_flat(true);
item_name_container->add_child(item_override_button);
@@ -2722,7 +2722,7 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_flat(true);
pin_leader_button->set_toggle_mode(true);
pin_leader_button->set_pressed(true);
- pin_leader_button->set_icon(get_editor_theme_icon(SNAME("Pin")));
+ pin_leader_button->set_button_icon(get_editor_theme_icon(SNAME("Pin")));
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(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_on_unpin_leader_button_pressed));
@@ -2765,7 +2765,7 @@ void ThemeTypeEditor::_update_type_items() {
Button *pin_leader_button = memnew(Button);
pin_leader_button->set_flat(true);
pin_leader_button->set_toggle_mode(true);
- pin_leader_button->set_icon(get_editor_theme_icon(SNAME("Pin")));
+ pin_leader_button->set_button_icon(get_editor_theme_icon(SNAME("Pin")));
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(SceneStringName(pressed), callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed).bind(item_editor, E.key));
@@ -3371,7 +3371,7 @@ void ThemeTypeEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- add_type_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_type_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
data_type_tabs->set_tab_icon(0, get_editor_theme_icon(SNAME("Color")));
data_type_tabs->set_tab_icon(1, get_editor_theme_icon(SNAME("MemberConstant")));
@@ -3381,7 +3381,7 @@ void ThemeTypeEditor::_notification(int p_what) {
data_type_tabs->set_tab_icon(5, get_editor_theme_icon(SNAME("StyleBoxFlat")));
data_type_tabs->set_tab_icon(6, get_editor_theme_icon(SNAME("Tools")));
- type_variation_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ type_variation_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
}
}
@@ -3695,7 +3695,7 @@ void ThemeEditor::_notification(int p_what) {
preview_tabs->add_theme_style_override("tab_unselected", get_theme_stylebox(SNAME("ThemeEditorPreviewBG"), EditorStringName(EditorStyles)));
preview_tabs_content->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainerOdd")));
- add_preview_button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ add_preview_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
}
}
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index 2426cec521..ea5e8a8ad7 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -211,7 +211,7 @@ void ThemeEditorPreview::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- picker_button->set_icon(get_editor_theme_icon(SNAME("ColorPick")));
+ picker_button->set_button_icon(get_editor_theme_icon(SNAME("ColorPick")));
theme_cache.preview_picker_overlay = get_theme_stylebox(SNAME("preview_picker_overlay"), SNAME("ThemeEditor"));
theme_cache.preview_picker_overlay_color = get_theme_color(SNAME("preview_picker_overlay_color"), SNAME("ThemeEditor"));
@@ -489,7 +489,7 @@ void SceneThemeEditorPreview::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- reload_scene_button->set_icon(get_editor_theme_icon(SNAME("Reload")));
+ reload_scene_button->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
} break;
}
}
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index b806d1e042..bafacf8e36 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -496,13 +496,13 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
float TileAtlasView::get_zoom() const {
return zoom_widget->get_zoom();
-};
+}
void TileAtlasView::set_transform(float p_zoom, Vector2i p_panning) {
zoom_widget->set_zoom(p_zoom);
panning = p_panning;
_update_zoom_and_panning();
-};
+}
void TileAtlasView::set_padding(Side p_side, int p_padding) {
ERR_FAIL_COND(p_padding < 0);
@@ -618,7 +618,7 @@ void TileAtlasView::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- button_center_view->set_icon(theme_cache.center_view_icon);
+ button_center_view->set_button_icon(theme_cache.center_view_icon);
} break;
}
}
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 8fcf942056..025df4fda0 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -135,8 +135,8 @@ public:
void set_padding(Side p_side, int p_padding);
// Left side.
- void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); };
- void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); };
+ void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); }
+ void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); }
Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp = false) const;
@@ -148,7 +148,7 @@ public:
}
p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- };
+ }
// Right side.
Vector3i get_alternative_tile_at_pos(const Vector2 p_pos) const;
@@ -162,7 +162,7 @@ public:
}
p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
- };
+ }
// Redraw everything.
void queue_redraw();
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index c6921699a4..bf53a9dfba 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -722,7 +722,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
void GenericTilePolygonEditor::_set_snap_option(int p_index) {
current_snap_option = p_index;
- button_pixel_snap->set_icon(button_pixel_snap->get_popup()->get_item_icon(p_index));
+ button_pixel_snap->set_button_icon(button_pixel_snap->get_popup()->get_item_icon(p_index));
snap_subdivision->set_visible(p_index == SNAP_GRID);
if (initializing) {
@@ -880,16 +880,16 @@ void GenericTilePolygonEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- button_expand->set_icon(get_editor_theme_icon(SNAME("DistractionFree")));
- button_create->set_icon(get_editor_theme_icon(SNAME("CurveCreate")));
- button_edit->set_icon(get_editor_theme_icon(SNAME("CurveEdit")));
- button_delete->set_icon(get_editor_theme_icon(SNAME("CurveDelete")));
- button_center_view->set_icon(get_editor_theme_icon(SNAME("CenterView")));
- button_advanced_menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ button_expand->set_button_icon(get_editor_theme_icon(SNAME("DistractionFree")));
+ button_create->set_button_icon(get_editor_theme_icon(SNAME("CurveCreate")));
+ button_edit->set_button_icon(get_editor_theme_icon(SNAME("CurveEdit")));
+ button_delete->set_button_icon(get_editor_theme_icon(SNAME("CurveDelete")));
+ button_center_view->set_button_icon(get_editor_theme_icon(SNAME("CenterView")));
+ button_advanced_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
button_pixel_snap->get_popup()->set_item_icon(0, get_editor_theme_icon(SNAME("SnapDisable")));
button_pixel_snap->get_popup()->set_item_icon(1, get_editor_theme_icon(SNAME("Snap")));
button_pixel_snap->get_popup()->set_item_icon(2, get_editor_theme_icon(SNAME("SnapGrid")));
- button_pixel_snap->set_icon(button_pixel_snap->get_popup()->get_item_icon(current_snap_option));
+ button_pixel_snap->set_button_icon(button_pixel_snap->get_popup()->get_item_icon(current_snap_option));
PopupMenu *p = button_advanced_menu->get_popup();
p->set_item_icon(p->get_item_index(ROTATE_RIGHT), get_editor_theme_icon(SNAME("RotateRight")));
@@ -1100,11 +1100,10 @@ void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_
}
p_canvas_item->draw_set_transform_matrix(Transform2D());
}
-};
+}
void TileDataDefaultEditor::forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {
-
-};
+}
void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
@@ -1362,7 +1361,7 @@ void TileDataDefaultEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- picker_button->set_icon(get_editor_theme_icon(SNAME("ColorPick")));
+ picker_button->set_button_icon(get_editor_theme_icon(SNAME("ColorPick")));
tile_bool_checked = get_editor_theme_icon(SNAME("TileChecked"));
tile_bool_unchecked = get_editor_theme_icon(SNAME("TileUnchecked"));
} break;
@@ -2868,7 +2867,7 @@ void TileDataTerrainsEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- picker_button->set_icon(get_editor_theme_icon(SNAME("ColorPick")));
+ picker_button->set_button_icon(get_editor_theme_icon(SNAME("ColorPick")));
} break;
}
}
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index 1426bb4c2f..312eb724ed 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -62,7 +62,7 @@ public:
void set_tile_set(Ref<TileSet> p_tile_set);
// Input to handle painting.
- virtual Control *get_toolbar() { return nullptr; };
+ virtual Control *get_toolbar() { return nullptr; }
virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {}
virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {}
virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) {}
@@ -238,7 +238,7 @@ protected:
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value);
public:
- virtual Control *get_toolbar() override { return toolbar; };
+ virtual Control *get_toolbar() override { return toolbar; }
virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override;
@@ -375,7 +375,7 @@ protected:
void _notification(int p_what);
public:
- virtual Control *get_toolbar() override { return toolbar; };
+ virtual Control *get_toolbar() override { return toolbar; }
virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override;
virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override;
diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp
index dcfd92f6f9..16d4ee6f68 100644
--- a/editor/plugins/tiles/tile_map_layer_editor.cpp
+++ b/editor/plugins/tiles/tile_map_layer_editor.cpp
@@ -503,21 +503,21 @@ void TileMapLayerEditorTilesPlugin::_scenes_list_lmb_empty_clicked(const Vector2
}
void TileMapLayerEditorTilesPlugin::_update_theme() {
- source_sort_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Sort")));
- select_tool_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("ToolSelect")));
- paint_tool_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Edit")));
- line_tool_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Line")));
- rect_tool_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Rectangle")));
- bucket_tool_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Bucket")));
-
- picker_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("ColorPick")));
- erase_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Eraser")));
- random_tile_toggle->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("RandomNumberGenerator")));
-
- transform_button_rotate_left->set_icon(tiles_bottom_panel->get_editor_theme_icon("RotateLeft"));
- transform_button_rotate_right->set_icon(tiles_bottom_panel->get_editor_theme_icon("RotateRight"));
- transform_button_flip_h->set_icon(tiles_bottom_panel->get_editor_theme_icon("MirrorX"));
- transform_button_flip_v->set_icon(tiles_bottom_panel->get_editor_theme_icon("MirrorY"));
+ source_sort_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Sort")));
+ select_tool_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("ToolSelect")));
+ paint_tool_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Edit")));
+ line_tool_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Line")));
+ rect_tool_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Rectangle")));
+ bucket_tool_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Bucket")));
+
+ picker_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("ColorPick")));
+ erase_button->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Eraser")));
+ random_tile_toggle->set_button_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("RandomNumberGenerator")));
+
+ transform_button_rotate_left->set_button_icon(tiles_bottom_panel->get_editor_theme_icon("RotateLeft"));
+ transform_button_rotate_right->set_button_icon(tiles_bottom_panel->get_editor_theme_icon("RotateRight"));
+ transform_button_flip_h->set_button_icon(tiles_bottom_panel->get_editor_theme_icon("MirrorX"));
+ transform_button_flip_v->set_button_icon(tiles_bottom_panel->get_editor_theme_icon("MirrorY"));
missing_atlas_texture_icon = tiles_bottom_panel->get_editor_theme_icon(SNAME("TileSet"));
_update_tile_set_sources_list();
@@ -1550,6 +1550,7 @@ int TileMapLayerEditorTilesPlugin::_get_transformed_alternative(int p_alternativ
case TRANSFORM_ROTATE_RIGHT: {
// A matrix with every possible flip/transpose combination, sorted by what comes next when you rotate.
const LocalVector<bool> rotation_matrix = {
+ // NOLINTBEGIN(modernize-use-bool-literals)
0, 0, 0,
0, 1, 1,
1, 1, 0,
@@ -1558,6 +1559,7 @@ int TileMapLayerEditorTilesPlugin::_get_transformed_alternative(int p_alternativ
0, 0, 1,
0, 1, 0,
1, 1, 1
+ // NOLINTEND(modernize-use-bool-literals)
};
for (int i = 0; i < 8; i++) {
@@ -3486,13 +3488,13 @@ void TileMapLayerEditorTerrainsPlugin::_update_tiles_list() {
}
void TileMapLayerEditorTerrainsPlugin::_update_theme() {
- paint_tool_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Edit")));
- line_tool_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Line")));
- rect_tool_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Rectangle")));
- bucket_tool_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Bucket")));
+ paint_tool_button->set_button_icon(main_vbox_container->get_editor_theme_icon(SNAME("Edit")));
+ line_tool_button->set_button_icon(main_vbox_container->get_editor_theme_icon(SNAME("Line")));
+ rect_tool_button->set_button_icon(main_vbox_container->get_editor_theme_icon(SNAME("Rectangle")));
+ bucket_tool_button->set_button_icon(main_vbox_container->get_editor_theme_icon(SNAME("Bucket")));
- picker_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("ColorPick")));
- erase_button->set_icon(main_vbox_container->get_editor_theme_icon(SNAME("Eraser")));
+ picker_button->set_button_icon(main_vbox_container->get_editor_theme_icon(SNAME("ColorPick")));
+ erase_button->set_button_icon(main_vbox_container->get_editor_theme_icon(SNAME("Eraser")));
_update_tiles_list();
}
@@ -3689,12 +3691,12 @@ void TileMapLayerEditor::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
missing_tile_texture = get_editor_theme_icon(SNAME("StatusWarning"));
warning_pattern_texture = get_editor_theme_icon(SNAME("WarningPattern"));
- advanced_menu_button->set_icon(get_editor_theme_icon(SNAME("Tools")));
- select_previous_layer->set_icon(get_editor_theme_icon(SNAME("MoveUp")));
- select_next_layer->set_icon(get_editor_theme_icon(SNAME("MoveDown")));
- select_all_layers->set_icon(get_editor_theme_icon(SNAME("FileList")));
- toggle_grid_button->set_icon(get_editor_theme_icon(SNAME("Grid")));
- toggle_highlight_selected_layer_button->set_icon(get_editor_theme_icon(SNAME("TileMapHighlightSelected")));
+ advanced_menu_button->set_button_icon(get_editor_theme_icon(SNAME("Tools")));
+ select_previous_layer->set_button_icon(get_editor_theme_icon(SNAME("MoveUp")));
+ select_next_layer->set_button_icon(get_editor_theme_icon(SNAME("MoveDown")));
+ select_all_layers->set_button_icon(get_editor_theme_icon(SNAME("FileList")));
+ toggle_grid_button->set_button_icon(get_editor_theme_icon(SNAME("Grid")));
+ toggle_highlight_selected_layer_button->set_button_icon(get_editor_theme_icon(SNAME("TileMapHighlightSelected")));
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
diff --git a/editor/plugins/tiles/tile_map_layer_editor.h b/editor/plugins/tiles/tile_map_layer_editor.h
index 805af7b58e..bcba34299d 100644
--- a/editor/plugins/tiles/tile_map_layer_editor.h
+++ b/editor/plugins/tiles/tile_map_layer_editor.h
@@ -63,9 +63,9 @@ public:
virtual Vector<TabData> get_tabs() const {
return Vector<TabData>();
- };
+ }
- virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; };
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; }
virtual void forward_canvas_draw_over_viewport(Control *p_overlay) {}
virtual void tile_set_changed() {}
virtual void edit(ObjectID p_tile_map_layer_id) {}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index b1417b2878..941d44c85e 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -996,7 +996,7 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
// Create and position the button.
Button *button = memnew(Button);
button->set_flat(true);
- button->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
button->add_theme_style_override(CoreStringName(normal), memnew(StyleBoxEmpty));
button->add_theme_style_override("hover", memnew(StyleBoxEmpty));
button->add_theme_style_override("focus", memnew(StyleBoxEmpty));
@@ -1699,7 +1699,7 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) {
void TileSetAtlasSourceEditor::shortcut_input(const Ref<InputEvent> &p_event) {
// Check for shortcuts.
- if (ED_IS_SHORTCUT("tiles_editor/delete_tile", p_event)) {
+ if (ED_IS_SHORTCUT("tiles_editor/delete", p_event)) {
if (tools_button_group->get_pressed_button() == tool_select_button && !selection.is_empty()) {
_menu_option(TILE_DELETE);
accept_event();
@@ -2441,12 +2441,12 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- tool_setup_atlas_source_button->set_icon(get_editor_theme_icon(SNAME("Tools")));
- tool_select_button->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
- tool_paint_button->set_icon(get_editor_theme_icon(SNAME("Paint")));
+ tool_setup_atlas_source_button->set_button_icon(get_editor_theme_icon(SNAME("Tools")));
+ tool_select_button->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
+ tool_paint_button->set_button_icon(get_editor_theme_icon(SNAME("Paint")));
- tools_settings_erase_button->set_icon(get_editor_theme_icon(SNAME("Eraser")));
- tool_advanced_menu_button->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ tools_settings_erase_button->set_button_icon(get_editor_theme_icon(SNAME("Eraser")));
+ tool_advanced_menu_button->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
outside_tiles_warning->set_texture(get_editor_theme_icon(SNAME("StatusWarning")));
resize_handle = get_editor_theme_icon(SNAME("EditorHandle"));
@@ -2711,7 +2711,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
alternative_tile_popup_menu = memnew(PopupMenu);
- alternative_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete_tile", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
+ alternative_tile_popup_menu->add_shortcut(ED_GET_SHORTCUT("tiles_editor/delete"), TILE_DELETE);
alternative_tile_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
tile_atlas_view->add_child(alternative_tile_popup_menu);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index c1a8338f81..f8b65bd675 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -80,7 +80,7 @@ public:
int get_id() const;
void edit(Ref<TileSet> p_tile_set, Ref<TileSetAtlasSource> p_tile_set_atlas_source, int p_source_id);
- Ref<TileSetAtlasSource> get_edited() { return tile_set_atlas_source; };
+ Ref<TileSetAtlasSource> get_edited() { return tile_set_atlas_source; }
};
// -- Proxy object for a tile, needed by the inspector --
@@ -91,7 +91,7 @@ public:
TileSetAtlasSourceEditor *tiles_set_atlas_source_editor = nullptr;
Ref<TileSetAtlasSource> tile_set_atlas_source;
- RBSet<TileSelection> tiles = RBSet<TileSelection>();
+ RBSet<TileSelection> tiles;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -101,8 +101,8 @@ public:
static void _bind_methods();
public:
- Ref<TileSetAtlasSource> get_edited_tile_set_atlas_source() const { return tile_set_atlas_source; };
- RBSet<TileSelection> get_edited_tiles() const { return tiles; };
+ Ref<TileSetAtlasSource> get_edited_tile_set_atlas_source() const { return tile_set_atlas_source; }
+ RBSet<TileSelection> get_edited_tiles() const { return tiles; }
// Update the proxyed object.
void edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, const RBSet<TileSelection> &p_tiles = RBSet<TileSelection>());
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 7e5336ce06..6f473d1b60 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -366,10 +366,10 @@ void TileSetEditor::_set_source_sort(int p_sort) {
void TileSetEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- sources_delete_button->set_icon(get_editor_theme_icon(SNAME("Remove")));
- sources_add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
- source_sort_button->set_icon(get_editor_theme_icon(SNAME("Sort")));
- sources_advanced_menu_button->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ sources_delete_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
+ sources_add_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ source_sort_button->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
+ sources_advanced_menu_button->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
missing_texture_texture = get_editor_theme_icon(SNAME("TileSet"));
expanded_area->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), "Tree"));
_update_sources_list();
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index 305407efdb..e2b3c451b0 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -367,8 +367,8 @@ void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- scene_tile_add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
- scene_tile_delete_button->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ scene_tile_add_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ scene_tile_delete_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
_update_scenes_list();
} break;
diff --git a/editor/plugins/tool_button_editor_plugin.cpp b/editor/plugins/tool_button_editor_plugin.cpp
index d9852c8694..d9a15d9a23 100644
--- a/editor/plugins/tool_button_editor_plugin.cpp
+++ b/editor/plugins/tool_button_editor_plugin.cpp
@@ -33,7 +33,7 @@
#include "scene/gui/button.h"
void EditorInspectorToolButtonPlugin::_update_action_icon(Button *p_action_button, const String &p_action_icon) {
- p_action_button->set_icon(p_action_button->get_editor_theme_icon(p_action_icon));
+ p_action_button->set_button_icon(p_action_button->get_editor_theme_icon(p_action_icon));
}
void EditorInspectorToolButtonPlugin::_call_action(const Variant &p_object, const StringName &p_property) {
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 4f0df1d5fc..815664c608 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -1081,7 +1081,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
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_editor_theme_icon("Folder"));
+ select_public_path_button->set_button_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon("Folder"));
select_public_path_button->connect(SceneStringName(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);
@@ -1114,7 +1114,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
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_editor_theme_icon("Folder"));
+ select_private_path_button->set_button_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon("Folder"));
select_private_path_button->connect(SceneStringName(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);
@@ -1159,7 +1159,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
refresh_button = memnew(Button);
refresh_button->set_tooltip_text(TTR("Detect new changes"));
refresh_button->set_theme_type_variation("FlatButton");
- refresh_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));
+ refresh_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));
refresh_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
refresh_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_commit_list));
refresh_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));
@@ -1179,14 +1179,14 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
discard_all_button = memnew(Button);
discard_all_button->set_tooltip_text(TTR("Discard all changes"));
- discard_all_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Close"), EditorStringName(EditorIcons)));
+ discard_all_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Close"), EditorStringName(EditorIcons)));
discard_all_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_confirm_discard_all));
discard_all_button->set_theme_type_variation("FlatButton");
unstage_title->add_child(discard_all_button);
stage_all_button = memnew(Button);
stage_all_button->set_theme_type_variation("FlatButton");
- stage_all_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));
+ stage_all_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));
stage_all_button->set_tooltip_text(TTR("Stage all changes"));
unstage_title->add_child(stage_all_button);
@@ -1216,7 +1216,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
unstage_all_button = memnew(Button);
unstage_all_button->set_theme_type_variation("FlatButton");
- unstage_all_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));
+ unstage_all_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));
unstage_all_button->set_tooltip_text(TTR("Unstage all changes"));
stage_title->add_child(unstage_all_button);
@@ -1411,26 +1411,26 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
fetch_button = memnew(Button);
fetch_button->set_theme_type_variation("FlatButton");
fetch_button->set_tooltip_text(TTR("Fetch"));
- fetch_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));
+ fetch_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));
fetch_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_fetch));
menu_bar->add_child(fetch_button);
pull_button = memnew(Button);
pull_button->set_theme_type_variation("FlatButton");
pull_button->set_tooltip_text(TTR("Pull"));
- pull_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));
+ pull_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));
pull_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_pull));
menu_bar->add_child(pull_button);
push_button = memnew(Button);
push_button->set_theme_type_variation("FlatButton");
push_button->set_tooltip_text(TTR("Push"));
- push_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));
+ push_button->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));
push_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_push));
menu_bar->add_child(push_button);
extra_options = memnew(MenuButton);
- extra_options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GuiTabMenuHl"), EditorStringName(EditorIcons)));
+ extra_options->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GuiTabMenuHl"), EditorStringName(EditorIcons)));
extra_options->get_popup()->connect(SNAME("about_to_popup"), callable_mp(this, &VersionControlEditorPlugin::_update_extra_options));
extra_options->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected));
menu_bar->add_child(extra_options);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index a5df9edcf0..9c1befa144 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -258,7 +258,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
vbox->add_child(offset);
VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);
- port_preview->setup(visual_shader, editor->preview_material, visual_shader->get_shader_type(), p_node_id, p_port_id, p_is_valid);
+ port_preview->setup(visual_shader, editor->preview_material, visual_shader->get_shader_type(), links[p_node_id].output_ports[p_port_id].type == VisualShaderNode::PORT_TYPE_VECTOR_4D, p_node_id, p_port_id, p_is_valid);
port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
vbox->add_child(port_preview);
link.preview_visible = true;
@@ -554,8 +554,8 @@ void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id,
links.insert(p_id, { p_type, p_visual_node, p_graph_element, p_visual_node->get_output_port_for_preview() != -1, -1, HashMap<int, InputPort>(), HashMap<int, Port>(), nullptr, nullptr, nullptr, { nullptr, nullptr, nullptr } });
}
-void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) {
- links[p_node_id].output_ports.insert(p_port, { p_button });
+void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, VisualShaderNode::PortType p_port_type, TextureButton *p_button) {
+ links[p_node_id].output_ports.insert(p_port, { p_port_type, p_button });
}
void VisualShaderGraphPlugin::register_parameter_name(int p_node_id, LineEdit *p_parameter_name) {
@@ -1138,7 +1138,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
name_box->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, j, false), CONNECT_DEFERRED);
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
+ remove_btn->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, j), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -1166,7 +1166,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
if (valid_right) {
if (is_group) {
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
+ remove_btn->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -1220,7 +1220,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
preview->set_texture_pressed(editor->get_editor_theme_icon(SNAME("GuiVisibilityVisible")));
preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
- register_output_port(p_id, j, preview);
+ register_output_port(p_id, j, port_right, preview);
preview->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_preview_select_port).bind(p_id, j), CONNECT_DEFERRED);
hb->add_child(preview);
@@ -1472,7 +1472,7 @@ void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_
if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) {
graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
- for (const List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {
+ for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {
if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
connections.erase(E);
break;
@@ -5106,8 +5106,8 @@ void VisualShaderEditor::_notification(int p_what) {
param_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search")));
node_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search")));
- code_preview_button->set_icon(Control::get_editor_theme_icon(SNAME("Shader")));
- shader_preview_button->set_icon(Control::get_editor_theme_icon(SNAME("SubViewport")));
+ code_preview_button->set_button_icon(Control::get_editor_theme_icon(SNAME("Shader")));
+ shader_preview_button->set_button_icon(Control::get_editor_theme_icon(SNAME("SubViewport")));
{
Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color");
@@ -5158,7 +5158,7 @@ void VisualShaderEditor::_notification(int p_what) {
error_label->end_bulk_theme_override();
}
- tools->set_icon(get_editor_theme_icon(SNAME("Tools")));
+ tools->set_button_icon(get_editor_theme_icon(SNAME("Tools")));
if (is_visible_in_tree()) {
_update_graph();
@@ -8031,7 +8031,15 @@ void VisualShaderNodePortPreview::_shader_changed() {
set_material(mat);
}
-void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Ref<ShaderMaterial> &p_preview_material, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid) {
+void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Ref<ShaderMaterial> &p_preview_material, VisualShader::Type p_type, bool p_has_transparency, int p_node, int p_port, bool p_is_valid) {
+ if (p_has_transparency) {
+ checkerboard = memnew(TextureRect);
+ checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE);
+ checkerboard->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+ checkerboard->set_draw_behind_parent(true);
+ add_child(checkerboard);
+ }
+
shader = p_shader;
shader->connect_changed(callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);
preview_mat = p_preview_material;
@@ -8050,6 +8058,11 @@ Size2 VisualShaderNodePortPreview::get_minimum_size() const {
void VisualShaderNodePortPreview::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ if (checkerboard != nullptr) {
+ checkerboard->set_texture(get_theme_icon(SNAME("GuiMiniCheckerboard"), EditorStringName(EditorIcons)));
+ }
+ } break;
case NOTIFICATION_DRAW: {
Vector<Vector2> points = {
Vector2(),
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 3b2ad33304..d3dc2e7564 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -107,6 +107,7 @@ private:
};
struct Port {
+ VisualShaderNode::PortType type = VisualShaderNode::PORT_TYPE_SCALAR;
TextureButton *preview_button = nullptr;
};
@@ -141,7 +142,7 @@ public:
void register_shader(VisualShader *p_visual_shader);
void set_connections(const List<VisualShader::Connection> &p_connections);
void register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphElement *p_graph_element);
- void register_output_port(int p_id, int p_port, TextureButton *p_button);
+ void register_output_port(int p_id, int p_port, VisualShaderNode::PortType p_port_type, TextureButton *p_button);
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);
@@ -680,6 +681,7 @@ public:
class VisualShaderNodePortPreview : public Control {
GDCLASS(VisualShaderNodePortPreview, Control);
+ TextureRect *checkerboard = nullptr;
Ref<VisualShader> shader;
Ref<ShaderMaterial> preview_mat;
VisualShader::Type type = VisualShader::Type::TYPE_MAX;
@@ -692,7 +694,7 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
- void setup(const Ref<VisualShader> &p_shader, Ref<ShaderMaterial> &p_preview_material, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid);
+ void setup(const Ref<VisualShader> &p_shader, Ref<ShaderMaterial> &p_preview_material, VisualShader::Type p_type, bool p_has_transparency, int p_node, int p_port, bool p_is_valid);
};
class VisualShaderConversionPlugin : public EditorResourceConversionPlugin {
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index 3e835d5cb6..68fe013c08 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -185,7 +185,7 @@ VoxelGIEditorPlugin::VoxelGIEditorPlugin() {
bake->set_theme_type_variation("FlatButton");
// TODO: Rework this as a dedicated toolbar control so we can hook into theme changes and update it
// when the editor theme updates.
- bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
+ bake->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake VoxelGI"));
bake->connect(SceneStringName(pressed), callable_mp(this, &VoxelGIEditorPlugin::_bake));
bake_hb->add_child(bake);
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index b295e5733e..d08610c93f 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -716,8 +716,9 @@ Vector<String> ProjectConverter3To4::check_for_files() {
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(".gdshader") || 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") || file_name.ends_with(".import"))
+ if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".gdshader") || 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") || file_name.ends_with(".import")) {
proper_extension = true;
+ }
if (proper_extension) {
collected_files.append(current_dir.path_join(file_name));
@@ -1270,7 +1271,7 @@ bool ProjectConverter3To4::test_single_array(const char *p_array[][2], bool p_ig
}
}
return valid;
-};
+}
// Returns arguments from given function execution, this cannot be really done as regex.
// `abc(d,e(f,g),h)` -> [d], [e(f,g)], [h]
@@ -1321,8 +1322,9 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
break;
};
case '"': {
- if (previous_character != '\\')
+ if (previous_character != '\\') {
is_inside_string = !is_inside_string;
+ }
}
}
previous_character = character;
@@ -1469,7 +1471,7 @@ void ProjectConverter3To4::rename_colors(Vector<SourceLine> &source_lines, const
}
}
}
-};
+}
// Convert hexadecimal colors from ARGB to RGBA
void ProjectConverter3To4::convert_hexadecimal_colors(Vector<SourceLine> &source_lines, const RegExContainer &reg_container) {
@@ -1566,7 +1568,7 @@ void ProjectConverter3To4::rename_classes(Vector<SourceLine> &source_lines, cons
}
}
}
-};
+}
Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
Vector<String> found_renames;
@@ -1618,7 +1620,7 @@ void ProjectConverter3To4::rename_gdscript_functions(Vector<SourceLine> &source_
process_gdscript_line(line, reg_container, builtin);
}
}
-};
+}
Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
int current_line = 1;
@@ -2438,7 +2440,7 @@ void ProjectConverter3To4::rename_csharp_functions(Vector<SourceLine> &source_li
process_csharp_line(line, reg_container);
}
}
-};
+}
Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
int current_line = 1;
@@ -2847,7 +2849,7 @@ void ProjectConverter3To4::custom_rename(Vector<SourceLine> &source_lines, const
line = reg.sub(line, to, true);
}
}
-};
+}
Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, const String &from, const String &to) {
Vector<String> found_renames;
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 30878a2488..30cf2030bc 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -224,7 +224,7 @@ void ProjectManager::_update_theme(bool p_skip_creation) {
background_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles)));
main_view_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer")));
- title_bar_logo->set_icon(get_editor_theme_icon(SNAME("TitleBarLogo")));
+ title_bar_logo->set_button_icon(get_editor_theme_icon(SNAME("TitleBarLogo")));
_set_main_view_icon(MAIN_VIEW_PROJECTS, get_editor_theme_icon(SNAME("ProjectList")));
_set_main_view_icon(MAIN_VIEW_ASSETLIB, get_editor_theme_icon(SNAME("AssetLib")));
@@ -234,28 +234,28 @@ void ProjectManager::_update_theme(bool p_skip_creation) {
loading_label->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("bold"), EditorStringName(EditorFonts)));
project_list_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("project_list"), SNAME("ProjectManager")));
- empty_list_create_project->set_icon(get_editor_theme_icon(SNAME("Add")));
- empty_list_import_project->set_icon(get_editor_theme_icon(SNAME("Load")));
- empty_list_open_assetlib->set_icon(get_editor_theme_icon(SNAME("AssetLib")));
+ empty_list_create_project->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ empty_list_import_project->set_button_icon(get_editor_theme_icon(SNAME("Load")));
+ empty_list_open_assetlib->set_button_icon(get_editor_theme_icon(SNAME("AssetLib")));
empty_list_online_warning->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("italic"), EditorStringName(EditorFonts)));
empty_list_online_warning->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("font_placeholder_color"), EditorStringName(Editor)));
// Top bar.
search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- quick_settings_button->set_icon(get_editor_theme_icon(SNAME("Tools")));
+ quick_settings_button->set_button_icon(get_editor_theme_icon(SNAME("Tools")));
// Sidebar.
- create_btn->set_icon(get_editor_theme_icon(SNAME("Add")));
- import_btn->set_icon(get_editor_theme_icon(SNAME("Load")));
- scan_btn->set_icon(get_editor_theme_icon(SNAME("Search")));
- open_btn->set_icon(get_editor_theme_icon(SNAME("Edit")));
- run_btn->set_icon(get_editor_theme_icon(SNAME("Play")));
- rename_btn->set_icon(get_editor_theme_icon(SNAME("Rename")));
- manage_tags_btn->set_icon(get_editor_theme_icon("Script"));
- erase_btn->set_icon(get_editor_theme_icon(SNAME("Remove")));
- erase_missing_btn->set_icon(get_editor_theme_icon(SNAME("Clear")));
- create_tag_btn->set_icon(get_editor_theme_icon("Add"));
+ create_btn->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ import_btn->set_button_icon(get_editor_theme_icon(SNAME("Load")));
+ scan_btn->set_button_icon(get_editor_theme_icon(SNAME("Search")));
+ open_btn->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
+ run_btn->set_button_icon(get_editor_theme_icon(SNAME("Play")));
+ rename_btn->set_button_icon(get_editor_theme_icon(SNAME("Rename")));
+ manage_tags_btn->set_button_icon(get_editor_theme_icon("Script"));
+ erase_btn->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
+ erase_missing_btn->set_button_icon(get_editor_theme_icon(SNAME("Clear")));
+ create_tag_btn->set_button_icon(get_editor_theme_icon("Add"));
tag_error->add_theme_color_override(SceneStringName(font_color), get_theme_color("error_color", EditorStringName(Editor)));
tag_edit_error->add_theme_color_override(SceneStringName(font_color), get_theme_color("error_color", EditorStringName(Editor)));
@@ -310,17 +310,17 @@ void ProjectManager::_set_main_view_icon(MainViewTab p_id, const Ref<Texture2D>
Button *toggle_button = main_view_toggle_map[p_id];
- Ref<Texture2D> old_icon = toggle_button->get_icon();
+ Ref<Texture2D> old_icon = toggle_button->get_button_icon();
if (old_icon.is_valid()) {
old_icon->disconnect_changed(callable_mp((Control *)toggle_button, &Control::update_minimum_size));
}
if (p_icon.is_valid()) {
- toggle_button->set_icon(p_icon);
+ toggle_button->set_button_icon(p_icon);
// Make sure the control is updated if the icon is reimported.
p_icon->connect_changed(callable_mp((Control *)toggle_button, &Control::update_minimum_size));
} else {
- toggle_button->set_icon(Ref<Texture2D>());
+ toggle_button->set_button_icon(Ref<Texture2D>());
}
}
diff --git a/editor/project_manager/project_dialog.cpp b/editor/project_manager/project_dialog.cpp
index 7aadb9ac3c..8750ae8714 100644
--- a/editor/project_manager/project_dialog.cpp
+++ b/editor/project_manager/project_dialog.cpp
@@ -825,9 +825,9 @@ void ProjectDialog::show_dialog(bool p_reset_name) {
void ProjectDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- create_dir->set_icon(get_editor_theme_icon(SNAME("FolderCreate")));
- project_browse->set_icon(get_editor_theme_icon(SNAME("FolderBrowse")));
- install_browse->set_icon(get_editor_theme_icon(SNAME("FolderBrowse")));
+ create_dir->set_button_icon(get_editor_theme_icon(SNAME("FolderCreate")));
+ project_browse->set_button_icon(get_editor_theme_icon(SNAME("FolderBrowse")));
+ install_browse->set_button_icon(get_editor_theme_icon(SNAME("FolderBrowse")));
} break;
case NOTIFICATION_READY: {
fdialog_project = memnew(EditorFileDialog);
diff --git a/editor/project_manager/project_list.cpp b/editor/project_manager/project_list.cpp
index 39c1a78c4a..27f04c0d0d 100644
--- a/editor/project_manager/project_list.cpp
+++ b/editor/project_manager/project_list.cpp
@@ -67,9 +67,9 @@ void ProjectListItemControl::_notification(int p_what) {
favorite_button->set_texture_normal(get_editor_theme_icon(SNAME("Favorites")));
if (project_is_missing) {
- explore_button->set_icon(get_editor_theme_icon(SNAME("FileBroken")));
+ explore_button->set_button_icon(get_editor_theme_icon(SNAME("FileBroken")));
} else {
- explore_button->set_icon(get_editor_theme_icon(SNAME("Load")));
+ explore_button->set_button_icon(get_editor_theme_icon(SNAME("Load")));
}
} break;
@@ -196,12 +196,12 @@ void ProjectListItemControl::set_is_missing(bool p_missing) {
if (project_is_missing) {
project_icon->set_modulate(Color(1, 1, 1, 0.5));
- explore_button->set_icon(get_editor_theme_icon(SNAME("FileBroken")));
+ explore_button->set_button_icon(get_editor_theme_icon(SNAME("FileBroken")));
explore_button->set_tooltip_text(TTR("Error: Project is missing on the filesystem."));
} else {
project_icon->set_modulate(Color(1, 1, 1, 1.0));
- explore_button->set_icon(get_editor_theme_icon(SNAME("Load")));
+ explore_button->set_button_icon(get_editor_theme_icon(SNAME("Load")));
#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
explore_button->set_tooltip_text(TTR("Show in File Manager"));
#else
diff --git a/editor/project_manager/project_tag.cpp b/editor/project_manager/project_tag.cpp
index 618b6555d4..e66969333c 100644
--- a/editor/project_manager/project_tag.cpp
+++ b/editor/project_manager/project_tag.cpp
@@ -36,7 +36,7 @@
void ProjectTag::_notification(int p_what) {
if (display_close && p_what == NOTIFICATION_THEME_CHANGED) {
- button->set_icon(get_theme_icon(SNAME("close"), SNAME("TabBar")));
+ button->set_button_icon(get_theme_icon(SNAME("close"), SNAME("TabBar")));
}
}
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index f973367bed..89c18143dc 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -576,10 +576,10 @@ void ProjectSettingsEditor::_update_action_map_editor() {
}
void ProjectSettingsEditor::_update_theme() {
- add_button->set_icon(get_editor_theme_icon(SNAME("Add")));
- del_button->set_icon(get_editor_theme_icon(SNAME("Remove")));
+ add_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ del_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- restart_close_button->set_icon(get_editor_theme_icon(SNAME("Close")));
+ restart_close_button->set_button_icon(get_editor_theme_icon(SNAME("Close")));
restart_container->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
restart_icon->set_texture(get_editor_theme_icon(SNAME("StatusWarning")));
restart_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h
index 37d159b4e2..5c2ac2558d 100644
--- a/editor/rename_dialog.h
+++ b/editor/rename_dialog.h
@@ -49,7 +49,7 @@ class TabContainer;
class RenameDialog : public ConfirmationDialog {
GDCLASS(RenameDialog, ConfirmationDialog);
- virtual void ok_pressed() override { rename(); };
+ virtual void ok_pressed() override { rename(); }
void _cancel_pressed() {}
void _features_toggled(bool pressed);
void _insert_text(const String &text);
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 90e4d74fcb..dc1198167d 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -48,10 +48,10 @@
void SceneCreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- select_node_button->set_icon(get_editor_theme_icon(SNAME("ClassList")));
- node_type_2d->set_icon(get_editor_theme_icon(SNAME("Node2D")));
- node_type_3d->set_icon(get_editor_theme_icon(SNAME("Node3D")));
- node_type_gui->set_icon(get_editor_theme_icon(SNAME("Control")));
+ select_node_button->set_button_icon(get_editor_theme_icon(SNAME("ClassList")));
+ node_type_2d->set_button_icon(get_editor_theme_icon(SNAME("Node2D")));
+ node_type_3d->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));
+ node_type_gui->set_button_icon(get_editor_theme_icon(SNAME("Control")));
node_type_other->add_theme_icon_override(SNAME("icon"), get_editor_theme_icon(SNAME("Node")));
} break;
@@ -121,9 +121,9 @@ void SceneCreateDialog::update_dialog() {
const StringName root_type_name = StringName(other_type_display->get_text());
if (has_theme_icon(root_type_name, EditorStringName(EditorIcons))) {
- node_type_other->set_icon(get_editor_theme_icon(root_type_name));
+ node_type_other->set_button_icon(get_editor_theme_icon(root_type_name));
} else {
- node_type_other->set_icon(nullptr);
+ node_type_other->set_button_icon(nullptr);
}
root_name = root_name_edit->get_text().strip_edges();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index bcab0c2883..87ba2e6875 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -126,7 +126,8 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT)) {
- if (mb->is_pressed() && scene_tree->get_rect().has_point(scene_tree->get_local_mouse_position())) {
+ Tree *tree = scene_tree->get_scene_tree();
+ if (mb->is_pressed() && tree->get_rect().has_point(tree->get_local_mouse_position())) {
tree_clicked = true;
} else if (!mb->is_pressed()) {
tree_clicked = false;
@@ -156,11 +157,12 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
}
if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) {
- // Prevent renaming if a button is focused
- // to avoid conflict with Enter shortcut on macOS
- if (!focus_owner || !Object::cast_to<BaseButton>(focus_owner)) {
- _tool_selected(TOOL_RENAME);
+ // Prevent renaming if a button or a range is focused
+ // to avoid conflict with Enter shortcut on macOS.
+ if (focus_owner && (Object::cast_to<BaseButton>(focus_owner) || Object::cast_to<Range>(focus_owner))) {
+ return;
}
+ _tool_selected(TOOL_RENAME);
#ifdef MODULE_REGEX_ENABLED
} else if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) {
_tool_selected(TOOL_BATCH_RENAME);
@@ -1589,7 +1591,7 @@ void SceneTreeDock::_notification(int p_what) {
node_shortcuts_toggle = memnew(Button);
node_shortcuts_toggle->set_flat(true);
- node_shortcuts_toggle->set_icon(get_editor_theme_icon(SNAME("Favorites")));
+ node_shortcuts_toggle->set_button_icon(get_editor_theme_icon(SNAME("Favorites")));
node_shortcuts_toggle->set_toggle_mode(true);
node_shortcuts_toggle->set_tooltip_text(TTR("Toggle the display of favorite nodes."));
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
@@ -1614,19 +1616,19 @@ void SceneTreeDock::_notification(int p_what) {
button_2d = memnew(Button);
beginner_node_shortcuts->add_child(button_2d);
button_2d->set_text(TTR("2D Scene"));
- button_2d->set_icon(get_editor_theme_icon(SNAME("Node2D")));
+ button_2d->set_button_icon(get_editor_theme_icon(SNAME("Node2D")));
button_2d->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_2D_SCENE, false));
button_3d = memnew(Button);
beginner_node_shortcuts->add_child(button_3d);
button_3d->set_text(TTR("3D Scene"));
- button_3d->set_icon(get_editor_theme_icon(SNAME("Node3D")));
+ button_3d->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));
button_3d->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_3D_SCENE, false));
button_ui = memnew(Button);
beginner_node_shortcuts->add_child(button_ui);
button_ui->set_text(TTR("User Interface"));
- button_ui->set_icon(get_editor_theme_icon(SNAME("Control")));
+ button_ui->set_button_icon(get_editor_theme_icon(SNAME("Control")));
button_ui->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_CREATE_USER_INTERFACE, false));
favorite_node_shortcuts = memnew(VBoxContainer);
@@ -1635,13 +1637,13 @@ void SceneTreeDock::_notification(int p_what) {
button_custom = memnew(Button);
node_shortcuts->add_child(button_custom);
button_custom->set_text(TTR("Other Node"));
- button_custom->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_custom->set_button_icon(get_editor_theme_icon(SNAME("Add")));
button_custom->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
button_clipboard = memnew(Button);
node_shortcuts->add_child(button_clipboard);
button_clipboard->set_text(TTR("Paste From Clipboard"));
- button_clipboard->set_icon(get_editor_theme_icon(SNAME("ActionPaste")));
+ button_clipboard->set_button_icon(get_editor_theme_icon(SNAME("ActionPaste")));
button_clipboard->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_PASTE, false));
_update_create_root_dialog(true);
@@ -1663,11 +1665,12 @@ void SceneTreeDock::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- button_add->set_icon(get_editor_theme_icon(SNAME("Add")));
- button_instance->set_icon(get_editor_theme_icon(SNAME("Instance")));
- button_create_script->set_icon(get_editor_theme_icon(SNAME("ScriptCreate")));
- button_detach_script->set_icon(get_editor_theme_icon(SNAME("ScriptRemove")));
- button_tree_menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ button_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
+ button_instance->set_button_icon(get_editor_theme_icon(SNAME("Instance")));
+ button_create_script->set_button_icon(get_editor_theme_icon(SNAME("ScriptCreate")));
+ button_detach_script->set_button_icon(get_editor_theme_icon(SNAME("ScriptRemove")));
+ button_extend_script->set_button_icon(get_editor_theme_icon(SNAME("ScriptExtend")));
+ button_tree_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));
@@ -1678,19 +1681,19 @@ void SceneTreeDock::_notification(int p_what) {
// These buttons are created on READY, because reasons...
if (button_2d) {
- button_2d->set_icon(get_editor_theme_icon(SNAME("Node2D")));
+ button_2d->set_button_icon(get_editor_theme_icon(SNAME("Node2D")));
}
if (button_3d) {
- button_3d->set_icon(get_editor_theme_icon(SNAME("Node3D")));
+ button_3d->set_button_icon(get_editor_theme_icon(SNAME("Node3D")));
}
if (button_ui) {
- button_ui->set_icon(get_editor_theme_icon(SNAME("Control")));
+ button_ui->set_button_icon(get_editor_theme_icon(SNAME("Control")));
}
if (button_custom) {
- button_custom->set_icon(get_editor_theme_icon(SNAME("Add")));
+ button_custom->set_button_icon(get_editor_theme_icon(SNAME("Add")));
}
if (button_clipboard) {
- button_clipboard->set_icon(get_editor_theme_icon(SNAME("ActionPaste")));
+ button_clipboard->set_button_icon(get_editor_theme_icon(SNAME("ActionPaste")));
}
menu_subresources->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)));
@@ -2784,33 +2787,49 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
}
void SceneTreeDock::_update_script_button() {
- if (!profile_allow_script_editing) {
- button_create_script->hide();
- button_detach_script->hide();
- } else if (editor_selection->get_selection().size() == 0) {
- button_create_script->hide();
- button_detach_script->hide();
- } else if (editor_selection->get_selection().size() == 1) {
- Node *n = editor_selection->get_selected_node_list().front()->get();
- if (n->get_script().is_null()) {
- button_create_script->show();
- button_detach_script->hide();
- } else {
- button_create_script->hide();
- button_detach_script->show();
- }
- } else {
- button_create_script->hide();
+ bool can_create_script = false;
+ bool can_detach_script = false;
+ bool can_extend_script = false;
+
+ if (profile_allow_script_editing) {
Array selection = editor_selection->get_selected_nodes();
+
for (int i = 0; i < selection.size(); i++) {
Node *n = Object::cast_to<Node>(selection[i]);
- if (!n->get_script().is_null()) {
- button_detach_script->show();
- return;
+ Ref<Script> s = n->get_script();
+ Ref<Script> cts;
+
+ if (n->has_meta(SceneStringName(_custom_type_script))) {
+ cts = n->get_meta(SceneStringName(_custom_type_script));
+ }
+
+ if (selection.size() == 1) {
+ if (s.is_valid()) {
+ if (cts.is_valid() && s == cts) {
+ can_extend_script = true;
+ }
+ } else {
+ can_create_script = true;
+ }
+ }
+
+ if (s.is_valid()) {
+ if (cts.is_valid()) {
+ if (s != cts) {
+ can_detach_script = true;
+ break;
+ }
+ } else {
+ can_detach_script = true;
+ break;
+ }
}
}
- button_detach_script->hide();
}
+
+ button_create_script->set_visible(can_create_script);
+ button_detach_script->set_visible(can_detach_script);
+ button_extend_script->set_visible(can_extend_script);
}
void SceneTreeDock::_selection_changed() {
@@ -3057,7 +3076,28 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro
Node *newnode = p_by_node;
if (p_keep_properties) {
- Node *default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(oldnode->get_class()));
+ Node *default_oldnode = nullptr;
+
+ // If we're dealing with a custom node type, we need to create a default instance of the custom type instead of the native type for property comparison.
+ if (oldnode->has_meta(SceneStringName(_custom_type_script))) {
+ Ref<Script> cts = oldnode->get_meta(SceneStringName(_custom_type_script));
+ default_oldnode = Object::cast_to<Node>(get_editor_data()->script_class_instance(cts->get_global_name()));
+ if (default_oldnode) {
+ default_oldnode->set_name(cts->get_global_name());
+ get_editor_data()->instantiate_object_properties(default_oldnode);
+ } else {
+ // Legacy custom type, registered with "add_custom_type()".
+ // TODO: Should probably be deprecated in 4.x.
+ const EditorData::CustomType *custom_type = get_editor_data()->get_custom_type_by_path(cts->get_path());
+ if (custom_type) {
+ default_oldnode = Object::cast_to<Node>(get_editor_data()->instantiate_custom_type(custom_type->name, cts->get_instance_base_type()));
+ }
+ }
+ }
+
+ if (!default_oldnode) {
+ default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(oldnode->get_class()));
+ }
List<PropertyInfo> pinfo;
oldnode->get_property_list(&pinfo);
@@ -3542,6 +3582,27 @@ void SceneTreeDock::_script_dropped(const String &p_file, NodePath p_to) {
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(n)).path_join(new_node->get_name())));
undo_redo->commit_action();
} else {
+ // Check if dropped script is compatible.
+ if (n->has_meta(SceneStringName(_custom_type_script))) {
+ Ref<Script> ct_scr = n->get_meta(SceneStringName(_custom_type_script));
+ if (!scr->inherits_script(ct_scr)) {
+ String custom_type_name = ct_scr->get_global_name();
+
+ // Legacy custom type, registered with "add_custom_type()".
+ if (custom_type_name.is_empty()) {
+ const EditorData::CustomType *custom_type = get_editor_data()->get_custom_type_by_path(ct_scr->get_path());
+ if (custom_type) {
+ custom_type_name = custom_type->name;
+ } else {
+ custom_type_name = TTR("<unknown>");
+ }
+ }
+
+ WARN_PRINT_ED(vformat("Script does not extend type: '%s'.", custom_type_name));
+ return;
+ }
+ }
+
undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, n);
undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", n);
undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n);
@@ -3649,6 +3710,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
Ref<Script> existing_script;
bool existing_script_removable = true;
+ bool allow_attach_new_script = true;
if (selection.size() == 1) {
Node *selected = selection.front()->get();
@@ -3672,6 +3734,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (EditorNode::get_singleton()->get_object_custom_type_base(selected) == existing_script) {
existing_script_removable = false;
}
+
+ if (selected->has_meta(SceneStringName(_custom_type_script))) {
+ allow_attach_new_script = false;
+ }
}
if (profile_allow_editing) {
@@ -3692,7 +3758,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (full_selection.size() == 1) {
add_separator = true;
- menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ScriptCreate")), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
+ if (allow_attach_new_script) {
+ menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ScriptCreate")), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
+ }
+
if (existing_script.is_valid()) {
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ScriptExtend")), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT);
}
@@ -4269,7 +4338,7 @@ void SceneTreeDock::_update_create_root_dialog(bool p_initializing) {
if (ScriptServer::is_global_class(name)) {
name = ScriptServer::get_global_class_native_base(name);
}
- button->set_icon(EditorNode::get_singleton()->get_class_icon(name));
+ button->set_button_icon(EditorNode::get_singleton()->get_class_icon(name));
button->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_favorite_root_selected).bind(l));
}
}
@@ -4601,6 +4670,14 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
filter_hbc->add_child(button_detach_script);
button_detach_script->hide();
+ button_extend_script = memnew(Button);
+ button_extend_script->set_flat(true);
+ button_extend_script->connect(SceneStringName(pressed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_EXTEND_SCRIPT, false));
+ button_extend_script->set_tooltip_text(TTR("Extend the script of the selected node."));
+ button_extend_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/extend_script"));
+ filter_hbc->add_child(button_extend_script);
+ button_extend_script->hide();
+
button_tree_menu = memnew(MenuButton);
button_tree_menu->set_flat(false);
button_tree_menu->set_theme_type_variation("FlatMenuButton");
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 05ad0f36e4..8cee2870f6 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -115,6 +115,7 @@ class SceneTreeDock : public VBoxContainer {
Button *button_instance = nullptr;
Button *button_create_script = nullptr;
Button *button_detach_script = nullptr;
+ Button *button_extend_script = nullptr;
MenuButton *button_tree_menu = nullptr;
Button *node_shortcuts_toggle = nullptr;
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 0cb4952b04..8dd2fe8e4e 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -135,9 +135,9 @@ void ScriptCreateDialog::_notification(int p_what) {
}
}
- path_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
- parent_browse_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
- parent_search_button->set_icon(get_editor_theme_icon(SNAME("ClassList")));
+ path_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));
+ parent_browse_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));
+ parent_search_button->set_button_icon(get_editor_theme_icon(SNAME("ClassList")));
} break;
}
}
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index 846e8867a1..2bfe088e7f 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -74,7 +74,7 @@ void ShaderCreateDialog::_notification(int p_what) {
}
}
- path_button->set_icon(get_editor_theme_icon(SNAME("Folder")));
+ path_button->set_button_icon(get_editor_theme_icon(SNAME("Folder")));
} break;
}
}
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 85e5cd6ea0..a53b621097 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -438,7 +438,7 @@ void ShaderGlobalsEditor::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
- variable_add->set_icon(get_editor_theme_icon(SNAME("Add")));
+ variable_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
case NOTIFICATION_PREDELETE: {
diff --git a/editor/surface_upgrade_tool.h b/editor/surface_upgrade_tool.h
index 59745250e4..130c49dcac 100644
--- a/editor/surface_upgrade_tool.h
+++ b/editor/surface_upgrade_tool.h
@@ -54,9 +54,9 @@ protected:
static void _bind_methods();
public:
- static SurfaceUpgradeTool *get_singleton() { return singleton; };
+ static SurfaceUpgradeTool *get_singleton() { return singleton; }
- bool is_show_requested() const { return show_requested; };
+ bool is_show_requested() const { return show_requested; }
void show_popup() { _show_popup(); }
void prepare_upgrade();
diff --git a/editor/themes/editor_color_map.cpp b/editor/themes/editor_color_map.cpp
index 9046a8b688..3c3d755586 100644
--- a/editor/themes/editor_color_map.cpp
+++ b/editor/themes/editor_color_map.cpp
@@ -173,6 +173,8 @@ void EditorColorMap::create() {
add_conversion_exception("OverbrightIndicator");
add_conversion_exception("MaterialPreviewCube");
add_conversion_exception("MaterialPreviewSphere");
+ add_conversion_exception("MaterialPreviewQuad");
+
add_conversion_exception("MaterialPreviewLight1");
add_conversion_exception("MaterialPreviewLight2");
diff --git a/editor/themes/editor_color_map.h b/editor/themes/editor_color_map.h
index c1176749f2..fba39f249e 100644
--- a/editor/themes/editor_color_map.h
+++ b/editor/themes/editor_color_map.h
@@ -50,8 +50,8 @@ public:
static void add_conversion_color_pair(const String &p_from_color, const String &p_to_color);
static void add_conversion_exception(const StringName &p_icon_name);
- static HashMap<Color, Color> &get_color_conversion_map() { return color_conversion_map; };
- static HashSet<StringName> &get_color_conversion_exceptions() { return color_conversion_exceptions; };
+ static HashMap<Color, Color> &get_color_conversion_map() { return color_conversion_map; }
+ static HashSet<StringName> &get_color_conversion_exceptions() { return color_conversion_exceptions; }
static void create();
static void finish();
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index cdc4087142..32079f3753 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -633,6 +633,16 @@ void EditorThemeManager::_create_shared_styles(const Ref<EditorTheme> &p_theme,
// in 4.0, and even if it was, it may not always work in practice (e.g. running with compositing disabled).
p_config.popup_style->set_corner_radius_all(0);
+ p_config.popup_border_style = p_config.popup_style->duplicate();
+ p_config.popup_border_style->set_content_margin_all(MAX(Math::round(EDSCALE), p_config.border_width) + 2 + (p_config.base_margin * 1.5) * EDSCALE);
+ // Always display a border for popups like PopupMenus so they can be distinguished from their background.
+ p_config.popup_border_style->set_border_width_all(MAX(Math::round(EDSCALE), p_config.border_width));
+ if (p_config.draw_extra_borders) {
+ p_config.popup_border_style->set_border_color(p_config.extra_border_color_2);
+ } else {
+ p_config.popup_border_style->set_border_color(p_config.dark_color_2);
+ }
+
p_config.window_style = p_config.popup_style->duplicate();
p_config.window_style->set_border_color(p_config.base_color);
p_config.window_style->set_border_width(SIDE_TOP, 24 * EDSCALE);
@@ -707,7 +717,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
}
// PopupPanel
- p_theme->set_stylebox(SceneStringName(panel), "PopupPanel", p_config.popup_style);
+ p_theme->set_stylebox(SceneStringName(panel), "PopupPanel", p_config.popup_border_style);
}
// Buttons.
@@ -1314,18 +1324,11 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
// PopupMenu.
{
- Ref<StyleBoxFlat> style_popup_menu = p_config.popup_style->duplicate();
+ Ref<StyleBoxFlat> style_popup_menu = p_config.popup_border_style->duplicate();
// 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_content_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);
- if (p_config.draw_extra_borders) {
- style_popup_menu->set_border_color(p_config.extra_border_color_2);
- } else {
- style_popup_menu->set_border_color(p_config.dark_color_2);
- }
+ style_popup_menu->set_content_margin_individual(Math::round(EDSCALE), 2 * EDSCALE, Math::round(EDSCALE), 2 * EDSCALE);
p_theme->set_stylebox(SceneStringName(panel), "PopupMenu", style_popup_menu);
Ref<StyleBoxFlat> style_menu_hover = p_config.button_style_hover->duplicate();
@@ -1335,17 +1338,17 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
Ref<StyleBoxLine> style_popup_separator(memnew(StyleBoxLine));
style_popup_separator->set_color(p_config.separator_color);
- style_popup_separator->set_grow_begin(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width));
- style_popup_separator->set_grow_end(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width));
+ style_popup_separator->set_grow_begin(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width));
+ style_popup_separator->set_grow_end(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width));
style_popup_separator->set_thickness(MAX(Math::round(EDSCALE), p_config.border_width));
Ref<StyleBoxLine> style_popup_labeled_separator_left(memnew(StyleBoxLine));
- style_popup_labeled_separator_left->set_grow_begin(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width));
+ style_popup_labeled_separator_left->set_grow_begin(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width));
style_popup_labeled_separator_left->set_color(p_config.separator_color);
style_popup_labeled_separator_left->set_thickness(MAX(Math::round(EDSCALE), p_config.border_width));
Ref<StyleBoxLine> style_popup_labeled_separator_right(memnew(StyleBoxLine));
- style_popup_labeled_separator_right->set_grow_end(p_config.popup_margin - MAX(Math::round(EDSCALE), p_config.border_width));
+ style_popup_labeled_separator_right->set_grow_end(Math::round(EDSCALE) - MAX(Math::round(EDSCALE), p_config.border_width));
style_popup_labeled_separator_right->set_color(p_config.separator_color);
style_popup_labeled_separator_right->set_thickness(MAX(Math::round(EDSCALE), p_config.border_width));
@@ -1854,6 +1857,12 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
p_theme->set_stylebox("ScriptEditorPanelFloating", EditorStringName(EditorStyles), make_empty_stylebox(0, 0, 0, 0));
p_theme->set_stylebox("ScriptEditor", EditorStringName(EditorStyles), make_empty_stylebox(0, 0, 0, 0));
+ // Game view.
+ p_theme->set_type_variation("GamePanel", "Panel");
+ Ref<StyleBoxFlat> game_panel = p_theme->get_stylebox(SNAME("panel"), SNAME("Panel"))->duplicate();
+ game_panel->set_corner_radius_all(0);
+ p_theme->set_stylebox(SceneStringName(panel), "GamePanel", game_panel);
+
// Main menu.
Ref<StyleBoxFlat> menu_transparent_style = p_config.button_style->duplicate();
menu_transparent_style->set_bg_color(Color(1, 1, 1, 0));
@@ -2123,21 +2132,6 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
// EditorValidationPanel.
p_theme->set_stylebox(SceneStringName(panel), "EditorValidationPanel", p_config.tree_panel_style);
-
- // ControlEditor.
- {
- p_theme->set_type_variation("ControlEditorPopupPanel", "PopupPanel");
-
- Ref<StyleBoxFlat> control_editor_popup_style = p_config.popup_style->duplicate();
- control_editor_popup_style->set_shadow_size(0);
- control_editor_popup_style->set_content_margin(SIDE_LEFT, p_config.base_margin * EDSCALE);
- control_editor_popup_style->set_content_margin(SIDE_TOP, p_config.base_margin * EDSCALE);
- control_editor_popup_style->set_content_margin(SIDE_RIGHT, p_config.base_margin * EDSCALE);
- control_editor_popup_style->set_content_margin(SIDE_BOTTOM, p_config.base_margin * EDSCALE);
- control_editor_popup_style->set_border_width_all(0);
-
- p_theme->set_stylebox(SceneStringName(panel), "ControlEditorPopupPanel", control_editor_popup_style);
- }
}
// Editor inspector.
diff --git a/editor/themes/editor_theme_manager.h b/editor/themes/editor_theme_manager.h
index 5e7bd00083..ca5e1a4e2d 100644
--- a/editor/themes/editor_theme_manager.h
+++ b/editor/themes/editor_theme_manager.h
@@ -135,6 +135,7 @@ class EditorThemeManager {
Ref<StyleBoxFlat> button_style_hover;
Ref<StyleBoxFlat> popup_style;
+ Ref<StyleBoxFlat> popup_border_style;
Ref<StyleBoxFlat> window_style;
Ref<StyleBoxFlat> dialog_style;
Ref<StyleBoxFlat> panel_container_style;
diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp
index 9496ba016c..3256680416 100644
--- a/editor/window_wrapper.cpp
+++ b/editor/window_wrapper.cpp
@@ -390,8 +390,7 @@ void ScreenSelect::_notification(int p_what) {
connect(SceneStringName(gui_input), callable_mp(this, &ScreenSelect::_handle_mouse_shortcut));
} break;
case NOTIFICATION_THEME_CHANGED: {
- set_icon(get_editor_theme_icon("MakeFloating"));
- popup_background->add_theme_style_override(SceneStringName(panel), get_theme_stylebox("PanelForeground", EditorStringName(EditorStyles)));
+ set_button_icon(get_editor_theme_icon("MakeFloating"));
const real_t popup_height = real_t(get_theme_font_size(SceneStringName(font_size))) * 2.0;
popup->set_min_size(Size2(0, popup_height * 3));
@@ -454,14 +453,10 @@ ScreenSelect::ScreenSelect() {
// Create the popup.
const Size2 borders = Size2(4, 4) * EDSCALE;
- popup = memnew(Popup);
+ popup = memnew(PopupPanel);
popup->connect("popup_hide", callable_mp(static_cast<BaseButton *>(this), &ScreenSelect::set_pressed).bind(false));
add_child(popup);
- popup_background = memnew(Panel);
- popup_background->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
- popup->add_child(popup_background);
-
MarginContainer *popup_root = memnew(MarginContainer);
popup_root->add_theme_constant_override("margin_right", borders.width);
popup_root->add_theme_constant_override("margin_top", borders.height);
diff --git a/editor/window_wrapper.h b/editor/window_wrapper.h
index a07e95f09e..3597276de9 100644
--- a/editor/window_wrapper.h
+++ b/editor/window_wrapper.h
@@ -88,7 +88,6 @@ class ScreenSelect : public Button {
GDCLASS(ScreenSelect, Button);
Popup *popup = nullptr;
- Panel *popup_background = nullptr;
HBoxContainer *screen_list = nullptr;
void _build_advanced_menu();