diff options
Diffstat (limited to 'editor')
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 ®_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 ®_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 ®_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 ®_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(); |