diff options
Diffstat (limited to 'editor')
152 files changed, 6448 insertions, 3383 deletions
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 648e950fd4..7cfedffcbf 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -732,9 +732,9 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { store_command_checkbox->set_pressed(true); store_command_checkbox->set_text(TTR("Store Command")); #ifdef APPLE_STYLE_KEYS - store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'meta'. Used for compatibility with Windows/Linux style keyboard.")); + store_command_checkbox->set_tooltip_text(TTR("Toggles between serializing 'command' and 'meta'. Used for compatibility with Windows/Linux style keyboard.")); #else - store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'control'. Used for compatibility with Apple Style keyboards.")); + store_command_checkbox->set_tooltip_text(TTR("Toggles between serializing 'command' and 'control'. Used for compatibility with Apple Style keyboards.")); #endif mod_container->add_child(store_command_checkbox); @@ -745,7 +745,7 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { physical_key_checkbox = memnew(CheckBox); physical_key_checkbox->set_text(TTR("Use Physical Keycode")); - physical_key_checkbox->set_tooltip(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications.")); + physical_key_checkbox->set_tooltip_text(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications.")); physical_key_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_physical_keycode_toggled)); physical_key_checkbox->hide(); additional_options_container->add_child(physical_key_checkbox); @@ -805,7 +805,7 @@ String ActionMapEditor::_check_new_action_name(const String &p_name) { void ActionMapEditor::_add_edit_text_changed(const String &p_name) { String error = _check_new_action_name(p_name); - add_button->set_tooltip(error); + add_button->set_tooltip_text(error); add_button->set_disabled(!error.is_empty()); } diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 9af8b907c4..0183d08733 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -648,7 +648,7 @@ void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_a animation = p_animation; read_only = p_read_only; selected_track = p_track; - update(); + queue_redraw(); } Size2 AnimationBezierTrackEdit::get_minimum_size() const { @@ -691,11 +691,11 @@ void AnimationBezierTrackEdit::_play_position_draw() { void AnimationBezierTrackEdit::set_play_position(real_t p_pos) { play_position_pos = p_pos; - play_position->update(); + play_position->queue_redraw(); } void AnimationBezierTrackEdit::update_play_position() { - play_position->update(); + play_position->queue_redraw(); } void AnimationBezierTrackEdit::set_root(Node *p_root) { @@ -734,12 +734,12 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) { } } } - update(); + queue_redraw(); } void AnimationBezierTrackEdit::_zoom_changed() { - update(); - play_position->update(); + queue_redraw(); + play_position->queue_redraw(); } void AnimationBezierTrackEdit::_update_locked_tracks_after(int p_track) { @@ -787,7 +787,7 @@ String AnimationBezierTrackEdit::get_tooltip(const Point2 &p_pos) const { void AnimationBezierTrackEdit::_clear_selection() { selection.clear(); emit_signal(SNAME("clear_selection")); - update(); + queue_redraw(); } void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) { @@ -819,7 +819,7 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int selection.insert(IntPair(p_track, idx)); emit_signal(SNAME("select_key"), idx, true, p_track); - update(); + queue_redraw(); } void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { @@ -909,7 +909,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { v_scroll = (maximum_value + minimum_value) / 2.0; v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9); - update(); + queue_redraw(); accept_event(); return; } else if (ED_GET_SHORTCUT("animation_bezier_editor/select_all_keys")->matches_event(p_event)) { @@ -917,13 +917,13 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { selection.insert(IntPair(edit_points[i].track, edit_points[i].key)); } - update(); + queue_redraw(); accept_event(); return; } else if (ED_GET_SHORTCUT("animation_bezier_editor/deselect_all_keys")->matches_event(p_event)) { selection.clear(); - update(); + queue_redraw(); accept_event(); return; } @@ -1024,7 +1024,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } } } - update(); + queue_redraw(); return; } else if (I.key == VISIBILITY_ICON) { if (hidden_tracks.has(track)) { @@ -1054,7 +1054,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { solo_track = -1; } - update(); + queue_redraw(); return; } else if (I.key == SOLO_ICON) { if (solo_track == track) { @@ -1076,7 +1076,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { set_animation_and_track(animation, track, read_only); solo_track = track; } - update(); + queue_redraw(); return; } return; @@ -1098,7 +1098,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } else { selection.insert(pair); } - update(); + queue_redraw(); select_single_attempt = IntPair(-1, -1); } else if (selection.has(pair)) { moving_selection_attempt = true; @@ -1110,7 +1110,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second); moving_selection_offset = Vector2(); select_single_attempt = pair; - update(); + queue_redraw(); } else { moving_selection_attempt = true; moving_selection = true; @@ -1135,7 +1135,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_handle_track = edit_points[i].track; moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key); moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key); - update(); + queue_redraw(); return; } @@ -1145,7 +1145,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_handle_track = edit_points[i].track; moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key); moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key); - update(); + queue_redraw(); return; } } @@ -1186,7 +1186,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_selection_from_track = selected_track; moving_selection_offset = Vector2(); select_single_attempt = IntPair(-1, -1); - update(); + queue_redraw(); return; } @@ -1258,7 +1258,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { box_selecting_attempt = false; box_selecting = false; - update(); + queue_redraw(); } if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { @@ -1376,7 +1376,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } moving_selection_attempt = false; - update(); + queue_redraw(); } } @@ -1397,7 +1397,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { additional_moving_handle_lefts.clear(); additional_moving_handle_rights.clear(); - update(); + queue_redraw(); } if (box_selecting_attempt && mm.is_valid()) { @@ -1412,7 +1412,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { //avoid cursor from going too above, so it does not lose focus with viewport warp_mouse(Vector2(get_local_mouse_position().x, 0)); } - update(); + queue_redraw(); } if ((moving_handle == 1 || moving_handle == -1) && mm.is_valid()) { @@ -1461,7 +1461,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_handle_left = -moving_handle_right; } } - update(); + queue_redraw(); } if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { @@ -1478,7 +1478,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } undo_redo->commit_action(); moving_handle = 0; - update(); + queue_redraw(); } } } @@ -1491,7 +1491,7 @@ void AnimationBezierTrackEdit::_pan_callback(Vector2 p_scroll_vec) { v_scroll += p_scroll_vec.y * v_zoom; v_scroll = CLAMP(v_scroll, -100000, 100000); timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale()); - update(); + queue_redraw(); } void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { @@ -1511,7 +1511,7 @@ void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_or } } v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig); - update(); + queue_redraw(); } void AnimationBezierTrackEdit::_menu_selected(int p_index) { @@ -1541,7 +1541,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time); undo_redo->commit_action(); - update(); + queue_redraw(); } } break; case MENU_KEY_DUPLICATE: { @@ -1624,7 +1624,7 @@ void AnimationBezierTrackEdit::duplicate_selection() { selection.insert(IntPair(track, existing_idx)); } - update(); + queue_redraw(); } void AnimationBezierTrackEdit::delete_selection() { diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index ddce4f8a36..4991b2cfaf 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1399,8 +1399,8 @@ public: }; void AnimationTimelineEdit::_zoom_changed(double) { - update(); - play_position->update(); + queue_redraw(); + play_position->queue_redraw(); emit_signal(SNAME("zoom_changed")); } @@ -1430,7 +1430,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) { undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length()); undo_redo->commit_action(); editing = false; - update(); + queue_redraw(); emit_signal(SNAME("length_changed"), p_new_len); } @@ -1703,7 +1703,7 @@ void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, boo add_track->hide(); play_position->hide(); } - update(); + queue_redraw(); update_values(); } @@ -1731,7 +1731,7 @@ void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) { void AnimationTimelineEdit::set_play_position(float p_pos) { play_position_pos = p_pos; - play_position->update(); + play_position->queue_redraw(); } float AnimationTimelineEdit::get_play_position() const { @@ -1739,7 +1739,7 @@ float AnimationTimelineEdit::get_play_position() const { } void AnimationTimelineEdit::update_play_position() { - play_position->update(); + play_position->queue_redraw(); } void AnimationTimelineEdit::update_values() { @@ -1751,13 +1751,13 @@ void AnimationTimelineEdit::update_values() { if (use_fps && animation->get_step() > 0) { length->set_value(animation->get_length() / animation->get_step()); length->set_step(1); - length->set_tooltip(TTR("Animation length (frames)")); - time_icon->set_tooltip(TTR("Animation length (frames)")); + length->set_tooltip_text(TTR("Animation length (frames)")); + time_icon->set_tooltip_text(TTR("Animation length (frames)")); } else { length->set_value(animation->get_length()); length->set_step(0.001); - length->set_tooltip(TTR("Animation length (seconds)")); - time_icon->set_tooltip(TTR("Animation length (seconds)")); + length->set_tooltip_text(TTR("Animation length (seconds)")); + time_icon->set_tooltip_text(TTR("Animation length (seconds)")); } switch (animation->get_loop_mode()) { @@ -1853,9 +1853,9 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) { if (dragging_hsize) { int ofs = mm->get_position().x - dragging_hsize_from; name_limit = dragging_hsize_at + ofs; - update(); + queue_redraw(); emit_signal(SNAME("name_limit_changed")); - play_position->update(); + play_position->queue_redraw(); } if (dragging_timeline) { int x = mm->get_position().x - get_name_limit(); @@ -1898,7 +1898,7 @@ void AnimationTimelineEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origi void AnimationTimelineEdit::set_use_fps(bool p_use_fps) { use_fps = p_use_fps; update_values(); - update(); + queue_redraw(); } bool AnimationTimelineEdit::is_using_fps() const { @@ -1942,7 +1942,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() { len_hb->add_child(expander); time_icon = memnew(TextureRect); time_icon->set_v_size_flags(SIZE_SHRINK_CENTER); - time_icon->set_tooltip(TTR("Animation length (seconds)")); + time_icon->set_tooltip_text(TTR("Animation length (seconds)")); len_hb->add_child(time_icon); length = memnew(EditorSpinSlider); length->set_min(0.001); @@ -1951,12 +1951,12 @@ AnimationTimelineEdit::AnimationTimelineEdit() { length->set_allow_greater(true); length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0)); length->set_hide_slider(true); - length->set_tooltip(TTR("Animation length (seconds)")); + length->set_tooltip_text(TTR("Animation length (seconds)")); length->connect("value_changed", callable_mp(this, &AnimationTimelineEdit::_anim_length_changed)); len_hb->add_child(length); loop = memnew(Button); loop->set_flat(true); - loop->set_tooltip(TTR("Animation Looping")); + loop->set_tooltip_text(TTR("Animation Looping")); loop->connect("pressed", callable_mp(this, &AnimationTimelineEdit::_anim_loop_pressed)); loop->set_toggle_mode(true); len_hb->add_child(loop); @@ -2122,10 +2122,12 @@ void AnimationTrackEdit::_notification(int p_what) { get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), }; - Ref<Texture2D> interp_icon[3] = { + Ref<Texture2D> interp_icon[5] = { get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), + get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), + get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), }; Ref<Texture2D> cont_icon[4] = { get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), @@ -2290,13 +2292,13 @@ void AnimationTrackEdit::_notification(int p_what) { case NOTIFICATION_MOUSE_ENTER: hovered = true; - update(); + queue_redraw(); break; case NOTIFICATION_MOUSE_EXIT: hovered = false; // When the mouse cursor exits the track, we're no longer hovering any keyframe. hovering_key_idx = -1; - update(); + queue_redraw(); [[fallthrough]]; case NOTIFICATION_DRAG_END: { cancel_drop(); @@ -2489,7 +2491,7 @@ void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animati read_only = p_read_only; track = p_track; - update(); + queue_redraw(); ERR_FAIL_INDEX(track, animation->get_track_count()); @@ -2551,11 +2553,11 @@ void AnimationTrackEdit::_play_position_draw() { void AnimationTrackEdit::set_play_position(float p_pos) { play_position_pos = p_pos; - play_position->update(); + play_position->queue_redraw(); } void AnimationTrackEdit::update_play_position() { - play_position->update(); + play_position->queue_redraw(); } void AnimationTrackEdit::set_root(Node *p_root) { @@ -2563,8 +2565,8 @@ void AnimationTrackEdit::set_root(Node *p_root) { } void AnimationTrackEdit::_zoom_changed() { - update(); - play_position->update(); + queue_redraw(); + play_position->queue_redraw(); } void AnimationTrackEdit::_path_submitted(const String &p_text) { @@ -2809,7 +2811,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track)); undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track)); undo_redo->commit_action(); - update(); + queue_redraw(); accept_event(); } @@ -2848,6 +2850,23 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST); menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR); menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC); + // Check is angle property. + AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton(); + if (ape) { + AnimationPlayer *ap = ape->get_player(); + if (ap) { + NodePath path = animation->track_get_path(track); + Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(path.get_concatenated_names())); + StringName prop = path.get_concatenated_subnames(); + PropertyInfo prop_info; + ClassDB::get_property_info(nd->get_class(), prop, &prop_info); + bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1; + if (is_angle) { + menu->add_icon_item(get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE); + menu->add_icon_item(get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE); + } + } + } menu->reset_size(); Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height); @@ -3071,7 +3090,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (hovering_key_idx != previous_hovering_key_idx) { // Required to draw keyframe hover feedback on the correct keyframe. - update(); + queue_redraw(); } } } @@ -3137,7 +3156,7 @@ bool AnimationTrackEdit::can_drop_data(const Point2 &p_point, const Variant &p_d dropping_at = 1; } - const_cast<AnimationTrackEdit *>(this)->update(); + const_cast<AnimationTrackEdit *>(this)->queue_redraw(); const_cast<AnimationTrackEdit *>(this)->emit_signal(SNAME("drop_attempted"), track); return true; @@ -3183,18 +3202,20 @@ void AnimationTrackEdit::_menu_selected(int p_index) { undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", track, update_mode); undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", track, animation->value_track_get_update_mode(track)); undo_redo->commit_action(); - update(); + queue_redraw(); } break; case MENU_INTERPOLATION_NEAREST: case MENU_INTERPOLATION_LINEAR: - case MENU_INTERPOLATION_CUBIC: { + case MENU_INTERPOLATION_CUBIC: + case MENU_INTERPOLATION_LINEAR_ANGLE: + case MENU_INTERPOLATION_CUBIC_ANGLE: { Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST); undo_redo->create_action(TTR("Change Animation Interpolation Mode")); undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode); undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", track, animation->track_get_interpolation_type(track)); undo_redo->commit_action(); - update(); + queue_redraw(); } break; case MENU_LOOP_WRAP: case MENU_LOOP_CLAMP: { @@ -3203,7 +3224,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) { undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, loop_wrap); undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, animation->track_get_interpolation_loop_wrap(track)); undo_redo->commit_action(); - update(); + queue_redraw(); } break; case MENU_KEY_INSERT: { @@ -3226,13 +3247,13 @@ void AnimationTrackEdit::_menu_selected(int p_index) { void AnimationTrackEdit::cancel_drop() { if (dropping_at != 0) { dropping_at = 0; - update(); + queue_redraw(); } } void AnimationTrackEdit::set_in_group(bool p_enable) { in_group = p_enable; - update(); + queue_redraw(); } void AnimationTrackEdit::append_to_selection(const Rect2 &p_box, bool p_deselection) { @@ -3378,7 +3399,7 @@ void AnimationTrackEditGroup::set_type_and_name(const Ref<Texture2D> &p_type, co icon = p_type; node_name = p_name; node = p_node; - update(); + queue_redraw(); update_minimum_size(); } @@ -3398,11 +3419,11 @@ void AnimationTrackEditGroup::set_timeline(AnimationTimelineEdit *p_timeline) { void AnimationTrackEditGroup::set_root(Node *p_root) { root = p_root; - update(); + queue_redraw(); } void AnimationTrackEditGroup::_zoom_changed() { - update(); + queue_redraw(); } void AnimationTrackEditGroup::_bind_methods() { @@ -3579,9 +3600,7 @@ void AnimationTrackEditor::cleanup() { } void AnimationTrackEditor::_name_limit_changed() { - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } + _redraw_tracks(); } void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only) { @@ -3676,9 +3695,7 @@ void AnimationTrackEditor::set_anim_pos(float p_pos) { for (int i = 0; i < track_edits.size(); i++) { track_edits[i]->set_play_position(p_pos); } - for (int i = 0; i < groups.size(); i++) { - groups[i]->update(); - } + _redraw_groups(); bezier_edit->set_play_position(p_pos); } @@ -4579,7 +4596,7 @@ void AnimationTrackEditor::_update_tracks() { g->set_type_and_name(icon, name, animation->track_get_path(i)); g->set_root(root); - g->set_tooltip(tooltip); + g->set_tooltip_text(tooltip); g->set_timeline(timeline); groups.push_back(g); VBoxContainer *vb = memnew(VBoxContainer); @@ -4626,8 +4643,20 @@ void AnimationTrackEditor::_update_tracks() { } } +void AnimationTrackEditor::_redraw_tracks() { + for (int i = 0; i < track_edits.size(); i++) { + track_edits[i]->queue_redraw(); + } +} + +void AnimationTrackEditor::_redraw_groups() { + for (int i = 0; i < groups.size(); i++) { + groups[i]->queue_redraw(); + } +} + void AnimationTrackEditor::_sync_animation_change() { - bezier_edit->update(); + bezier_edit->queue_redraw(); } void AnimationTrackEditor::_animation_changed() { @@ -4640,12 +4669,12 @@ void AnimationTrackEditor::_animation_changed() { } if (key_edit && key_edit->setting) { - // If editing a key, just update the edited track, makes refresh less costly. + // If editing a key, just redraw the edited track, makes refresh less costly. if (key_edit->track < track_edits.size()) { if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER) { - bezier_edit->update(); + bezier_edit->queue_redraw(); } else { - track_edits[key_edit->track]->update(); + track_edits[key_edit->track]->queue_redraw(); } } return; @@ -4684,7 +4713,7 @@ void AnimationTrackEditor::_update_step_spinbox() { } void AnimationTrackEditor::_animation_update() { - timeline->update(); + timeline->queue_redraw(); timeline->update_values(); bool same = true; @@ -4707,17 +4736,13 @@ void AnimationTrackEditor::_animation_update() { } if (same) { - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } - for (int i = 0; i < groups.size(); i++) { - groups[i]->update(); - } + _redraw_tracks(); + _redraw_groups(); } else { _update_tracks(); } - bezier_edit->update(); + bezier_edit->queue_redraw(); _update_step_spinbox(); emit_signal(SNAME("animation_step_changed"), animation->get_step()); @@ -4762,12 +4787,8 @@ void AnimationTrackEditor::_notification(int p_what) { } void AnimationTrackEditor::_update_scroll(double) { - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } - for (int i = 0; i < groups.size(); i++) { - groups[i]->update(); - } + _redraw_tracks(); + _redraw_groups(); } void AnimationTrackEditor::_update_step(double p_new_step) { @@ -4795,7 +4816,7 @@ void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) { return; } - _clear_selection(); + _clear_selection(true); undo_redo->create_action(TTR("Rearrange Tracks")); undo_redo->add_do_method(animation.ptr(), "track_move_to", p_from_track, p_to_track); // Take into account that the position of the tracks that come after the one removed will change. @@ -4973,16 +4994,13 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) { void AnimationTrackEditor::_timeline_value_changed(double) { timeline->update_play_position(); + _redraw_tracks(); for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); track_edits[i]->update_play_position(); } + _redraw_groups(); - for (int i = 0; i < groups.size(); i++) { - groups[i]->update(); - } - - bezier_edit->update(); + bezier_edit->queue_redraw(); bezier_edit->update_play_position(); } @@ -5191,10 +5209,7 @@ void AnimationTrackEditor::_key_selected(int p_key, bool p_single, int p_track) ki.pos = animation->track_get_key_time(p_track, p_key); selection[sk] = ki; - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } - + _redraw_tracks(); _update_key_edit(); } @@ -5208,10 +5223,7 @@ void AnimationTrackEditor::_key_deselected(int p_key, int p_track) { selection.erase(sk); - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } - + _redraw_tracks(); _update_key_edit(); } @@ -5222,10 +5234,7 @@ void AnimationTrackEditor::_move_selection_begin() { void AnimationTrackEditor::_move_selection(float p_offset) { moving_selection_offset = p_offset; - - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } + _redraw_tracks(); } struct _AnimMoveRestore { @@ -5262,9 +5271,7 @@ void AnimationTrackEditor::_clear_selection(bool p_update) { selection.clear(); if (p_update) { - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } + _redraw_tracks(); } _clear_key_edit(); @@ -5422,21 +5429,16 @@ void AnimationTrackEditor::_move_selection_commit() { undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos); } - undo_redo->commit_action(); - moving_selection = false; - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } - + undo_redo->add_do_method(this, "_redraw_tracks"); + undo_redo->add_undo_method(this, "_redraw_tracks"); + undo_redo->commit_action(); _update_key_edit(); } void AnimationTrackEditor::_move_selection_cancel() { moving_selection = false; - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } + _redraw_tracks(); } bool AnimationTrackEditor::is_moving_selection() const { @@ -5479,7 +5481,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) { track_edits[track_edits.size() - 1]->grab_focus(); } } else { - _clear_selection(); // Clear it. + _clear_selection(true); // Clear it. } box_selection->hide(); @@ -5499,7 +5501,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) { if (!box_selection->is_visible_in_tree()) { if (!mm->is_command_pressed() && !mm->is_shift_pressed()) { - _clear_selection(); + _clear_selection(true); } box_selection->show(); } @@ -5646,32 +5648,21 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { } } - undo_redo->commit_action(); + undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); // Reselect duplicated. - RBMap<SelectedKey, KeyInfo> new_selection; for (const Pair<int, float> &E : new_selection_values) { - int track = E.first; - float time = E.second; - - int existing_idx = animation->track_find_key(track, time, true); - - if (existing_idx == -1) { - continue; - } - SelectedKey sk2; - sk2.track = track; - sk2.key = existing_idx; - - KeyInfo ki; - ki.pos = time; - - new_selection[sk2] = ki; + undo_redo->add_do_method(this, "_select_at_anim", animation, E.first, E.second); + } + for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { + undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, E->get().pos); } - selection = new_selection; - _update_tracks(); + undo_redo->add_do_method(this, "_redraw_tracks"); + undo_redo->add_undo_method(this, "_redraw_tracks"); + undo_redo->commit_action(); _update_key_edit(); } } @@ -5992,7 +5983,12 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos); } #undef NEW_POS + + undo_redo->add_do_method(this, "_redraw_tracks"); + undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); + _update_key_edit(); + } break; case EDIT_EASE_SELECTION: { @@ -6042,8 +6038,11 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { Vector<int> keys = E->value; int len = keys.size() - 1; + // Special case for angle interpolation. + bool is_using_angle = animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_LINEAR_ANGLE || animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_CUBIC_ANGLE; + // Make insert queue. - Vector<Pair<double, Variant>> insert_queue; + Vector<Pair<real_t, Variant>> insert_queue; for (int i = 0; i < len; i++) { // Check neighboring keys. if (keys[i] + 1 == keys[i + 1]) { @@ -6051,12 +6050,18 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { double to_t = animation->track_get_key_time(track, keys[i + 1]); Variant from_v = animation->track_get_key_value(track, keys[i]); Variant to_v = animation->track_get_key_value(track, keys[i + 1]); + if (is_using_angle) { + real_t a = from_v; + real_t b = to_v; + real_t to_diff = fmod(b - a, Math_TAU); + to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff; + } Variant delta_v; Variant::sub(to_v, from_v, delta_v); double duration = to_t - from_t; double fixed_duration = duration - 0.01; // Prevent to overwrap keys... for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) { - Pair<double, Variant> keydata; + Pair<real_t, Variant> keydata; keydata.first = from_t + delta_t; keydata.second = Tween::interpolate_variant(from_v, delta_v, delta_t, duration, transition_type, ease_type); insert_queue.append(keydata); @@ -6073,7 +6078,12 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { ++E; } + undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_do_method(this, "_redraw_tracks"); + undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); + _update_key_edit(); } break; @@ -6093,6 +6103,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case EDIT_ADD_RESET_KEY: { undo_redo->create_action(TTR("Anim Add RESET Keys")); + Ref<Animation> reset = _create_and_get_reset_animation(); int reset_tracks = reset->get_track_count(); HashSet<int> tracks_added; @@ -6137,6 +6148,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } } + undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_do_method(this, "_redraw_tracks"); + undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); } break; @@ -6155,6 +6170,8 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_do_method(this, "_redraw_tracks"); + undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); _update_key_edit(); } @@ -6166,6 +6183,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { case EDIT_GOTO_PREV_STEP: { goto_prev_step(false); } break; + case EDIT_APPLY_RESET: { AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true); } break; @@ -6192,17 +6210,21 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { do_bake |= b_bs && type == Animation::TYPE_BLEND_SHAPE; do_bake |= b_v && type == Animation::TYPE_VALUE; if (do_bake && !animation->track_is_compressed(i)) { - if (animation->track_get_interpolation_type(i) == Animation::INTERPOLATION_NEAREST) { - continue; // Nearest interpolation cannot be baked. + Animation::InterpolationType it = animation->track_get_interpolation_type(i); + if (it == Animation::INTERPOLATION_NEAREST) { + continue; // Nearest and Angle interpolation cannot be baked. } + // Special case for angle interpolation. + bool is_using_angle = it == Animation::INTERPOLATION_LINEAR_ANGLE || it == Animation::INTERPOLATION_CUBIC_ANGLE; + // Make insert queue. - Vector<Pair<double, Variant>> insert_queue; + Vector<Pair<real_t, Variant>> insert_queue; switch (type) { case Animation::TYPE_POSITION_3D: { for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { - Pair<double, Variant> keydata; + Pair<real_t, Variant> keydata; keydata.first = delta_t; Vector3 v; animation->position_track_interpolate(i, delta_t, &v); @@ -6212,7 +6234,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case Animation::TYPE_ROTATION_3D: { for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { - Pair<double, Variant> keydata; + Pair<real_t, Variant> keydata; keydata.first = delta_t; Quaternion v; animation->rotation_track_interpolate(i, delta_t, &v); @@ -6222,7 +6244,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case Animation::TYPE_SCALE_3D: { for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { - Pair<double, Variant> keydata; + Pair<real_t, Variant> keydata; keydata.first = delta_t; Vector3 v; animation->scale_track_interpolate(i, delta_t, &v); @@ -6232,7 +6254,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case Animation::TYPE_BLEND_SHAPE: { for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) { - Pair<double, Variant> keydata; + Pair<real_t, Variant> keydata; keydata.first = delta_t; float v; animation->blend_shape_track_interpolate(i, delta_t, &v); @@ -6242,7 +6264,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case Animation::TYPE_VALUE: { for (double delta_t = 0.0; delta_t < anim_len; delta_t += dur_step) { - Pair<double, Variant> keydata; + Pair<real_t, Variant> keydata; keydata.first = delta_t; keydata.second = animation->value_track_interpolate(i, delta_t); insert_queue.append(keydata); @@ -6259,10 +6281,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } // Insert keys. - undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, Animation::INTERPOLATION_LINEAR); + undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, is_using_angle ? Animation::INTERPOLATION_LINEAR_ANGLE : Animation::INTERPOLATION_LINEAR); for (int j = insert_queue.size() - 1; j >= 0; j--) { undo_redo->add_do_method(animation.ptr(), "track_insert_key", i, insert_queue[j].first, insert_queue[j].second); - undo_redo->add_undo_method(animation.ptr(), "track_remove_key", i, j); + undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", i, insert_queue[j].first); } // Undo methods. @@ -6273,7 +6295,12 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } } + undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_do_method(this, "_redraw_tracks"); + undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); + _update_key_edit(); } break; @@ -6283,8 +6310,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case EDIT_OPTIMIZE_ANIMATION_CONFIRM: { animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value()); - _update_tracks(); - undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id); + _redraw_tracks(); + _update_key_edit(); + undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr())); + undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this)); } break; case EDIT_CLEAN_UP_ANIMATION: { @@ -6352,7 +6381,8 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) { } } - undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id); + undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr())); + undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this)); _update_tracks(); } @@ -6374,13 +6404,8 @@ void AnimationTrackEditor::_selection_changed() { if (selected_filter->is_pressed()) { _update_tracks(); // Needs updatin. } else { - for (int i = 0; i < track_edits.size(); i++) { - track_edits[i]->update(); - } - - for (int i = 0; i < groups.size(); i++) { - groups[i]->update(); - } + _redraw_tracks(); + _redraw_groups(); } } @@ -6442,6 +6467,7 @@ void AnimationTrackEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_animation_update"), &AnimationTrackEditor::_animation_update); ClassDB::bind_method(D_METHOD("_track_grab_focus"), &AnimationTrackEditor::_track_grab_focus); ClassDB::bind_method(D_METHOD("_update_tracks"), &AnimationTrackEditor::_update_tracks); + ClassDB::bind_method(D_METHOD("_redraw_tracks"), &AnimationTrackEditor::_redraw_tracks); ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationTrackEditor::_clear_selection_for_anim); ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationTrackEditor::_select_at_anim); @@ -6601,7 +6627,7 @@ AnimationTrackEditor::AnimationTrackEditor() { imported_anim_warning = memnew(Button); imported_anim_warning->hide(); imported_anim_warning->set_text(TTR("Imported Scene")); - imported_anim_warning->set_tooltip(TTR("Warning: Editing imported animation")); + imported_anim_warning->set_tooltip_text(TTR("Warning: Editing imported animation")); imported_anim_warning->connect("pressed", callable_mp(this, &AnimationTrackEditor::_show_imported_anim_warning)); bottom_hb->add_child(imported_anim_warning); @@ -6612,7 +6638,7 @@ AnimationTrackEditor::AnimationTrackEditor() { bezier_edit_icon->set_disabled(true); bezier_edit_icon->set_toggle_mode(true); bezier_edit_icon->connect("pressed", callable_mp(this, &AnimationTrackEditor::_toggle_bezier_edit)); - bezier_edit_icon->set_tooltip(TTR("Toggle between the bezier curve editor and track editor.")); + bezier_edit_icon->set_tooltip_text(TTR("Toggle between the bezier curve editor and track editor.")); bottom_hb->add_child(bezier_edit_icon); @@ -6620,7 +6646,7 @@ AnimationTrackEditor::AnimationTrackEditor() { selected_filter->set_flat(true); selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); // Same function works the same. selected_filter->set_toggle_mode(true); - selected_filter->set_tooltip(TTR("Only show tracks from nodes selected in tree.")); + selected_filter->set_tooltip_text(TTR("Only show tracks from nodes selected in tree.")); bottom_hb->add_child(selected_filter); @@ -6628,7 +6654,7 @@ AnimationTrackEditor::AnimationTrackEditor() { view_group->set_flat(true); view_group->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); view_group->set_toggle_mode(true); - view_group->set_tooltip(TTR("Group tracks by node or display them as plain list.")); + view_group->set_tooltip_text(TTR("Group tracks by node or display them as plain list.")); bottom_hb->add_child(view_group); bottom_hb->add_child(memnew(VSeparator)); @@ -6647,7 +6673,7 @@ AnimationTrackEditor::AnimationTrackEditor() { step->set_step(0.001); step->set_hide_slider(true); step->set_custom_minimum_size(Size2(100, 0) * EDSCALE); - step->set_tooltip(TTR("Animation step value.")); + step->set_tooltip_text(TTR("Animation step value.")); bottom_hb->add_child(step); step->connect("value_changed", callable_mp(this, &AnimationTrackEditor::_update_step)); step->set_read_only(true); @@ -6679,7 +6705,7 @@ AnimationTrackEditor::AnimationTrackEditor() { edit->set_text(TTR("Edit")); edit->set_flat(false); edit->set_disabled(true); - edit->set_tooltip(TTR("Animation properties.")); + edit->set_tooltip_text(TTR("Animation properties.")); edit->get_popup()->add_item(TTR("Copy Tracks"), EDIT_COPY_TRACKS); edit->get_popup()->add_item(TTR("Paste Tracks"), EDIT_PASTE_TRACKS); edit->get_popup()->add_separator(); @@ -6701,8 +6727,8 @@ AnimationTrackEditor::AnimationTrackEditor() { edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET); edit->get_popup()->add_separator(); edit->get_popup()->add_item(TTR("Bake Animation"), EDIT_BAKE_ANIMATION); - edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION); - edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION); + edit->get_popup()->add_item(TTR("Optimize Animation (no undo)"), EDIT_OPTIMIZE_ANIMATION); + edit->get_popup()->add_item(TTR("Clean-Up Animation (no undo)"), EDIT_CLEAN_UP_ANIMATION); edit->get_popup()->connect("id_pressed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed)); edit->get_popup()->connect("about_to_popup", callable_mp(this, &AnimationTrackEditor::_edit_menu_about_to_popup)); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 025f910578..ac69b88e99 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -144,6 +144,8 @@ class AnimationTrackEdit : public Control { MENU_INTERPOLATION_NEAREST, MENU_INTERPOLATION_LINEAR, MENU_INTERPOLATION_CUBIC, + MENU_INTERPOLATION_LINEAR_ANGLE, + MENU_INTERPOLATION_CUBIC_ANGLE, MENU_LOOP_WRAP, MENU_LOOP_CLAMP, MENU_KEY_INSERT, @@ -328,6 +330,8 @@ class AnimationTrackEditor : public VBoxContainer { void _sync_animation_change(); void _animation_changed(); void _update_tracks(); + void _redraw_tracks(); + void _redraw_groups(); void _name_limit_changed(); void _timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only); @@ -500,7 +504,7 @@ class AnimationTrackEditor : public VBoxContainer { NodePath full_path; NodePath base_path; Animation::TrackType track_type = Animation::TYPE_ANIMATION; - Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC; + Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_ANGLE; Animation::UpdateMode update_mode = Animation::UPDATE_CAPTURE; Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG; bool loop_wrap = false; diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index ab64aaa24d..6499cf8df2 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -197,7 +197,7 @@ void AnimationTrackEditAudio::_preview_changed(ObjectID p_which) { Ref<AudioStream> stream = object->call("get_stream"); if (stream.is_valid() && stream->get_instance_id() == p_which) { - update(); + queue_redraw(); } } @@ -799,7 +799,7 @@ void AnimationTrackEditTypeAudio::_preview_changed(ObjectID p_which) { for (int i = 0; i < get_animation()->track_get_key_count(get_track()); i++) { Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), i); if (stream.is_valid() && stream->get_instance_id() == p_which) { - update(); + queue_redraw(); return; } } @@ -1026,7 +1026,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant get_undo_redo()->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs); get_undo_redo()->commit_action(); - update(); + queue_redraw(); return; } } @@ -1086,7 +1086,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { if (len_resizing && mm.is_valid()) { len_resizing_rel += mm->get_relative().x; len_resizing_start = mm->is_shift_pressed(); - update(); + queue_redraw(); accept_event(); return; } @@ -1097,7 +1097,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { len_resizing_start = mb->is_shift_pressed(); len_resizing_from_px = mb->get_position().x; len_resizing_rel = 0; - update(); + queue_redraw(); accept_event(); return; } @@ -1120,7 +1120,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { } len_resizing_index = -1; - update(); + queue_redraw(); accept_event(); return; } diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index bdd30dc653..2d5e70e1ff 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1092,7 +1092,7 @@ void CodeTextEditor::trim_trailing_whitespace() { if (trimed_whitespace) { text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } } @@ -1110,7 +1110,7 @@ void CodeTextEditor::insert_final_newline() { text_editor->set_line(final_line, line); text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } } @@ -1154,7 +1154,7 @@ void CodeTextEditor::convert_indent_to_spaces() { if (changed_indentation) { text_editor->set_caret_column(cursor_column); text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } } @@ -1203,7 +1203,7 @@ void CodeTextEditor::convert_indent_to_tabs() { if (changed_indentation) { text_editor->set_caret_column(cursor_column); text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } } @@ -1295,7 +1295,7 @@ void CodeTextEditor::move_lines_up() { text_editor->set_caret_line(next_id); } text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } void CodeTextEditor::move_lines_down() { @@ -1341,7 +1341,7 @@ void CodeTextEditor::move_lines_down() { text_editor->set_caret_line(next_id); } text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } void CodeTextEditor::_delete_line(int p_line) { @@ -1418,7 +1418,7 @@ void CodeTextEditor::duplicate_selection() { } text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } void CodeTextEditor::toggle_inline_comment(const String &delimiter) { @@ -1495,7 +1495,7 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) { text_editor->set_caret_column(col); } text_editor->end_complex_operation(); - text_editor->update(); + text_editor->queue_redraw(); } void CodeTextEditor::goto_line(int p_line) { @@ -1862,7 +1862,7 @@ void CodeTextEditor::update_toggle_scripts_button() { } else { toggle_scripts_button->set_icon(get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons"))); } - toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text())); + toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text())); } CodeTextEditor::CodeTextEditor() { @@ -1955,7 +1955,7 @@ CodeTextEditor::CodeTextEditor() { error_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); error_button->set_default_cursor_shape(CURSOR_POINTING_HAND); error_button->connect("pressed", callable_mp(this, &CodeTextEditor::_error_button_pressed)); - error_button->set_tooltip(TTR("Errors")); + error_button->set_tooltip_text(TTR("Errors")); set_error_count(0); // Warnings @@ -1965,14 +1965,14 @@ CodeTextEditor::CodeTextEditor() { warning_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); warning_button->set_default_cursor_shape(CURSOR_POINTING_HAND); warning_button->connect("pressed", callable_mp(this, &CodeTextEditor::_warning_button_pressed)); - warning_button->set_tooltip(TTR("Warnings")); + warning_button->set_tooltip_text(TTR("Warnings")); set_warning_count(0); // Line and column line_and_col_txt = memnew(Label); status_bar->add_child(line_and_col_txt); line_and_col_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); - line_and_col_txt->set_tooltip(TTR("Line and column numbers.")); + line_and_col_txt->set_tooltip_text(TTR("Line and column numbers.")); line_and_col_txt->set_mouse_filter(MOUSE_FILTER_STOP); text_editor->connect("gui_input", callable_mp(this, &CodeTextEditor::_text_editor_gui_input)); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index dc8a64d904..dce9ca2b93 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -460,7 +460,7 @@ ConnectDialog::ConnectDialog() { vbc_right->add_margin_child(TTR("Extra Call Arguments:"), bind_editor, true); unbind_count = memnew(SpinBox); - unbind_count->set_tooltip(TTR("Allows to drop arguments sent by signal emitter.")); + unbind_count->set_tooltip_text(TTR("Allows to drop arguments sent by signal emitter.")); unbind_count->connect("value_changed", callable_mp(this, &ConnectDialog::_unbind_count_changed)); vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count); @@ -481,13 +481,13 @@ ConnectDialog::ConnectDialog() { deferred = memnew(CheckBox); deferred->set_h_size_flags(0); deferred->set_text(TTR("Deferred")); - deferred->set_tooltip(TTR("Defers the signal, storing it in a queue and only firing it at idle time.")); + deferred->set_tooltip_text(TTR("Defers the signal, storing it in a queue and only firing it at idle time.")); vbc_right->add_child(deferred); oneshot = memnew(CheckBox); oneshot->set_h_size_flags(0); oneshot->set_text(TTR("Oneshot")); - oneshot->set_tooltip(TTR("Disconnects the signal after its first emission.")); + oneshot->set_tooltip_text(TTR("Disconnects the signal after its first emission.")); vbc_right->add_child(oneshot); cdbinds = memnew(ConnectDialogBinds); @@ -753,22 +753,12 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) { } Dictionary subst; - - String s = node_name.capitalize().replace(" ", ""); - subst["NodeName"] = s; - if (!s.is_empty()) { - s[0] = s.to_lower()[0]; - } - subst["nodeName"] = s; - subst["node_name"] = node_name.capitalize().replace(" ", "_").to_lower(); - - s = signal_name.capitalize().replace(" ", ""); - subst["SignalName"] = s; - if (!s.is_empty()) { - s[0] = s.to_lower()[0]; - } - subst["signalName"] = s; - subst["signal_name"] = signal_name.capitalize().replace(" ", "_").to_lower(); + subst["NodeName"] = node_name.to_pascal_case(); + subst["nodeName"] = node_name.to_camel_case(); + subst["node_name"] = node_name.to_snake_case(); + subst["SignalName"] = signal_name.to_pascal_case(); + subst["signalName"] = signal_name.to_camel_case(); + subst["signal_name"] = signal_name.to_snake_case(); String dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst); @@ -1070,7 +1060,7 @@ void ConnectionsDock::update_tree() { } // "::" separators used in make_custom_tooltip for formatting. - signal_item->set_tooltip(0, String(signal_name) + "::" + signaldesc + "::" + descr); + signal_item->set_tooltip_text(0, String(signal_name) + "::" + signaldesc + "::" + descr); } // List existing connections. diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index c84e8ec48f..8ccfda1145 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -313,7 +313,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String } const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description); - r_item->set_tooltip(0, description); + r_item->set_tooltip_text(0, description); if (p_type_category == TypeCategory::OTHER_TYPE && !script_type) { Ref<Texture2D> icon = EditorNode::get_editor_data().get_custom_types()[custom_type_parents[p_type]][custom_type_indices[p_type]].icon; @@ -383,7 +383,7 @@ void CreateDialog::_confirmed() { } { - Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("create_recent." + base_type), FileAccess::WRITE); if (f.is_valid()) { f->store_line(selected_item); @@ -660,7 +660,7 @@ void CreateDialog::_save_and_update_favorite_list() { TreeItem *root = favorites->create_item(); { - Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites." + base_type), FileAccess::WRITE); if (f.is_valid()) { for (int i = 0; i < favorite_list.size(); i++) { String l = favorite_list[i]; @@ -686,7 +686,7 @@ void CreateDialog::_save_and_update_favorite_list() { void CreateDialog::_load_favorites_and_history() { String dir = EditorPaths::get_singleton()->get_project_settings_dir(); - Ref<FileAccess> f = FileAccess::open(dir.plus_file("create_recent." + base_type), FileAccess::READ); + Ref<FileAccess> f = FileAccess::open(dir.path_join("create_recent." + base_type), FileAccess::READ); if (f.is_valid()) { while (!f->eof_reached()) { String l = f->get_line().strip_edges(); @@ -698,7 +698,7 @@ void CreateDialog::_load_favorites_and_history() { } } - f = FileAccess::open(dir.plus_file("favorites." + base_type), FileAccess::READ); + f = FileAccess::open(dir.path_join("favorites." + base_type), FileAccess::READ); if (f.is_valid()) { while (!f->eof_reached()) { String l = f->get_line().strip_edges(); @@ -780,7 +780,7 @@ CreateDialog::CreateDialog() { favorite = memnew(Button); favorite->set_toggle_mode(true); - favorite->set_tooltip(TTR("(Un)favorite selected item.")); + favorite->set_tooltip_text(TTR("(Un)favorite selected item.")); favorite->connect("pressed", callable_mp(this, &CreateDialog::_favorite_toggled)); search_hb->add_child(favorite); vbc->add_margin_child(TTR("Search:"), search_hb); diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp index 3c3e4faa6f..ac41306cde 100644 --- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp +++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp @@ -201,7 +201,7 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const { } } else if (platform_string == "web") { for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) { - if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "HTML5") { + if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "Web") { idx = i; break; } diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index dbd2c61d44..76efcd7190 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -155,7 +155,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int const SceneDebuggerTree::RemoteNode &node = p_tree->nodes[i]; TreeItem *item = create_item(parent); item->set_text(0, node.name); - item->set_tooltip(0, TTR("Type:") + " " + node.type_name); + item->set_tooltip_text(0, TTR("Type:") + " " + node.type_name); Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(node.type_name, ""); if (icon.is_valid()) { item->set_icon(0, icon); diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index 55d025f675..10b50a81e4 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -61,7 +61,7 @@ void EditorPerformanceProfiler::Monitor::update_value(float p_value) { } break; } item->set_text(1, label); - item->set_tooltip(1, tooltip); + item->set_tooltip_text(1, tooltip); if (p_value > max) { max = p_value; @@ -73,7 +73,7 @@ void EditorPerformanceProfiler::Monitor::reset() { max = 0.0f; if (item) { item->set_text(1, ""); - item->set_tooltip(1, ""); + item->set_tooltip_text(1, ""); } } @@ -92,7 +92,7 @@ String EditorPerformanceProfiler::_create_label(float p_value, Performance::Moni } void EditorPerformanceProfiler::_monitor_select() { - monitor_draw->update(); + monitor_draw->queue_redraw(); } void EditorPerformanceProfiler::_monitor_draw() { @@ -283,12 +283,12 @@ void EditorPerformanceProfiler::_marker_input(const Ref<InputEvent> &p_event) { float spacing = float(point_sep) / float(columns); marker_frame = (rect.size.x - point.x) / spacing; } - monitor_draw->update(); + monitor_draw->queue_redraw(); return; } } marker_key = ""; - monitor_draw->update(); + monitor_draw->queue_redraw(); } } @@ -308,7 +308,7 @@ void EditorPerformanceProfiler::reset() { _build_monitor_tree(); marker_key = ""; marker_frame = 0; - monitor_draw->update(); + monitor_draw->queue_redraw(); } void EditorPerformanceProfiler::update_monitors(const Vector<StringName> &p_names) { @@ -357,7 +357,7 @@ void EditorPerformanceProfiler::add_profile_frame(const Vector<float> &p_values) E.value.update_value(data); } marker_frame++; - monitor_draw->update(); + monitor_draw->queue_redraw(); } List<float> *EditorPerformanceProfiler::get_monitor_data(const StringName &p_name) { diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index 28b5d4be15..cf48366bd3 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -318,7 +318,7 @@ void EditorProfiler::_update_plot() { graph_texture->update(img); graph->set_texture(graph_texture); - graph->update(); + graph->queue_redraw(); } void EditorProfiler::_update_frame() { @@ -356,7 +356,7 @@ void EditorProfiler::_update_frame() { item->set_metadata(1, it.script); item->set_metadata(2, it.line); item->set_text_alignment(2, HORIZONTAL_ALIGNMENT_RIGHT); - item->set_tooltip(0, it.name + "\n" + it.script + ":" + itos(it.line)); + item->set_tooltip_text(0, it.name + "\n" + it.script + ":" + itos(it.line)); float time = dtime == DISPLAY_SELF_TIME ? it.self : it.total; @@ -421,7 +421,7 @@ void EditorProfiler::_graph_tex_draw() { void EditorProfiler::_graph_tex_mouse_exit() { hover_metric = -1; - graph->update(); + graph->queue_redraw(); } void EditorProfiler::_cursor_metric_changed(double) { @@ -429,7 +429,7 @@ void EditorProfiler::_cursor_metric_changed(double) { return; } - graph->update(); + graph->queue_redraw(); _update_frame(); } @@ -480,13 +480,13 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) { } } - graph->update(); + graph->queue_redraw(); } } void EditorProfiler::disable_seeking() { seeking = false; - graph->update(); + graph->queue_redraw(); } void EditorProfiler::_combo_changed(int) { @@ -607,7 +607,7 @@ EditorProfiler::EditorProfiler() { display_time = memnew(OptionButton); display_time->add_item(TTR("Inclusive")); display_time->add_item(TTR("Self")); - display_time->set_tooltip(TTR("Inclusive: Includes time from other functions called by this function.\nUse this to spot bottlenecks.\n\nSelf: Only count the time spent in the function itself, not in other functions called by that function.\nUse this to find individual functions to optimize.")); + display_time->set_tooltip_text(TTR("Inclusive: Includes time from other functions called by this function.\nUse this to spot bottlenecks.\n\nSelf: Only count the time spent in the function itself, not in other functions called by that function.\nUse this to find individual functions to optimize.")); display_time->connect("item_selected", callable_mp(this, &EditorProfiler::_combo_changed)); hb->add_child(display_time); diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index 6f3dd1793c..8e7135f1c5 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -312,7 +312,7 @@ void EditorVisualProfiler::_update_plot() { graph_texture->update(img); graph->set_texture(graph_texture); - graph->update(); + graph->queue_redraw(); } void EditorVisualProfiler::_update_frame(bool p_focus_selected) { @@ -489,7 +489,7 @@ void EditorVisualProfiler::_graph_tex_draw() { void EditorVisualProfiler::_graph_tex_mouse_exit() { hover_metric = -1; - graph->update(); + graph->queue_redraw(); } void EditorVisualProfiler::_cursor_metric_changed(double) { @@ -497,7 +497,7 @@ void EditorVisualProfiler::_cursor_metric_changed(double) { return; } - graph->update(); + graph->queue_redraw(); _update_frame(); } @@ -613,7 +613,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) { } } - graph->update(); + graph->queue_redraw(); } } @@ -637,7 +637,7 @@ int EditorVisualProfiler::_get_cursor_index() const { void EditorVisualProfiler::disable_seeking() { seeking = false; - graph->update(); + graph->queue_redraw(); } void EditorVisualProfiler::_combo_changed(int) { diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 1bee0513ca..5baa9970af 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -369,7 +369,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da } } - vmem_total->set_tooltip(TTR("Bytes:") + " " + itos(total)); + vmem_total->set_tooltip_text(TTR("Bytes:") + " " + itos(total)); vmem_total->set_text(String::humanize_size(total)); } else if (p_msg == "stack_dump") { @@ -580,8 +580,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da stack_trace->set_text(1, frame_txt); } - error->set_tooltip(0, tooltip); - error->set_tooltip(1, tooltip); + error->set_tooltip_text(0, tooltip); + error->set_tooltip_text(1, tooltip); if (warning_count == 0 && error_count == 0) { expand_all_button->set_disabled(false); @@ -776,7 +776,7 @@ void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType reason->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor"))); } reason->set_text(p_reason); - reason->set_tooltip(p_reason.word_wrap(80)); + reason->set_tooltip_text(p_reason.word_wrap(80)); } void ScriptEditorDebugger::_notification(int p_what) { @@ -964,7 +964,7 @@ void ScriptEditorDebugger::stop() { peer->close(); peer.unref(); reason->set_text(""); - reason->set_tooltip(""); + reason->set_tooltip_text(""); } node_path_cache.clear(); @@ -1706,7 +1706,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() { skip_breakpoints = memnew(Button); skip_breakpoints->set_flat(true); hbc->add_child(skip_breakpoints); - skip_breakpoints->set_tooltip(TTR("Skip Breakpoints")); + skip_breakpoints->set_tooltip_text(TTR("Skip Breakpoints")); skip_breakpoints->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_skip_breakpoints)); hbc->add_child(memnew(VSeparator)); @@ -1714,7 +1714,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() { copy = memnew(Button); copy->set_flat(true); hbc->add_child(copy); - copy->set_tooltip(TTR("Copy Error")); + copy->set_tooltip_text(TTR("Copy Error")); copy->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_copy)); hbc->add_child(memnew(VSeparator)); @@ -1722,14 +1722,14 @@ ScriptEditorDebugger::ScriptEditorDebugger() { step = memnew(Button); step->set_flat(true); hbc->add_child(step); - step->set_tooltip(TTR("Step Into")); + step->set_tooltip_text(TTR("Step Into")); step->set_shortcut(ED_GET_SHORTCUT("debugger/step_into")); step->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_step)); next = memnew(Button); next->set_flat(true); hbc->add_child(next); - next->set_tooltip(TTR("Step Over")); + next->set_tooltip_text(TTR("Step Over")); next->set_shortcut(ED_GET_SHORTCUT("debugger/step_over")); next->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_next)); @@ -1738,14 +1738,14 @@ ScriptEditorDebugger::ScriptEditorDebugger() { dobreak = memnew(Button); dobreak->set_flat(true); hbc->add_child(dobreak); - dobreak->set_tooltip(TTR("Break")); + dobreak->set_tooltip_text(TTR("Break")); dobreak->set_shortcut(ED_GET_SHORTCUT("debugger/break")); dobreak->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_break)); docontinue = memnew(Button); docontinue->set_flat(true); hbc->add_child(docontinue); - docontinue->set_tooltip(TTR("Continue")); + docontinue->set_tooltip_text(TTR("Continue")); docontinue->set_shortcut(ED_GET_SHORTCUT("debugger/continue")); docontinue->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_continue)); @@ -1917,7 +1917,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() { vmem_hb->add_child(vmem_refresh); vmem_export = memnew(Button); vmem_export->set_flat(true); - vmem_export->set_tooltip(TTR("Export list to a CSV file")); + vmem_export->set_tooltip_text(TTR("Export list to a CSV file")); vmem_hb->add_child(vmem_export); vmem_vb->add_child(vmem_hb); vmem_refresh->connect("pressed", callable_mp(this, &ScriptEditorDebugger::_video_mem_request)); diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 864871bb7e..ec9a744e57 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -41,6 +41,7 @@ #include "core/version.h" #include "editor/editor_settings.h" #include "scene/resources/theme.h" +#include "scene/theme/theme_db.h" // Used for a hack preserving Mono properties on non-Mono builds. #include "modules/modules_enabled.gen.h" // For mono. @@ -567,29 +568,29 @@ void DocTools::generate(bool p_basic_types) { { List<StringName> l; - Theme::get_default()->get_color_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_color_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; tid.type = "Color"; tid.data_type = "color"; - tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string().replace("\n", " "); + tid.default_value = Variant(ThemeDB::get_singleton()->get_default_theme()->get_color(E, cname)).get_construct_string().replace("\n", " "); c.theme_properties.push_back(tid); } l.clear(); - Theme::get_default()->get_constant_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_constant_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; tid.type = "int"; tid.data_type = "constant"; - tid.default_value = itos(Theme::get_default()->get_constant(E, cname)); + tid.default_value = itos(ThemeDB::get_singleton()->get_default_theme()->get_constant(E, cname)); c.theme_properties.push_back(tid); } l.clear(); - Theme::get_default()->get_font_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_font_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; @@ -599,7 +600,7 @@ void DocTools::generate(bool p_basic_types) { } l.clear(); - Theme::get_default()->get_font_size_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; @@ -609,7 +610,7 @@ void DocTools::generate(bool p_basic_types) { } l.clear(); - Theme::get_default()->get_icon_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_icon_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; @@ -619,7 +620,7 @@ void DocTools::generate(bool p_basic_types) { } l.clear(); - Theme::get_default()->get_stylebox_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; @@ -1070,7 +1071,7 @@ Error DocTools::load_classes(const String &p_dir) { while (!path.is_empty()) { if (!da->current_is_dir() && path.ends_with("xml")) { Ref<XMLParser> parser = memnew(XMLParser); - Error err2 = parser->open(p_dir.plus_file(path)); + Error err2 = parser->open(p_dir.path_join(path)); if (err2) { return err2; } @@ -1379,7 +1380,7 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String, } Error err; - String save_file = save_path.plus_file(c.name + ".xml"); + String save_file = save_path.path_join(c.name + ".xml"); Ref<FileAccess> f = FileAccess::open(save_file, FileAccess::WRITE, &err); ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + "."); diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 17aa67cd45..7baaffb1be 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -147,7 +147,7 @@ EditorAbout::EditorAbout() { // Set the text to copy in metadata as it slightly differs from the button's text. version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip(TTR("Click to copy.")); + version_btn->set_tooltip_text(TTR("Click to copy.")); version_btn->connect("pressed", callable_mp(this, &EditorAbout::_version_button_pressed)); version_info_vbc->add_child(version_btn); diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp index 8dc8a0ab6b..aaa5956c17 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -215,11 +215,11 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { if (FileAccess::exists(res_path)) { num_file_conflicts += 1; ti->set_custom_color(0, tree->get_theme_color(SNAME("error_color"), SNAME("Editor"))); - ti->set_tooltip(0, vformat(TTR("%s (already exists)"), res_path)); + ti->set_tooltip_text(0, vformat(TTR("%s (already exists)"), res_path)); ti->set_checked(0, false); ti->propagate_check(0); } else { - ti->set_tooltip(0, res_path); + ti->set_tooltip_text(0, res_path); } ti->set_metadata(0, res_path); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index f1add65b7c..b1253ed7cb 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -182,7 +182,7 @@ void EditorAudioBus::_notification(int p_what) { case NOTIFICATION_DRAG_END: { if (hovering_drop) { hovering_drop = false; - update(); + queue_redraw(); } } break; } @@ -395,7 +395,7 @@ void EditorAudioBus::_show_value(float slider_value) { // Also set the preview text as a standard Control tooltip. // This way, it can be seen when the slider is merely hovered (instead of dragged). - slider->set_tooltip(text); + slider->set_tooltip_text(text); audio_value_preview_label->set_text(text); const Vector2 slider_size = slider->get_size(); const Vector2 slider_position = slider->get_global_position(); @@ -779,7 +779,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { buses = p_buses; is_master = p_is_master; - set_tooltip(TTR("Drag & drop to rearrange.")); + set_tooltip_text(TTR("Drag & drop to rearrange.")); VBoxContainer *vb = memnew(VBoxContainer); add_child(vb); @@ -796,21 +796,21 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { solo = memnew(Button); solo->set_flat(true); solo->set_toggle_mode(true); - solo->set_tooltip(TTR("Solo")); + solo->set_tooltip_text(TTR("Solo")); solo->set_focus_mode(FOCUS_NONE); solo->connect("pressed", callable_mp(this, &EditorAudioBus::_solo_toggled)); hbc->add_child(solo); mute = memnew(Button); mute->set_flat(true); mute->set_toggle_mode(true); - mute->set_tooltip(TTR("Mute")); + mute->set_tooltip_text(TTR("Mute")); mute->set_focus_mode(FOCUS_NONE); mute->connect("pressed", callable_mp(this, &EditorAudioBus::_mute_toggled)); hbc->add_child(mute); bypass = memnew(Button); bypass->set_flat(true); bypass->set_toggle_mode(true); - bypass->set_tooltip(TTR("Bypass")); + bypass->set_tooltip_text(TTR("Bypass")); bypass->set_focus_mode(FOCUS_NONE); bypass->connect("pressed", callable_mp(this, &EditorAudioBus::_bypass_toggled)); hbc->add_child(bypass); @@ -936,7 +936,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { bus_options->set_shortcut_context(this); bus_options->set_h_size_flags(SIZE_SHRINK_END); bus_options->set_anchor(SIDE_RIGHT, 0.0); - bus_options->set_tooltip(TTR("Bus Options")); + bus_options->set_tooltip_text(TTR("Bus Options")); hbc->add_child(bus_options); bus_popup = bus_options->get_popup(); @@ -967,7 +967,7 @@ void EditorAudioBusDrop::_notification(int p_what) { case NOTIFICATION_MOUSE_ENTER: { if (!hovering_drop) { hovering_drop = true; - update(); + queue_redraw(); } } break; @@ -975,7 +975,7 @@ void EditorAudioBusDrop::_notification(int p_what) { case NOTIFICATION_DRAG_END: { if (hovering_drop) { hovering_drop = false; - update(); + queue_redraw(); } } break; } @@ -1282,7 +1282,7 @@ EditorAudioBuses::EditorAudioBuses() { add = memnew(Button); top_hb->add_child(add); add->set_text(TTR("Add Bus")); - add->set_tooltip(TTR("Add a new Audio Bus to this layout.")); + add->set_tooltip_text(TTR("Add a new Audio Bus to this layout.")); add->connect("pressed", callable_mp(this, &EditorAudioBuses::_add_bus)); VSeparator *separator = memnew(VSeparator); @@ -1290,25 +1290,25 @@ EditorAudioBuses::EditorAudioBuses() { load = memnew(Button); load->set_text(TTR("Load")); - load->set_tooltip(TTR("Load an existing Bus Layout.")); + load->set_tooltip_text(TTR("Load an existing Bus Layout.")); top_hb->add_child(load); load->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_layout)); save_as = memnew(Button); save_as->set_text(TTR("Save As")); - save_as->set_tooltip(TTR("Save this Bus Layout to a file.")); + save_as->set_tooltip_text(TTR("Save this Bus Layout to a file.")); top_hb->add_child(save_as); save_as->connect("pressed", callable_mp(this, &EditorAudioBuses::_save_as_layout)); _default = memnew(Button); _default->set_text(TTR("Load Default")); - _default->set_tooltip(TTR("Load the default Bus Layout.")); + _default->set_tooltip_text(TTR("Load the default Bus Layout.")); top_hb->add_child(_default); _default->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_default_layout)); _new = memnew(Button); _new->set_text(TTR("Create")); - _new->set_tooltip(TTR("Create a new Bus Layout.")); + _new->set_tooltip_text(TTR("Create a new Bus Layout.")); top_hb->add_child(_new); _new->connect("pressed", callable_mp(this, &EditorAudioBuses::_new_layout)); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 120ac5b984..544b6c7141 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -164,7 +164,7 @@ void EditorAutoloadSettings::_autoload_add() { if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } - dialog->config("Node", fpath.plus_file(vformat("%s.gd", autoload_add_name->get_text().camelcase_to_underscore())), false, false); + dialog->config("Node", fpath.path_join(vformat("%s.gd", autoload_add_name->get_text().to_snake_case())), false, false); dialog->popup_centered(); } else { if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text())) { @@ -371,7 +371,7 @@ void EditorAutoloadSettings::_autoload_open(const String &fpath) { void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { // Convert the file name to PascalCase, which is the convention for classes in GDScript. - const String class_name = p_path.get_file().get_basename().capitalize().replace(" ", ""); + const String class_name = p_path.get_file().get_basename().to_pascal_case(); // If the name collides with a built-in class, prefix the name to make it possible to add without having to edit the name. // The prefix is subjective, but it provides better UX than leaving the Add button disabled :) @@ -580,7 +580,7 @@ void EditorAutoloadSettings::_script_created(Ref<Script> p_script) { FileSystemDock::get_singleton()->get_script_create_dialog()->hide(); path = p_script->get_path().get_base_dir(); autoload_add_path->set_text(p_script->get_path()); - autoload_add_name->set_text(p_script->get_path().get_file().get_basename().capitalize().replace(" ", "")); + autoload_add_name->set_text(p_script->get_path().get_file().get_basename().to_pascal_case()); _autoload_add(); } diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp index 4071722185..3bb050ce77 100644 --- a/editor/editor_dir_dialog.cpp +++ b/editor/editor_dir_dialog.cpp @@ -172,7 +172,7 @@ void EditorDirDialog::_make_dir_confirm() { mkdirerr->popup_centered(Size2(250, 80) * EDSCALE); } else { opened_paths.insert(dir); - //reload(dir.plus_file(makedirname->get_text())); + //reload(dir.path_join(makedirname->get_text())); EditorFileSystem::get_singleton()->scan_changes(); //we created a dir, so rescan changes } makedirname->set_text(""); // reset label diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index f0bf9fd5b3..708173ea26 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -315,7 +315,7 @@ void EditorFeatureProfileManager::_notification(int p_what) { current_profile = EDITOR_GET("_default_feature_profile"); if (!current_profile.is_empty()) { current.instantiate(); - Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(current_profile + ".profile")); + Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(current_profile + ".profile")); if (err != OK) { ERR_PRINT("Error loading default feature profile: " + current_profile); current_profile = String(); @@ -346,7 +346,7 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr if (p_select_profile.is_empty()) { //default, keep if (profile_list->get_selected() >= 0) { selected_profile = profile_list->get_item_metadata(profile_list->get_selected()); - if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(selected_profile + ".profile"))) { + if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(selected_profile + ".profile"))) { selected_profile = String(); //does not exist } } @@ -475,7 +475,7 @@ void EditorFeatureProfileManager::_create_new_profile() { EditorNode::get_singleton()->show_warning(TTR("Profile must be a valid filename and must not contain '.'")); return; } - String file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(name + ".profile"); + String file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(name + ".profile"); if (FileAccess::exists(file)) { EditorNode::get_singleton()->show_warning(TTR("Profile with this name already exists.")); return; @@ -630,7 +630,7 @@ void EditorFeatureProfileManager::_class_list_item_selected() { property->set_selectable(0, true); property->set_checked(0, !edited->is_class_property_disabled(class_name, name)); property->set_text(0, text); - property->set_tooltip(0, tooltip); + property->set_tooltip_text(0, tooltip); property->set_metadata(0, name); String icon_type = Variant::get_type_name(E.type); property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type)); @@ -754,8 +754,8 @@ void EditorFeatureProfileManager::_update_selected_profile() { } else { //reload edited, if different from current edited.instantiate(); - Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile")); - ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile") + "'."); + Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile")); + ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile") + "'."); } updating_features = true; @@ -810,7 +810,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths return; } - String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile); + String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile); if (FileAccess::exists(dst_file)) { EditorNode::get_singleton()->show_warning(vformat(TTR("Profile '%s' already exists. Remove it first before importing, import aborted."), basefile.get_basename())); @@ -825,7 +825,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths Error err = profile->load_from_file(p_paths[i]); ERR_CONTINUE(err != OK); String basefile = p_paths[i].get_file(); - String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile); + String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile); profile->save_to_file(dst_file); } @@ -849,7 +849,7 @@ void EditorFeatureProfileManager::_save_and_update() { ERR_FAIL_COND(edited_path.is_empty()); ERR_FAIL_COND(edited.is_null()); - edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(edited_path + ".profile")); + edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(edited_path + ".profile")); if (edited == current) { update_timer->start(); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 2f1134e8ef..fca9907c20 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -37,6 +37,7 @@ #include "core/string/print_string.h" #include "dependency_editor.h" #include "editor/editor_file_system.h" +#include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -251,7 +252,7 @@ void EditorFileDialog::_file_submitted(const String &p_file) { } void EditorFileDialog::_save_confirm_pressed() { - String f = dir_access->get_current_dir().plus_file(file->get_text()); + String f = dir_access->get_current_dir().path_join(file->get_text()); _save_to_recent(); hide(); emit_signal(SNAME("file_selected"), f); @@ -284,7 +285,7 @@ void EditorFileDialog::_post_popup() { } if (is_visible() && !get_current_file().is_empty()) { - _request_single_thumbnail(get_current_dir().plus_file(get_current_file())); + _request_single_thumbnail(get_current_dir().path_join(get_current_file())); } if (is_visible()) { @@ -294,11 +295,22 @@ void EditorFileDialog::_post_popup() { bool res = (access == ACCESS_RESOURCES); Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs(); + Vector<String> recentd_paths; + Vector<String> recentd_names; + for (int i = 0; i < recentd.size(); i++) { bool cres = recentd[i].begins_with("res://"); if (cres != res) { continue; } + + if (!dir_access->dir_exists(recentd[i])) { + // Remove invalid directory from the list of Recent directories. + recentd.remove_at(i--); + continue; + } + + // Compute recent directory display text. String name = recentd[i]; if (res && name == "res://") { name = "/"; @@ -306,17 +318,18 @@ void EditorFileDialog::_post_popup() { if (name.ends_with("/")) { name = name.substr(0, name.length() - 1); } - name = name.get_file() + "/"; - } - bool exists = dir_access->dir_exists(recentd[i]); - if (!exists) { - // Remove invalid directory from the list of Recent directories. - recentd.remove_at(i--); - } else { - recent->add_item(name, folder); - recent->set_item_metadata(-1, recentd[i]); - recent->set_item_icon_modulate(-1, folder_color); + name = name.get_file(); } + recentd_paths.append(recentd[i]); + recentd_names.append(name); + } + + EditorNode::disambiguate_filenames(recentd_paths, recentd_names); + + for (int i = 0; i < recentd_paths.size(); i++) { + recent->add_item(recentd_names[i], folder); + recent->set_item_metadata(-1, recentd_paths[i]); + recent->set_item_icon_modulate(-1, folder_color); } EditorSettings::get_singleton()->set_recent_dirs(recentd); @@ -381,7 +394,7 @@ void EditorFileDialog::_action_pressed() { Vector<String> files; for (int i = 0; i < item_list->get_item_count(); i++) { if (item_list->is_selected(i)) { - files.push_back(fbase.plus_file(item_list->get_item_text(i))); + files.push_back(fbase.path_join(item_list->get_item_text(i))); } } @@ -395,7 +408,7 @@ void EditorFileDialog::_action_pressed() { } String file_text = file->get_text(); - String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text); + String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text); if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) { _save_to_recent(); @@ -410,7 +423,7 @@ void EditorFileDialog::_action_pressed() { if (item_list->is_selected(i)) { Dictionary d = item_list->get_item_metadata(i); if (d["dir"]) { - path = path.plus_file(d["name"]); + path = path.path_join(d["name"]); break; } @@ -461,7 +474,7 @@ void EditorFileDialog::_action_pressed() { if (!valid && filterSliceCount > 0) { String str = (flt.get_slice(",", 0).strip_edges()); f += str.substr(1, str.length() - 1); - _request_single_thumbnail(get_current_dir().plus_file(f.get_file())); + _request_single_thumbnail(get_current_dir().path_join(f.get_file())); file->set_text(f.get_file()); valid = true; } @@ -505,7 +518,7 @@ void EditorFileDialog::_item_selected(int p_item) { if (!d["dir"]) { file->set_text(d["name"]); - _request_single_thumbnail(get_current_dir().plus_file(get_current_file())); + _request_single_thumbnail(get_current_dir().path_join(get_current_file())); } else if (mode == FILE_MODE_OPEN_DIR) { set_ok_button_text(TTR("Select This Folder")); } @@ -523,7 +536,7 @@ void EditorFileDialog::_multi_selected(int p_item, bool p_selected) { if (!d["dir"] && p_selected) { file->set_text(d["name"]); - _request_single_thumbnail(get_current_dir().plus_file(get_current_file())); + _request_single_thumbnail(get_current_dir().path_join(get_current_file())); } get_ok_button()->set_disabled(_is_open_should_be_disabled()); @@ -830,7 +843,7 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = dir_name; - d["path"] = cdir.plus_file(dir_name); + d["path"] = cdir.path_join(dir_name); d["dir"] = true; item_list->set_item_metadata(-1, d); @@ -879,7 +892,7 @@ void EditorFileDialog::update_file_list() { item_list->add_item(files.front()->get()); if (get_icon_func) { - Ref<Texture2D> icon = get_icon_func(cdir.plus_file(files.front()->get())); + Ref<Texture2D> icon = get_icon_func(cdir.path_join(files.front()->get())); if (display_mode == DISPLAY_THUMBNAILS) { item_list->set_item_icon(-1, file_thumbnail); item_list->set_item_tag_icon(-1, icon); @@ -891,7 +904,7 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = files.front()->get(); d["dir"] = false; - String fullpath = cdir.plus_file(files.front()->get()); + String fullpath = cdir.path_join(files.front()->get()); d["path"] = fullpath; item_list->set_item_metadata(-1, d); @@ -995,7 +1008,7 @@ String EditorFileDialog::get_current_file() const { } String EditorFileDialog::get_current_path() const { - return dir_access->get_current_dir().plus_file(file->get_text()); + return dir_access->get_current_dir().path_join(file->get_text()); } void EditorFileDialog::set_current_dir(const String &p_dir) { @@ -1014,7 +1027,7 @@ void EditorFileDialog::set_current_file(const String &p_file) { _focus_file_text(); if (is_visible()) { - _request_single_thumbnail(get_current_dir().plus_file(get_current_file())); + _request_single_thumbnail(get_current_dir().path_join(get_current_file())); } } @@ -1329,49 +1342,58 @@ void EditorFileDialog::_update_favorites() { favorite->set_pressed(false); Vector<String> favorited = EditorSettings::get_singleton()->get_favorites(); + Vector<String> favorited_paths; + Vector<String> favorited_names; bool fav_changed = false; - for (int i = favorited.size() - 1; i >= 0; i--) { - if (!dir_access->dir_exists(favorited[i])) { - favorited.remove_at(i); - fav_changed = true; - } - } - if (fav_changed) { - EditorSettings::get_singleton()->set_favorites(favorited); - } - + int current_favorite = -1; for (int i = 0; i < favorited.size(); i++) { bool cres = favorited[i].begins_with("res://"); if (cres != res) { continue; } - String name = favorited[i]; - bool setthis = false; + if (!dir_access->dir_exists(favorited[i])) { + // Remove invalid directory from the list of Favorited directories. + favorited.remove_at(i--); + fav_changed = true; + continue; + } + + // Compute favorite display text. + String name = favorited[i]; if (res && name == "res://") { if (name == current) { - setthis = true; + current_favorite = favorited_paths.size(); } name = "/"; - - favorites->add_item(name, folder_icon); + favorited_paths.append(favorited[i]); + favorited_names.append(name); } else if (name.ends_with("/")) { if (name == current || name == current + "/") { - setthis = true; + current_favorite = favorited_paths.size(); } name = name.substr(0, name.length() - 1); name = name.get_file(); - - favorites->add_item(name, folder_icon); + favorited_paths.append(favorited[i]); + favorited_names.append(name); } else { - continue; // We don't handle favorite files here. + // Ignore favorited files. } + } + + if (fav_changed) { + EditorSettings::get_singleton()->set_favorites(favorited); + } + + EditorNode::disambiguate_filenames(favorited_paths, favorited_names); - favorites->set_item_metadata(-1, favorited[i]); + for (int i = 0; i < favorited_paths.size(); i++) { + favorites->add_item(favorited_names[i], folder_icon); + favorites->set_item_metadata(-1, favorited_paths[i]); favorites->set_item_icon_modulate(-1, folder_color); - if (setthis) { + if (i == current_favorite) { favorite->set_pressed(true); favorites->set_current(favorites->get_item_count() - 1); recent->deselect_all(); @@ -1625,13 +1647,13 @@ EditorFileDialog::EditorFileDialog() { dir_prev = memnew(Button); dir_prev->set_flat(true); - dir_prev->set_tooltip(TTR("Go to previous folder.")); + dir_prev->set_tooltip_text(TTR("Go to previous folder.")); dir_next = memnew(Button); dir_next->set_flat(true); - dir_next->set_tooltip(TTR("Go to next folder.")); + dir_next->set_tooltip_text(TTR("Go to next folder.")); dir_up = memnew(Button); dir_up->set_flat(true); - dir_up->set_tooltip(TTR("Go to parent folder.")); + dir_up->set_tooltip_text(TTR("Go to parent folder.")); pathhb->add_child(dir_prev); pathhb->add_child(dir_next); @@ -1655,14 +1677,14 @@ EditorFileDialog::EditorFileDialog() { refresh = memnew(Button); refresh->set_flat(true); - refresh->set_tooltip(TTR("Refresh files.")); + refresh->set_tooltip_text(TTR("Refresh files.")); refresh->connect("pressed", callable_mp(this, &EditorFileDialog::update_file_list)); pathhb->add_child(refresh); favorite = memnew(Button); favorite->set_flat(true); favorite->set_toggle_mode(true); - favorite->set_tooltip(TTR("(Un)favorite current folder.")); + favorite->set_tooltip_text(TTR("(Un)favorite current folder.")); favorite->connect("pressed", callable_mp(this, &EditorFileDialog::_favorite_pressed)); pathhb->add_child(favorite); @@ -1670,7 +1692,7 @@ EditorFileDialog::EditorFileDialog() { show_hidden->set_flat(true); show_hidden->set_toggle_mode(true); show_hidden->set_pressed(is_showing_hidden_files()); - show_hidden->set_tooltip(TTR("Toggle the visibility of hidden files.")); + show_hidden->set_tooltip_text(TTR("Toggle the visibility of hidden files.")); show_hidden->connect("toggled", callable_mp(this, &EditorFileDialog::set_show_hidden_files)); pathhb->add_child(show_hidden); @@ -1685,7 +1707,7 @@ EditorFileDialog::EditorFileDialog() { mode_thumbnails->set_toggle_mode(true); mode_thumbnails->set_pressed(display_mode == DISPLAY_THUMBNAILS); mode_thumbnails->set_button_group(view_mode_group); - mode_thumbnails->set_tooltip(TTR("View items as a grid of thumbnails.")); + mode_thumbnails->set_tooltip_text(TTR("View items as a grid of thumbnails.")); pathhb->add_child(mode_thumbnails); mode_list = memnew(Button); @@ -1694,7 +1716,7 @@ EditorFileDialog::EditorFileDialog() { mode_list->set_toggle_mode(true); mode_list->set_pressed(display_mode == DISPLAY_LIST); mode_list->set_button_group(view_mode_group); - mode_list->set_tooltip(TTR("View items as a list.")); + mode_list->set_tooltip_text(TTR("View items as a list.")); pathhb->add_child(mode_list); shortcuts_container = memnew(HBoxContainer); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index bda2e283ef..177bc6d2b2 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -99,7 +99,7 @@ String EditorFileSystemDirectory::get_path() const { String p; const EditorFileSystemDirectory *d = this; while (d->parent) { - p = d->name.plus_file(p); + p = d->name.path_join(p); d = d->parent; } @@ -110,7 +110,7 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const { String file = get_file(p_idx); const EditorFileSystemDirectory *d = this; while (d->parent) { - file = d->name.plus_file(file); + file = d->name.path_join(file); d = d->parent; } @@ -219,7 +219,7 @@ void EditorFileSystem::_scan_filesystem() { String project = ProjectSettings::get_singleton()->get_resource_path(); - String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); + String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME); { Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::READ); @@ -261,7 +261,7 @@ void EditorFileSystem::_scan_filesystem() { String file; file = name; - name = cpath.plus_file(name); + name = cpath.path_join(name); FileCache fc; fc.type = split[1]; @@ -289,7 +289,7 @@ void EditorFileSystem::_scan_filesystem() { } } - String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4"); + String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4"); if (FileAccess::exists(update_cache)) { { @@ -332,7 +332,7 @@ void EditorFileSystem::_scan_filesystem() { void EditorFileSystem::_save_filesystem_cache() { group_file_cache.clear(); - String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); + String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME); Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE); ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions."); @@ -758,7 +758,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc continue; } - if (_should_skip_directory(cd.plus_file(f))) { + if (_should_skip_directory(cd.path_join(f))) { continue; } @@ -822,7 +822,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo); fi->file = E->get(); - String path = cd.plus_file(fi->file); + String path = cd.path_join(fi->file); FileCache *fc = file_cache.getptr(path); uint64_t mt = FileAccess::get_modified_time(path); @@ -982,7 +982,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const int idx = p_dir->find_dir_index(f); if (idx == -1) { - if (_should_skip_directory(cd.plus_file(f))) { + if (_should_skip_directory(cd.path_join(f))) { continue; } @@ -991,7 +991,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const efd->parent = p_dir; efd->name = f; Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); - d->change_dir(cd.plus_file(f)); + d->change_dir(cd.path_join(f)); _scan_new_dir(efd, d, p_progress.get_sub(1, 1)); ItemAction ia; @@ -1017,7 +1017,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo); fi->file = f; - String path = cd.plus_file(fi->file); + String path = cd.path_join(fi->file); fi->modified_time = FileAccess::get_modified_time(path); fi->import_modified_time = 0; fi->type = ResourceLoader::get_resource_type(path); @@ -1066,7 +1066,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const continue; } - String path = cd.plus_file(p_dir->files[i]->file); + String path = cd.path_join(p_dir->files[i]->file); if (import_extensions.has(p_dir->files[i]->file.get_extension().to_lower())) { //check here if file must be imported or not @@ -1452,7 +1452,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p void EditorFileSystem::_save_late_updated_files() { //files that already existed, and were modified, need re-scanning for dependencies upon project restart. This is done via saving this special file - String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4"); + String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4"); Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE); ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions."); for (const String &E : late_update_files) { @@ -2198,12 +2198,12 @@ bool EditorFileSystem::_should_skip_directory(const String &p_path) { return true; } - if (FileAccess::exists(p_path.plus_file("project.godot"))) { + if (FileAccess::exists(p_path.path_join("project.godot"))) { // skip if another project inside this return true; } - if (FileAccess::exists(p_path.plus_file(".gdignore"))) { + if (FileAccess::exists(p_path.path_join(".gdignore"))) { // skip if a `.gdignore` file is inside this return true; } diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp index c1d6e505db..d455e0248e 100644 --- a/editor/editor_folding.cpp +++ b/editor/editor_folding.cpp @@ -56,7 +56,7 @@ void EditorFolding::save_resource_folding(const Ref<Resource> &p_resource, const config->set_value("folding", "sections_unfolded", unfolds); String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; - file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file); + file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file); config->save(file); } @@ -74,7 +74,7 @@ void EditorFolding::load_resource_folding(Ref<Resource> p_resource, const String config.instantiate(); String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; - file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file); + file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file); if (config->load(file) != OK) { return; @@ -150,7 +150,7 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path config->set_value("folding", "nodes_folded", nodes_folded); String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; - file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file); + file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file); config->save(file); } @@ -160,7 +160,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) { String path = EditorPaths::get_singleton()->get_project_settings_dir(); String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; - file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file); + file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file); if (config->load(file) != OK) { return; @@ -214,7 +214,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) { bool EditorFolding::has_folding_data(const String &p_path) { String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; - file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file); + file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file); return FileAccess::exists(file); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 7fa4303145..97f5363bb8 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -239,6 +239,27 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) { class_desc->pop(); } +void EditorHelp::_add_type_icon(const String &p_type, int p_size) { + Ref<Texture2D> icon; + if (has_theme_icon(p_type, SNAME("EditorIcons"))) { + icon = get_theme_icon(p_type, SNAME("EditorIcons")); + } else if (ClassDB::class_exists(p_type) && ClassDB::is_parent_class(p_type, "Object")) { + icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons")); + } else { + icon = get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons")); + } + + Vector2i size = Vector2i(icon->get_width(), icon->get_height()); + if (p_size > 0) { + // Ensures icon scales proportionally on both axis, based on icon height. + float ratio = p_size / float(size.height); + size.width *= ratio; + size.height *= ratio; + } + + class_desc->add_image(icon, size.width, size.height); +} + String EditorHelp::_fix_constant(const String &p_constant) const { if (p_constant.strip_edges() == "4294967295") { return "0xFFFFFFFF"; @@ -530,22 +551,13 @@ void EditorHelp::_update_doc() { DocData::ClassDoc cd = doc->class_list[edited_class]; // Make a copy, so we can sort without worrying. - Ref<Texture2D> icon; - if (has_theme_icon(edited_class, SNAME("EditorIcons"))) { - icon = get_theme_icon(edited_class, SNAME("EditorIcons")); - } else if (ClassDB::class_exists(edited_class) && ClassDB::is_parent_class(edited_class, "Object")) { - icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons")); - } else { - icon = get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons")); - } - // Class name section_line.push_back(Pair<String, int>(TTR("Top"), 0)); class_desc->push_font(doc_title_font); class_desc->push_font_size(doc_title_font_size); class_desc->push_color(title_color); class_desc->add_text(TTR("Class:") + " "); - class_desc->add_image(icon, icon->get_width(), icon->get_height()); + _add_type_icon(edited_class, doc_title_font_size); class_desc->add_text(" "); class_desc->push_color(headline_color); _add_text(edited_class); @@ -566,6 +578,8 @@ void EditorHelp::_update_doc() { String inherits = cd.inherits; while (!inherits.is_empty()) { + _add_type_icon(inherits); + class_desc->add_text(" "); // Extra space, otherwise icon borrows hyperlink from _add_type(). _add_type(inherits); inherits = doc->class_list[inherits].inherits; @@ -597,7 +611,8 @@ void EditorHelp::_update_doc() { if (prev) { class_desc->add_text(" , "); } - + _add_type_icon(E.value.name); + class_desc->add_text(" "); // Extra space, otherwise icon borrows hyperlink from _add_type(). _add_type(E.value.name); prev = true; } @@ -1914,7 +1929,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { } String image = bbcode.substr(brk_end + 1, end - brk_end - 1); - Ref<Texture2D> texture = ResourceLoader::load(base_path.plus_file(image), "Texture2D"); + Ref<Texture2D> texture = ResourceLoader::load(base_path.path_join(image), "Texture2D"); if (texture.is_valid()) { p_rt->add_image(texture); } @@ -1931,7 +1946,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { } else if (tag.begins_with("font=")) { String fnt = tag.substr(5, tag.length()); - Ref<Font> font = ResourceLoader::load(base_path.plus_file(fnt), "Font"); + Ref<Font> font = ResourceLoader::load(base_path.path_join(fnt), "Font"); if (font.is_valid()) { p_rt->push_font(font); } else { @@ -2078,7 +2093,7 @@ void EditorHelp::update_toggle_scripts_button() { } else { toggle_scripts_button->set_icon(get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons"))); } - toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text())); + toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text())); } void EditorHelp::_bind_methods() { diff --git a/editor/editor_help.h b/editor/editor_help.h index 9f8da938f1..c9c1afb51b 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -153,6 +153,7 @@ class EditorHelp : public VBoxContainer { //void _button_pressed(int p_idx); void _add_type(const String &p_type, const String &p_enum = String()); + void _add_type_icon(const String &p_type, int p_size = 0); void _add_method(const DocData::MethodDoc &p_method, bool p_overview = true); void _add_bulletpoint(); diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 297d1226e3..2e35f21e47 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -206,7 +206,7 @@ EditorHelpSearch::EditorHelpSearch() { case_sensitive_button = memnew(Button); case_sensitive_button->set_flat(true); - case_sensitive_button->set_tooltip(TTR("Case Sensitive")); + case_sensitive_button->set_tooltip_text(TTR("Case Sensitive")); case_sensitive_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results)); case_sensitive_button->set_toggle_mode(true); case_sensitive_button->set_focus_mode(Control::FOCUS_NONE); @@ -214,7 +214,7 @@ EditorHelpSearch::EditorHelpSearch() { hierarchy_button = memnew(Button); hierarchy_button->set_flat(true); - hierarchy_button->set_tooltip(TTR("Show Hierarchy")); + hierarchy_button->set_tooltip_text(TTR("Show Hierarchy")); hierarchy_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results)); hierarchy_button->set_toggle_mode(true); hierarchy_button->set_pressed(true); @@ -562,8 +562,8 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const item->set_icon(0, icon); item->set_text(0, p_doc->name); item->set_text(1, TTR("Class")); - item->set_tooltip(0, tooltip); - item->set_tooltip(1, tooltip); + item->set_tooltip_text(0, tooltip); + item->set_tooltip_text(1, tooltip); item->set_metadata(0, "class_name:" + p_doc->name); if (p_gray) { item->set_custom_color(0, disabled_color); @@ -639,8 +639,8 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons item->set_icon(0, icon); item->set_text(0, text); item->set_text(1, TTRGET(p_type)); - item->set_tooltip(0, p_tooltip); - item->set_tooltip(1, p_tooltip); + item->set_tooltip_text(0, p_tooltip); + item->set_tooltip_text(1, p_tooltip); item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name); _match_item(item, p_name); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 1095321053..6aa0bd3f99 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -231,7 +231,7 @@ void EditorProperty::_notification(int p_what) { bottom_child_rect = bottom_rect; } - update(); //need to redraw text + queue_redraw(); //need to redraw text } break; case NOTIFICATION_DRAW: { @@ -398,7 +398,7 @@ void EditorProperty::_notification(int p_what) { void EditorProperty::set_label(const String &p_label) { label = p_label; - update(); + queue_redraw(); } String EditorProperty::get_label() const { @@ -478,7 +478,7 @@ void EditorProperty::update_revert_and_pin_status() { } can_revert = new_can_revert; pinned = new_pinned; - update(); + queue_redraw(); } } @@ -499,7 +499,7 @@ bool EditorProperty::use_keying_next() const { void EditorProperty::set_checkable(bool p_checkable) { checkable = p_checkable; - update(); + queue_redraw(); queue_sort(); } @@ -509,7 +509,7 @@ bool EditorProperty::is_checkable() const { void EditorProperty::set_checked(bool p_checked) { checked = p_checked; - update(); + queue_redraw(); } bool EditorProperty::is_checked() const { @@ -518,18 +518,18 @@ bool EditorProperty::is_checked() const { void EditorProperty::set_draw_warning(bool p_draw_warning) { draw_warning = p_draw_warning; - update(); + queue_redraw(); } void EditorProperty::set_keying(bool p_keying) { keying = p_keying; - update(); + queue_redraw(); queue_sort(); } void EditorProperty::set_deletable(bool p_deletable) { deletable = p_deletable; - update(); + queue_redraw(); queue_sort(); } @@ -552,7 +552,7 @@ void EditorProperty::_focusable_focused(int p_index) { bool already_selected = selected; selected = true; selected_focusable = p_index; - update(); + queue_redraw(); if (!already_selected && selected) { emit_signal(SNAME("selected"), property, selected_focusable); } @@ -571,7 +571,7 @@ void EditorProperty::select(int p_focusable) { focusables[p_focusable]->grab_focus(); } else { selected = true; - update(); + queue_redraw(); } if (!already_selected && selected) { @@ -582,7 +582,7 @@ void EditorProperty::select(int p_focusable) { void EditorProperty::deselect() { selected = false; selected_focusable = -1; - update(); + queue_redraw(); } bool EditorProperty::is_selected() const { @@ -608,25 +608,25 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { bool new_keying_hover = keying_rect.has_point(mpos) && !button_left; if (new_keying_hover != keying_hover) { keying_hover = new_keying_hover; - update(); + queue_redraw(); } bool new_delete_hover = delete_rect.has_point(mpos) && !button_left; if (new_delete_hover != delete_hover) { delete_hover = new_delete_hover; - update(); + queue_redraw(); } bool new_revert_hover = revert_rect.has_point(mpos) && !button_left; if (new_revert_hover != revert_hover) { revert_hover = new_revert_hover; - update(); + queue_redraw(); } bool new_check_hover = check_rect.has_point(mpos) && !button_left; if (new_check_hover != check_hover) { check_hover = new_check_hover; - update(); + queue_redraw(); } } @@ -641,7 +641,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { if (!selected && selectable) { selected = true; emit_signal(SNAME("selected"), property, -1); - update(); + queue_redraw(); } if (keying_rect.has_point(mpos)) { @@ -681,7 +681,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { if (check_rect.has_point(mpos)) { checked = !checked; - update(); + queue_redraw(); emit_signal(SNAME("property_checked"), property, checked); } } else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { @@ -912,7 +912,7 @@ void EditorProperty::menu_option(int p_option) { } break; case MENU_PIN_VALUE: { emit_signal(SNAME("property_pinned"), property, !pinned); - update(); + queue_redraw(); } break; case MENU_OPEN_DOCUMENTATION: { ScriptEditor::get_singleton()->goto_help(doc_path); @@ -961,7 +961,7 @@ void EditorProperty::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keying"), "set_keying", "is_keying"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deletable"), "set_deletable", "is_deletable"); - ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); + ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::STRING_NAME, "field"), PropertyInfo(Variant::BOOL, "changing"))); ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::PACKED_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value"))); ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING_NAME, "property"))); ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING_NAME, "property"))); @@ -1372,26 +1372,26 @@ void EditorInspectorSection::_notification(int p_what) { } dropping = children_can_drop; - update(); + queue_redraw(); } break; case NOTIFICATION_DRAG_END: { dropping = false; - update(); + queue_redraw(); } break; case NOTIFICATION_MOUSE_ENTER: { if (dropping) { dropping_unfold_timer->start(); } - update(); + queue_redraw(); } break; case NOTIFICATION_MOUSE_EXIT: { if (dropping) { dropping_unfold_timer->stop(); } - update(); + queue_redraw(); } break; } } @@ -1477,7 +1477,7 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) { fold(); } } else if (mb.is_valid() && !mb->is_pressed()) { - update(); + queue_redraw(); } } @@ -1494,7 +1494,7 @@ void EditorInspectorSection::unfold() { object->editor_set_section_unfold(section, true); vbox->show(); - update(); + queue_redraw(); } void EditorInspectorSection::fold() { @@ -1508,7 +1508,7 @@ void EditorInspectorSection::fold() { object->editor_set_section_unfold(section, false); vbox->hide(); - update(); + queue_redraw(); } bool EditorInspectorSection::has_revertable_properties() const { @@ -1523,7 +1523,7 @@ void EditorInspectorSection::property_can_revert_changed(const String &p_path, b revertable_properties.erase(p_path); } if (has_revertable_properties() != had_revertable_properties) { - update(); + queue_redraw(); } } @@ -2051,9 +2051,9 @@ void EditorInspectorArray::_setup() { ae.panel->set_mouse_filter(MOUSE_FILTER_PASS); ae.panel->set_drag_forwarding(this); ae.panel->set_meta("index", begin_array_index + i); - ae.panel->set_tooltip(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i)); - ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update)); - ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update)); + ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i)); + ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw)); + ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw)); ae.panel->connect("draw", callable_mp(this, &EditorInspectorArray::_panel_draw).bind(i)); ae.panel->connect("gui_input", callable_mp(this, &EditorInspectorArray::_panel_gui_input).bind(i)); ae.panel->add_theme_style_override(SNAME("panel"), i % 2 ? odd_style : even_style); @@ -2155,7 +2155,7 @@ bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant return false; } // First, update drawing. - control_dropping->update(); + control_dropping->queue_redraw(); if (p_data.get_type() != Variant::DICTIONARY) { return false; @@ -2206,14 +2206,14 @@ void EditorInspectorArray::_notification(int p_what) { Dictionary dict = get_viewport()->gui_get_drag_data(); if (dict.has("type") && dict["type"] == "property_array_element" && String(dict["property_array_prefix"]) == array_element_prefix) { dropping = true; - control_dropping->update(); + control_dropping->queue_redraw(); } } break; case NOTIFICATION_DRAG_END: { if (dropping) { dropping = false; - control_dropping->update(); + control_dropping->queue_redraw(); } } break; } @@ -2788,7 +2788,7 @@ void EditorInspector::update_tree() { class_descr_cache[doc_name] = descr; } - category->set_tooltip(p.name + "::" + (class_descr_cache[doc_name].is_empty() ? "" : class_descr_cache[doc_name])); + category->set_tooltip_text(p.name + "::" + (class_descr_cache[doc_name].is_empty() ? "" : class_descr_cache[doc_name])); } // Add editors at the start of a category. @@ -2981,7 +2981,7 @@ void EditorInspector::update_tree() { Color c = sscolor; c.a /= level; section->setup(acc_path, label, object, c, use_folding, section_depth); - section->set_tooltip(tooltip); + section->set_tooltip_text(tooltip); // Add editors at the start of a group. for (Ref<EditorInspectorPlugin> &ped : valid_plugins) { @@ -3225,9 +3225,9 @@ void EditorInspector::update_tree() { ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), CONNECT_DEFERRED); ep->connect("object_id_selected", callable_mp(this, &EditorInspector::_object_id_selected), CONNECT_DEFERRED); if (!doc_info.description.is_empty()) { - ep->set_tooltip(property_prefix + p.name + "::" + doc_info.description); + ep->set_tooltip_text(property_prefix + p.name + "::" + doc_info.description); } else { - ep->set_tooltip(property_prefix + p.name); + ep->set_tooltip_text(property_prefix + p.name); } ep->set_doc_path(doc_info.path); ep->update_property(); diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp index 0cf7f7df2a..87da67fb05 100644 --- a/editor/editor_locale_dialog.cpp +++ b/editor/editor_locale_dialog.cpp @@ -493,7 +493,7 @@ EditorLocaleDialog::EditorLocaleDialog() { { lang_code = memnew(LineEdit); lang_code->set_max_length(3); - lang_code->set_tooltip("Language"); + lang_code->set_tooltip_text("Language"); vb_language->add_child(lang_code); } hb_locale->add_child(vb_language); @@ -509,7 +509,7 @@ EditorLocaleDialog::EditorLocaleDialog() { { script_code = memnew(LineEdit); script_code->set_max_length(4); - script_code->set_tooltip("Script"); + script_code->set_tooltip_text("Script"); vb_script->add_child(script_code); } hb_locale->add_child(vb_script); @@ -525,7 +525,7 @@ EditorLocaleDialog::EditorLocaleDialog() { { country_code = memnew(LineEdit); country_code->set_max_length(2); - country_code->set_tooltip("Country"); + country_code->set_tooltip_text("Country"); vb_country->add_child(country_code); } hb_locale->add_child(vb_country); @@ -542,7 +542,7 @@ EditorLocaleDialog::EditorLocaleDialog() { variant_code = memnew(LineEdit); variant_code->set_h_size_flags(Control::SIZE_EXPAND_FILL); variant_code->set_placeholder("Variant"); - variant_code->set_tooltip("Variant"); + variant_code->set_tooltip_text("Variant"); vb_variant->add_child(variant_code); } hb_locale->add_child(vb_variant); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index f540e2b2a1..a3d4296edb 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -131,7 +131,7 @@ void EditorLog::_save_state() { Ref<ConfigFile> config; config.instantiate(); // Load and amend existing config if it exists. - config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); + config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); const String section = "editor_log"; for (const KeyValue<MessageType, LogFilter *> &E : type_filter_map) { @@ -141,7 +141,7 @@ void EditorLog::_save_state() { config->set_value(section, "collapse", collapse); config->set_value(section, "show_search", search_box->is_visible()); - config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); + config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); } void EditorLog::_load_state() { @@ -149,7 +149,7 @@ void EditorLog::_load_state() { Ref<ConfigFile> config; config.instantiate(); - config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); + config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); // Run the below code even if config->load returns an error, since we want the defaults to be set even if the file does not exist yet. const String section = "editor_log"; @@ -419,7 +419,7 @@ EditorLog::EditorLog() { collapse_button = memnew(Button); collapse_button->set_flat(true); collapse_button->set_focus_mode(FOCUS_NONE); - collapse_button->set_tooltip(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences.")); + collapse_button->set_tooltip_text(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences.")); collapse_button->set_toggle_mode(true); collapse_button->set_pressed(false); collapse_button->connect("toggled", callable_mp(this, &EditorLog::_set_collapse)); diff --git a/editor/editor_log.h b/editor/editor_log.h index 3bdfd936c1..43d7037414 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -95,7 +95,7 @@ private: toggle_button->set_toggle_mode(true); toggle_button->set_pressed(true); toggle_button->set_text(itos(message_count)); - toggle_button->set_tooltip(TTR(p_tooltip)); + toggle_button->set_tooltip_text(TTR(p_tooltip)); // Don't tint the icon even when in "pressed" state. toggle_button->add_theme_color_override("icon_color_pressed", Color(1, 1, 1, 1)); toggle_button->set_focus_mode(FOCUS_NONE); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 828c833ba3..c2820389c6 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -217,6 +217,8 @@ EditorNode *EditorNode::singleton = nullptr; static const String META_TEXT_TO_COPY = "text_to_copy"; void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) { + ERR_FAIL_COND_MSG(p_full_paths.size() != r_filenames.size(), vformat("disambiguate_filenames requires two string vectors of same length (%d != %d).", p_full_paths.size(), r_filenames.size())); + // Keep track of a list of "index sets," i.e. sets of indices // within disambiguated_scene_names which contain the same name. Vector<RBSet<int>> index_sets; @@ -251,6 +253,10 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto full_path = full_path.substr(0, full_path.rfind(".")); } + // Normalize trailing slashes when normalizing directory names. + scene_name = scene_name.trim_suffix("/"); + full_path = full_path.trim_suffix("/"); + int scene_name_size = scene_name.size(); int full_path_size = full_path.size(); int difference = full_path_size - scene_name_size; @@ -293,17 +299,23 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto // and the scene name first to remove extensions so that this // comparison actually works. String path = p_full_paths[E->get()]; + + // Get rid of file extensions and res:// prefixes. + if (scene_name.rfind(".") >= 0) { + scene_name = scene_name.substr(0, scene_name.rfind(".")); + } if (path.begins_with("res://")) { path = path.substr(6); } if (path.rfind(".") >= 0) { path = path.substr(0, path.rfind(".")); } - if (scene_name.rfind(".") >= 0) { - scene_name = scene_name.substr(0, scene_name.rfind(".")); - } - // We can proceed iff the full path is longer than the scene name, + // Normalize trailing slashes when normalizing directory names. + scene_name = scene_name.trim_suffix("/"); + path = path.trim_suffix("/"); + + // We can proceed if the full path is longer than the scene name, // meaning that there is at least one more parent folder we can // tack onto the name. can_proceed = can_proceed || (path.size() - scene_name.size()) >= 1; @@ -355,7 +367,7 @@ void EditorNode::_update_scene_tabs() { scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) { - DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), i); + DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), Callable(), i); } if (show_rb && editor_data.get_scene_root_script(i).is_valid()) { @@ -412,9 +424,6 @@ void EditorNode::_version_control_menu_option(int p_idx) { case RUN_VCS_SETTINGS: { VersionControlEditorPlugin::get_singleton()->popup_vcs_set_up_dialog(gui_base); } break; - case RUN_VCS_SHUT_DOWN: { - VersionControlEditorPlugin::get_singleton()->shut_down(); - } break; } } @@ -493,10 +502,10 @@ void EditorNode::_update_from_settings() { } RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape"))); - RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape); + RS::get_singleton()->camera_attributes_set_dof_blur_bokeh_shape(dof_shape); RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))); bool dof_jitter = GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter"); - RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter); + RS::get_singleton()->camera_attributes_set_dof_blur_quality(dof_quality, dof_jitter); RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to")); RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit")); bool glow_bicubic = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0; @@ -512,13 +521,13 @@ void EditorNode::_update_from_settings() { float sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale"); RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale); - uint32_t directional_shadow_size = GLOBAL_GET("rendering/shadows/directional_shadow/size"); - uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits"); + uint32_t directional_shadow_size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size"); + uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits"); RS::get_singleton()->directional_shadow_atlas_set_size(directional_shadow_size, directional_shadow_16_bits); - RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/positional_shadow/soft_shadow_filter_quality"))); + RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality"))); RS::get_singleton()->positional_soft_shadow_filter_set_quality(shadows_quality); - RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_filter_quality"))); + RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality"))); RS::get_singleton()->directional_soft_shadow_filter_set_quality(directional_shadow_quality); float probe_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed"); RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed); @@ -545,6 +554,9 @@ void EditorNode::_update_from_settings() { Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/2d/sdf/scale"))); scene_root->set_sdf_scale(sdf_scale); + Viewport::MSAA msaa = Viewport::MSAA(int(GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d"))); + scene_root->set_msaa_2d(msaa); + float mesh_lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels"); scene_root->set_mesh_lod_threshold(mesh_lod_threshold); @@ -751,6 +763,8 @@ void EditorNode::_notification(int p_what) { gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles"))); scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Content"), SNAME("EditorStyles"))); bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + + tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))); scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles"))); scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles"))); @@ -782,6 +796,14 @@ void EditorNode::_notification(int p_what) { _build_icon_type_cache(); + if (write_movie_button->is_pressed()) { + launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadMovieMode"), SNAME("EditorStyles"))); + write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonPressed"), SNAME("EditorStyles"))); + } else { + launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles"))); + write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles"))); + } + play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons"))); play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons"))); @@ -846,7 +868,7 @@ void EditorNode::_update_update_spinner() { update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !update_continuously); if (update_continuously) { - update_spinner->set_tooltip(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it.")); + update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it.")); // Use a different color for the update spinner when Update Continuously is enabled, // as this feature should only be enabled for troubleshooting purposes. @@ -856,7 +878,7 @@ void EditorNode::_update_update_spinner() { update_spinner->set_self_modulate( gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor")) * (dark_theme ? Color(1.1, 1.1, 1.1) : Color(4.25, 4.25, 4.25))); } else { - update_spinner->set_tooltip(TTR("Spins when the editor window redraws.")); + update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws.")); update_spinner->set_self_modulate(Color(1, 1, 1)); } @@ -1097,7 +1119,7 @@ void EditorNode::_scan_external_changes() { } } - String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("project.godot"); + String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().path_join("project.godot"); if (FileAccess::get_modified_time(project_settings_path) > ProjectSettings::get_singleton()->get_last_saved_time()) { TreeItem *ti = disk_changed_list->create_item(r); ti->set_text(0, "project.godot"); @@ -1315,7 +1337,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String file->set_current_file(p_resource->get_path().get_file()); } else { if (extensions.size()) { - String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore(); + String resource_name_snake_case = p_resource->get_class().to_snake_case(); file->set_current_file("new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower()); } else { file->set_current_file(String()); @@ -1332,7 +1354,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String } else if (preferred.size()) { String existing; if (extensions.size()) { - String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore(); + String resource_name_snake_case = p_resource->get_class().to_snake_case(); existing = "new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower(); } file->set_current_path(existing); @@ -1394,7 +1416,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) { return; } - String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; cf.instantiate(); @@ -1426,7 +1448,7 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) { return; } - String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; cf.instantiate(); @@ -1622,7 +1644,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { // Save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5. String temp_path = EditorPaths::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text(); - cache_base = temp_path.plus_file("resthumb-" + cache_base); + cache_base = temp_path.path_join("resthumb-" + cache_base); // Does not have it, try to load a cached thumbnail. String file = cache_base + ".png"; @@ -2403,6 +2425,16 @@ void EditorNode::_edit_current(bool p_skip_foreign) { InspectorDock::get_singleton()->update(current_obj); } +void EditorNode::_write_movie_toggled(bool p_enabled) { + if (p_enabled) { + launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadMovieMode"), SNAME("EditorStyles"))); + write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonPressed"), SNAME("EditorStyles"))); + } else { + launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles"))); + write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles"))); + } +} + void EditorNode::_run(bool p_current, const String &p_custom) { if (editor_run.get_status() == EditorRun::STATUS_PLAY) { play_button->set_pressed(!_playing_edited); @@ -2498,16 +2530,16 @@ void EditorNode::_run(bool p_current, const String &p_custom) { run_current_filename = run_filename; play_scene_button->set_pressed(true); play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); - play_scene_button->set_tooltip(TTR("Reload the played scene.")); + play_scene_button->set_tooltip_text(TTR("Reload the played scene.")); } else if (!p_custom.is_empty()) { run_custom_filename = p_custom; play_custom_scene_button->set_pressed(true); play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); - play_custom_scene_button->set_tooltip(TTR("Reload the played scene.")); + play_custom_scene_button->set_tooltip_text(TTR("Reload the played scene.")); } else { play_button->set_pressed(true); play_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); - play_button->set_tooltip(TTR("Reload the played scene.")); + play_button->set_tooltip_text(TTR("Reload the played scene.")); } stop_button->set_disabled(false); @@ -2535,13 +2567,13 @@ void EditorNode::_run_native(const Ref<EditorExportPreset> &p_preset) { void EditorNode::_reset_play_buttons() { play_button->set_pressed(false); play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); - play_button->set_tooltip(TTR("Play the project.")); + play_button->set_tooltip_text(TTR("Play the project.")); play_scene_button->set_pressed(false); play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons"))); - play_scene_button->set_tooltip(TTR("Play the edited scene.")); + play_scene_button->set_tooltip_text(TTR("Play the edited scene.")); play_custom_scene_button->set_pressed(false); play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons"))); - play_custom_scene_button->set_tooltip(TTR("Play a custom scene.")); + play_custom_scene_button->set_tooltip_text(TTR("Play a custom scene.")); } void EditorNode::_android_build_source_selected(const String &p_file) { @@ -2731,10 +2763,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { // Use casing of the root node. break; case SCENE_NAME_CASING_PASCAL_CASE: { - root_name = root_name.capitalize().replace(" ", ""); + root_name = root_name.to_pascal_case(); } break; case SCENE_NAME_CASING_SNAKE_CASE: - root_name = root_name.capitalize().replace(" ", "").replace("-", "_").camelcase_to_underscore(); + root_name = root_name.replace("-", "_").to_snake_case(); break; } file->set_current_path(root_name + "." + extensions.front()->get().to_lower()); @@ -2909,7 +2941,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir()); } break; case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: { - OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().plus_file("android")); + OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().path_join("android")); } break; case FILE_QUIT: case RUN_PROJECT_MANAGER: @@ -3446,7 +3478,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, // Only try to load the script if it has a name. Else, the plugin has no init script. if (script_path.length() > 0) { - script_path = addon_path.get_base_dir().plus_file(script_path); + script_path = addon_path.get_base_dir().path_join(script_path); script = ResourceLoader::load(script_path); if (script.is_null()) { @@ -3703,6 +3735,18 @@ void EditorNode::fix_dependencies(const String &p_for_file) { int EditorNode::new_scene() { int idx = editor_data.add_edited_scene(-1); + // Remove placeholder empty scene. + if (editor_data.get_edited_scene_count() > 1) { + for (int i = 0; i < editor_data.get_edited_scene_count() - 1; i++) { + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); + if (!unsaved && editor_data.get_scene_path(i).is_empty()) { + editor_data.remove_scene(i); + idx--; + } + } + } + idx = MAX(idx, 0); + _scene_tab_changed(idx); editor_data.clear_editor_states(); _update_scene_tabs(); @@ -4067,6 +4111,7 @@ void EditorNode::register_editor_types() { GDREGISTER_CLASS(EditorSyntaxHighlighter); GDREGISTER_ABSTRACT_CLASS(EditorInterface); GDREGISTER_CLASS(EditorExportPlugin); + GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform); GDREGISTER_CLASS(EditorResourceConversionPlugin); GDREGISTER_CLASS(EditorSceneFormatImporter); GDREGISTER_CLASS(EditorScenePostImportPlugin); @@ -4552,7 +4597,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) { } if (nrect != dock_select_rect_over_idx) { - dock_select->update(); + dock_select->queue_redraw(); dock_select_rect_over_idx = nrect; } @@ -4578,7 +4623,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) { dock_popup_selected_idx = nrect; dock_slot[nrect]->set_current_tab(dock_slot[nrect]->get_tab_count() - 1); dock_slot[nrect]->show(); - dock_select->update(); + dock_select->queue_redraw(); _update_dock_containers(); @@ -4590,7 +4635,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) { void EditorNode::_dock_popup_exit() { dock_select_rect_over_idx = -1; - dock_select->update(); + dock_select->queue_redraw(); } void EditorNode::_dock_pre_popup(int p_which) { @@ -4608,7 +4653,7 @@ void EditorNode::_dock_move_left() { } dock_slot[dock_popup_selected_idx]->move_child(current, prev->get_index()); dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() - 1); - dock_select->update(); + dock_select->queue_redraw(); _edit_current(); _save_docks(); } @@ -4621,7 +4666,7 @@ void EditorNode::_dock_move_right() { } dock_slot[dock_popup_selected_idx]->move_child(next, current->get_index()); dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() + 1); - dock_select->update(); + dock_select->queue_redraw(); _edit_current(); _save_docks(); } @@ -4719,13 +4764,13 @@ void EditorNode::_save_docks() { Ref<ConfigFile> config; config.instantiate(); // Load and amend existing config if it exists. - config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); + config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); _save_docks_to_config(config, "docks"); _save_open_scenes_to_config(config, "EditorNode"); editor_data.get_plugin_window_layout(config); - config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); + config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); } void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) { @@ -4789,7 +4834,7 @@ void EditorNode::_dock_split_dragged(int ofs) { void EditorNode::_load_docks() { Ref<ConfigFile> config; config.instantiate(); - Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); + Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); if (err != OK) { // No config. if (overridden_default_layout >= 0) { @@ -5022,7 +5067,7 @@ bool EditorNode::has_scenes_in_session() { } Ref<ConfigFile> config; config.instantiate(); - Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); + Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); if (err != OK) { return false; } @@ -5674,7 +5719,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str for (int i = 0; i < p_files.size(); i++) { String from = p_files[i]; - String to = to_path.plus_file(from.get_file()); + String to = to_path.path_join(from.get_file()); if (dir->dir_exists(from)) { Vector<String> sub_files; @@ -5689,7 +5734,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str continue; } - sub_files.push_back(from.plus_file(next_file)); + sub_files.push_back(from.path_join(next_file)); next_file = sub_dir->get_next(); } @@ -6476,8 +6521,11 @@ EditorNode::EditorNode() { tab_preview->set_position(Point2(2, 2) * EDSCALE); tab_preview_panel->add_child(tab_preview); + tabbar_panel = memnew(PanelContainer); + tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))); + srt->add_child(tabbar_panel); tabbar_container = memnew(HBoxContainer); - srt->add_child(tabbar_container); + tabbar_panel->add_child(tabbar_container); scene_tabs = memnew(TabBar); scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles"))); @@ -6504,7 +6552,7 @@ EditorNode::EditorNode() { scene_tab_add = memnew(Button); scene_tab_add->set_flat(true); - scene_tab_add->set_tooltip(TTR("Add a new scene.")); + scene_tab_add->set_tooltip_text(TTR("Add a new scene.")); scene_tab_add->set_icon(gui_base->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); scene_tab_add->add_theme_color_override("icon_normal_color", Color(0.6f, 0.6f, 0.6f, 0.8f)); scene_tabs->add_child(scene_tab_add); @@ -6520,7 +6568,7 @@ EditorNode::EditorNode() { ED_SHORTCUT_AND_COMMAND("editor/distraction_free_mode", TTR("Distraction Free Mode"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F11); ED_SHORTCUT_OVERRIDE("editor/distraction_free_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::D); distraction_free->set_shortcut(ED_GET_SHORTCUT("editor/distraction_free_mode")); - distraction_free->set_tooltip(TTR("Toggle distraction-free mode.")); + distraction_free->set_tooltip_text(TTR("Toggle distraction-free mode.")); distraction_free->connect("pressed", callable_mp(this, &EditorNode::_toggle_distraction_free_mode)); distraction_free->set_icon(gui_base->get_theme_icon(SNAME("DistractionFree"), SNAME("EditorIcons"))); distraction_free->set_toggle_mode(true); @@ -6572,7 +6620,7 @@ EditorNode::EditorNode() { prev_scene = memnew(Button); prev_scene->set_flat(true); prev_scene->set_icon(gui_base->get_theme_icon(SNAME("PrevScene"), SNAME("EditorIcons"))); - prev_scene->set_tooltip(TTR("Go to previously opened scene.")); + prev_scene->set_tooltip_text(TTR("Go to previously opened scene.")); prev_scene->set_disabled(true); prev_scene->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(FILE_OPEN_PREV)); gui_base->add_child(prev_scene); @@ -6695,8 +6743,7 @@ EditorNode::EditorNode() { project_menu->add_child(vcs_actions_menu); project_menu->add_submenu_item(TTR("Version Control"), "Version Control"); vcs_actions_menu->add_item(TTR("Create Version Control Metadata"), RUN_VCS_METADATA); - vcs_actions_menu->add_item(TTR("Set Up Version Control"), RUN_VCS_SETTINGS); - vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN); + vcs_actions_menu->add_item(TTR("Version Control Settings"), RUN_VCS_SETTINGS); project_menu->add_separator(); project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT); @@ -6811,12 +6858,16 @@ EditorNode::EditorNode() { right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS); menu_hb->add_child(right_spacer); - HBoxContainer *play_hb = memnew(HBoxContainer); - menu_hb->add_child(play_hb); + launch_pad = memnew(PanelContainer); + launch_pad->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("LaunchPadNormal"), SNAME("EditorStyles"))); + menu_hb->add_child(launch_pad); + + HBoxContainer *launch_pad_hb = memnew(HBoxContainer); + launch_pad->add_child(launch_pad_hb); play_button = memnew(Button); play_button->set_flat(true); - play_hb->add_child(play_button); + launch_pad_hb->add_child(play_button); play_button->set_toggle_mode(true); play_button->set_focus_mode(Control::FOCUS_NONE); play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY)); @@ -6830,9 +6881,9 @@ EditorNode::EditorNode() { pause_button->set_toggle_mode(true); pause_button->set_icon(gui_base->get_theme_icon(SNAME("Pause"), SNAME("EditorIcons"))); pause_button->set_focus_mode(Control::FOCUS_NONE); - pause_button->set_tooltip(TTR("Pause the scene execution for debugging.")); + pause_button->set_tooltip_text(TTR("Pause the scene execution for debugging.")); pause_button->set_disabled(true); - play_hb->add_child(pause_button); + launch_pad_hb->add_child(pause_button); ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), Key::F7); ED_SHORTCUT_OVERRIDE("editor/pause_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::Y); @@ -6840,11 +6891,11 @@ EditorNode::EditorNode() { stop_button = memnew(Button); stop_button->set_flat(true); - play_hb->add_child(stop_button); + launch_pad_hb->add_child(stop_button); stop_button->set_focus_mode(Control::FOCUS_NONE); stop_button->set_icon(gui_base->get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_STOP)); - stop_button->set_tooltip(TTR("Stop the scene.")); + stop_button->set_tooltip_text(TTR("Stop the scene.")); stop_button->set_disabled(true); ED_SHORTCUT("editor/stop", TTR("Stop"), Key::F8); @@ -6852,12 +6903,12 @@ EditorNode::EditorNode() { stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop")); run_native = memnew(EditorRunNative); - play_hb->add_child(run_native); + launch_pad_hb->add_child(run_native); run_native->connect("native_run", callable_mp(this, &EditorNode::_run_native)); play_scene_button = memnew(Button); play_scene_button->set_flat(true); - play_hb->add_child(play_scene_button); + launch_pad_hb->add_child(play_scene_button); play_scene_button->set_toggle_mode(true); play_scene_button->set_focus_mode(Control::FOCUS_NONE); play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE)); @@ -6868,7 +6919,7 @@ EditorNode::EditorNode() { play_custom_scene_button = memnew(Button); play_custom_scene_button->set_flat(true); - play_hb->add_child(play_custom_scene_button); + launch_pad_hb->add_child(play_custom_scene_button); play_custom_scene_button->set_toggle_mode(true); play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE); play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE)); @@ -6879,18 +6930,23 @@ EditorNode::EditorNode() { ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::R); play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene")); + write_movie_panel = memnew(PanelContainer); + write_movie_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("MovieWriterButtonNormal"), SNAME("EditorStyles"))); + launch_pad_hb->add_child(write_movie_panel); + write_movie_button = memnew(Button); write_movie_button->set_flat(true); write_movie_button->set_toggle_mode(true); - play_hb->add_child(write_movie_button); + write_movie_panel->add_child(write_movie_button); write_movie_button->set_pressed(false); write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons"))); write_movie_button->set_focus_mode(Control::FOCUS_NONE); - write_movie_button->set_tooltip(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file.")); + write_movie_button->connect("toggled", callable_mp(this, &EditorNode::_write_movie_toggled)); + write_movie_button->set_tooltip_text(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file.")); // This button behaves differently, so color it as such. write_movie_button->add_theme_color_override("icon_normal_color", Color(1, 1, 1, 0.7)); - write_movie_button->add_theme_color_override("icon_pressed_color", gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor"))); + write_movie_button->add_theme_color_override("icon_pressed_color", Color(0, 0, 0, 0.84)); write_movie_button->add_theme_color_override("icon_hover_color", Color(1, 1, 1, 0.9)); HBoxContainer *right_menu_hb = memnew(HBoxContainer); @@ -7073,7 +7129,7 @@ EditorNode::EditorNode() { // Fade out the version label to be less prominent, but still readable. version_btn->set_self_modulate(Color(1, 1, 1, 0.65)); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip(TTR("Click to copy.")); + version_btn->set_tooltip_text(TTR("Click to copy.")); version_btn->connect("pressed", callable_mp(this, &EditorNode::_version_button_pressed)); version_info_vbc->add_child(version_btn); @@ -7368,11 +7424,6 @@ EditorNode::EditorNode() { editor_plugins_force_over = memnew(EditorPluginList); editor_plugins_force_input_forwarding = memnew(EditorPluginList); - Ref<EditorExportTextSceneToBinaryPlugin> export_text_to_binary_plugin; - export_text_to_binary_plugin.instantiate(); - - EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin); - Ref<GDExtensionExportPlugin> gdextension_export_plugin; gdextension_export_plugin.instantiate(); @@ -7476,9 +7527,9 @@ EditorNode::EditorNode() { screenshot_timer->set_owner(get_owner()); // Adjust spacers to center 2D / 3D / Script buttons. - int max_w = MAX(play_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x); + int max_w = MAX(launch_pad_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x); left_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - main_menu->get_minimum_size().x), 0)); - right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - play_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0)); + right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - launch_pad_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0)); // Extend menu bar to window title. if (can_expand) { diff --git a/editor/editor_node.h b/editor/editor_node.h index 792d2fc879..c3b4c985cc 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -185,7 +185,6 @@ private: RUN_PROJECT_MANAGER, RUN_VCS_METADATA, RUN_VCS_SETTINGS, - RUN_VCS_SHUT_DOWN, SETTINGS_UPDATE_CONTINUOUSLY, SETTINGS_UPDATE_WHEN_CHANGED, SETTINGS_UPDATE_ALWAYS, @@ -335,15 +334,17 @@ private: PopupMenu *export_as_menu = nullptr; Button *export_button = nullptr; Button *prev_scene = nullptr; + Button *search_button = nullptr; + TextureProgressBar *audio_vu = nullptr; + + PanelContainer *launch_pad = nullptr; Button *play_button = nullptr; Button *pause_button = nullptr; Button *stop_button = nullptr; - Button *run_settings_button = nullptr; Button *play_scene_button = nullptr; Button *play_custom_scene_button = nullptr; - Button *search_button = nullptr; + PanelContainer *write_movie_panel = nullptr; Button *write_movie_button = nullptr; - TextureProgressBar *audio_vu = nullptr; Timer *screenshot_timer = nullptr; @@ -426,6 +427,7 @@ private: int dock_popup_selected_idx = -1; int dock_select_rect_over_idx = -1; + PanelContainer *tabbar_panel = nullptr; HBoxContainer *tabbar_container = nullptr; Button *distraction_free = nullptr; Button *scene_tab_add = nullptr; @@ -581,6 +583,8 @@ private: void _quick_run(); void _open_command_palette(); + void _write_movie_toggled(bool p_enabled); + void _run(bool p_current = false, const String &p_custom = ""); void _run_native(const Ref<EditorExportPreset> &p_preset); void _reset_play_buttons(); diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index adbfacd131..a8f8f7ab97 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -150,14 +150,14 @@ void EditorPath::update_path() { } current_object_label->set_text(" " + name); // An extra space so the text is not too close of the icon. - set_tooltip(obj->get_class()); + set_tooltip_text(obj->get_class()); } } } void EditorPath::clear_path() { set_disabled(true); - set_tooltip(""); + set_tooltip_text(""); current_object_label->set_text(""); current_object_icon->set_texture(nullptr); @@ -231,5 +231,5 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) { sub_objects_menu->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show)); sub_objects_menu->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed)); - set_tooltip(TTR("Open a list of sub-resources.")); + set_tooltip_text(TTR("Open a list of sub-resources.")); } diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp index b6364e1ab7..54d4660cb6 100644 --- a/editor/editor_paths.cpp +++ b/editor/editor_paths.cpp @@ -67,19 +67,19 @@ String EditorPaths::get_self_contained_file() const { } String EditorPaths::get_export_templates_dir() const { - return get_data_dir().plus_file(export_templates_folder); + return get_data_dir().path_join(export_templates_folder); } String EditorPaths::get_project_settings_dir() const { - return get_project_data_dir().plus_file("editor"); + return get_project_data_dir().path_join("editor"); } String EditorPaths::get_text_editor_themes_dir() const { - return get_config_dir().plus_file(text_editor_themes_folder); + return get_config_dir().path_join(text_editor_themes_folder); } String EditorPaths::get_script_templates_dir() const { - return get_config_dir().plus_file(script_templates_folder); + return get_config_dir().path_join(script_templates_folder); } String EditorPaths::get_project_script_templates_dir() const { @@ -87,7 +87,7 @@ String EditorPaths::get_project_script_templates_dir() const { } String EditorPaths::get_feature_profiles_dir() const { - return get_config_dir().plus_file(feature_profiles_folder); + return get_config_dir().path_join(feature_profiles_folder); } void EditorPaths::create() { @@ -119,8 +119,8 @@ EditorPaths::EditorPaths() { String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); // On macOS, look outside .app bundle, since .app bundle is read-only. - if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.plus_file("..").simplify_path().ends_with("Contents")) { - exe_path = exe_path.plus_file("../../..").simplify_path(); + if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.path_join("..").simplify_path().ends_with("Contents")) { + exe_path = exe_path.path_join("../../..").simplify_path(); } { Ref<DirAccess> d = DirAccess::create_for_path(exe_path); @@ -141,24 +141,24 @@ EditorPaths::EditorPaths() { if (self_contained) { // editor is self contained, all in same folder data_path = exe_path; - data_dir = data_path.plus_file("editor_data"); + data_dir = data_path.path_join("editor_data"); config_path = exe_path; config_dir = data_dir; cache_path = exe_path; - cache_dir = data_dir.plus_file("cache"); + cache_dir = data_dir.path_join("cache"); } else { // Typically XDG_DATA_HOME or %APPDATA%. data_path = OS::get_singleton()->get_data_path(); - data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + data_dir = data_path.path_join(OS::get_singleton()->get_godot_dir_name()); // Can be different from data_path e.g. on Linux or macOS. config_path = OS::get_singleton()->get_config_path(); - config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + config_dir = config_path.path_join(OS::get_singleton()->get_godot_dir_name()); // Can be different from above paths, otherwise a subfolder of data_dir. cache_path = OS::get_singleton()->get_cache_path(); if (cache_path == data_path) { - cache_dir = data_dir.plus_file("cache"); + cache_dir = data_dir.path_join("cache"); } else { - cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + cache_dir = cache_path.path_join(OS::get_singleton()->get_godot_dir_name()); } } @@ -232,7 +232,7 @@ EditorPaths::EditorPaths() { } // Check that the project data directory '.gdignore' file exists - String project_data_gdignore_file_path = project_data_dir.plus_file(".gdignore"); + String project_data_gdignore_file_path = project_data_dir.path_join(".gdignore"); if (!FileAccess::exists(project_data_gdignore_file_path)) { // Add an empty .gdignore file to avoid scan. Ref<FileAccess> f = FileAccess::open(project_data_gdignore_file_path, FileAccess::WRITE); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index b0bd500ef8..4fc6947636 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -599,7 +599,7 @@ int EditorPlugin::update_overlays() const { return count; } else { // This will update the normal viewport itself as well - CanvasItemEditor::get_singleton()->get_viewport_control()->update(); + CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw(); return 1; } } diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 5a010a66c1..a8df486381 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -102,7 +102,7 @@ void EditorPluginSettings::update_plugins() { TreeItem *item = plugin_list->create_item(root); item->set_text(0, name); - item->set_tooltip(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description); + item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description); item->set_metadata(0, path); item->set_text(1, version); item->set_metadata(1, script); @@ -178,8 +178,8 @@ Vector<String> EditorPluginSettings::_get_plugins(const String &p_dir) { continue; } - const String full_path = p_dir.plus_file(path); - const String plugin_config = full_path.plus_file("plugin.cfg"); + const String full_path = p_dir.path_join(path); + const String plugin_config = full_path.path_join("plugin.cfg"); if (FileAccess::exists(plugin_config)) { plugins.push_back(plugin_config); } else { diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index c70dc6bc51..d78fee6ad6 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -52,7 +52,7 @@ void EditorPropertyNil::update_property() { EditorPropertyNil::EditorPropertyNil() { Label *label = memnew(Label); - label->set_text("[null]"); + label->set_text("<null>"); add_child(label); } @@ -396,7 +396,7 @@ void EditorPropertyLocale::_locale_pressed() { void EditorPropertyLocale::update_property() { String locale_code = get_edited_object()->get(get_edited_property()); locale->set_text(locale_code); - locale->set_tooltip(locale_code); + locale->set_tooltip_text(locale_code); } void EditorPropertyLocale::setup(const String &p_hint_text) { @@ -485,7 +485,7 @@ void EditorPropertyPath::_path_pressed() { void EditorPropertyPath::update_property() { String full_path = get_edited_object()->get(get_edited_property()); path->set_text(full_path); - path->set_tooltip(full_path); + path->set_tooltip_text(full_path); } void EditorPropertyPath::setup(const Vector<String> &p_extensions, bool p_folder, bool p_global) { @@ -832,26 +832,35 @@ void EditorPropertyFlags::setup(const Vector<String> &p_options) { bool first = true; uint32_t current_val; for (int i = 0; i < p_options.size(); i++) { + // An empty option is not considered a "flag". String option = p_options[i].strip_edges(); - if (!option.is_empty()) { - CheckBox *cb = memnew(CheckBox); - cb->set_text(option); - cb->set_clip_text(true); - cb->connect("pressed", callable_mp(this, &EditorPropertyFlags::_flag_toggled).bind(i)); - add_focusable(cb); - vbox->add_child(cb); - flags.push_back(cb); - Vector<String> text_split = p_options[i].split(":"); - if (text_split.size() != 1) { - current_val = text_split[1].to_int(); - } else { - current_val = 1 << i; - } - flag_values.push_back(current_val); - if (first) { - set_label_reference(cb); - first = false; - } + if (option.is_empty()) { + continue; + } + const int flag_index = flags.size(); // Index of the next element (added by the code below). + + // Value for a flag can be explicitly overridden. + Vector<String> text_split = p_options[i].split(":"); + if (text_split.size() != 1) { + current_val = text_split[1].to_int(); + } else { + current_val = 1 << i; + } + flag_values.push_back(current_val); + + // Create a CheckBox for the current flag. + CheckBox *cb = memnew(CheckBox); + cb->set_text(option); + cb->set_clip_text(true); + cb->connect("pressed", callable_mp(this, &EditorPropertyFlags::_flag_toggled).bind(flag_index)); + add_focusable(cb); + vbox->add_child(cb); + flags.push_back(cb); + + // Can't use `i == 0` because we want to find the first none-empty option. + if (first) { + set_label_reference(cb); + first = false; } } } @@ -951,7 +960,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) { bool expand_was_hovered = expand_hovered; expand_hovered = expand_rect.has_point(mm->get_position()); if (expand_hovered != expand_was_hovered) { - update(); + queue_redraw(); } if (!expand_hovered) { @@ -959,7 +968,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) { if (flag_rects[i].has_point(mm->get_position())) { // Used to highlight the hovered flag in the layers grid. hovered_index = i; - update(); + queue_redraw(); return; } } @@ -968,7 +977,7 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) { // Remove highlight when no square is hovered. if (hovered_index != -1) { hovered_index = -1; - update(); + queue_redraw(); } return; @@ -986,11 +995,11 @@ void EditorPropertyLayersGrid::gui_input(const Ref<InputEvent> &p_ev) { } emit_signal(SNAME("flag_changed"), value); - update(); + queue_redraw(); } else if (expand_hovered) { expanded = !expanded; update_minimum_size(); - update(); + queue_redraw(); } } if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { @@ -1131,11 +1140,11 @@ void EditorPropertyLayersGrid::_notification(int p_what) { case NOTIFICATION_MOUSE_EXIT: { if (expand_hovered) { expand_hovered = false; - update(); + queue_redraw(); } if (hovered_index != -1) { hovered_index = -1; - update(); + queue_redraw(); } } break; } @@ -1143,7 +1152,7 @@ void EditorPropertyLayersGrid::_notification(int p_what) { void EditorPropertyLayersGrid::set_flag(uint32_t p_flag) { value = p_flag; - update(); + queue_redraw(); } void EditorPropertyLayersGrid::_bind_methods() { @@ -1276,7 +1285,7 @@ void EditorPropertyLayers::_menu_pressed(int p_menu) { } else { grid->value |= (1 << p_menu); } - grid->update(); + grid->queue_redraw(); layers->set_item_checked(layers->get_item_index(p_menu), grid->value & (1 << p_menu)); _grid_changed(grid->value); } @@ -1382,7 +1391,7 @@ void EditorPropertyObjectID::update_property() { edit->set_disabled(false); edit->set_icon(EditorNode::get_singleton()->get_class_icon(type)); } else { - edit->set_text(TTR("[Empty]")); + edit->set_text(TTR("<empty>")); edit->set_disabled(true); edit->set_icon(Ref<Texture2D>()); } @@ -1523,13 +1532,13 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) { // Ensure the easing doesn't appear as being dragged dragging = false; - easing_draw->update(); + easing_draw->queue_redraw(); } if (mb->get_button_index() == MouseButton::LEFT) { dragging = mb->is_pressed(); // Update to display the correct dragging color - easing_draw->update(); + easing_draw->queue_redraw(); } } @@ -1569,7 +1578,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) { val = CLAMP(val, -1'000'000, 1'000'000); emit_changed(get_edited_property(), val); - easing_draw->update(); + easing_draw->queue_redraw(); } } @@ -1621,14 +1630,14 @@ void EditorPropertyEasing::_draw_easing() { } void EditorPropertyEasing::update_property() { - easing_draw->update(); + easing_draw->queue_redraw(); } void EditorPropertyEasing::_set_preset(int p_preset) { static const float preset_value[EASING_MAX] = { 0.0, 1.0, 2.0, 0.5, -2.0, -0.5 }; emit_changed(get_edited_property(), preset_value[p_preset]); - easing_draw->update(); + easing_draw->queue_redraw(); } void EditorPropertyEasing::_setup_spin() { @@ -1667,7 +1676,7 @@ void EditorPropertyEasing::_spin_focus_exited() { spin->hide(); // Ensure the easing doesn't appear as being dragged dragging = false; - easing_draw->update(); + easing_draw->queue_redraw(); } void EditorPropertyEasing::setup(bool p_positive_only, bool p_flip) { @@ -3515,14 +3524,14 @@ void EditorPropertyColor::update_property() { // Add a tooltip to display each channel's values without having to click the ColorPickerButton if (picker->is_editing_alpha()) { - picker->set_tooltip(vformat( + picker->set_tooltip_text(vformat( "R: %s\nG: %s\nB: %s\nA: %s", rtos(color.r).pad_decimals(2), rtos(color.g).pad_decimals(2), rtos(color.b).pad_decimals(2), rtos(color.a).pad_decimals(2))); } else { - picker->set_tooltip(vformat( + picker->set_tooltip_text(vformat( "R: %s\nG: %s\nB: %s", rtos(color.r).pad_decimals(2), rtos(color.g).pad_decimals(2), @@ -3680,7 +3689,7 @@ void EditorPropertyNodePath::update_property() { p = get_edited_object()->get(get_edited_property()); } - assign->set_tooltip(p); + assign->set_tooltip_text(p); if (p == NodePath()) { assign->set_icon(Ref<Texture2D>()); assign->set_text(TTR("Assign...")); @@ -3952,7 +3961,7 @@ void EditorPropertyResource::_update_property_bg() { } updating_theme = false; - update(); + queue_redraw(); } void EditorPropertyResource::_update_preferred_shader() { diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 9a83082d1e..ad84b30689 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -509,7 +509,7 @@ void EditorPropertyArray::_notification(int p_what) { if (is_visible_in_tree()) { if (_is_drop_valid(get_viewport()->gui_get_drag_data())) { dropping = true; - edit->update(); + edit->queue_redraw(); } } } break; @@ -517,7 +517,7 @@ void EditorPropertyArray::_notification(int p_what) { case NOTIFICATION_DRAG_END: { if (dropping) { dropping = false; - edit->update(); + edit->queue_redraw(); } } break; } @@ -1111,7 +1111,7 @@ void EditorPropertyDictionary::update_property() { if (i < amount) { String cs = key.get_construct_string(); prop->set_label(key.get_construct_string()); - prop->set_tooltip(cs); + prop->set_tooltip_text(cs); change_index = i + offset; } else if (i == amount) { prop->set_label(TTR("New Key:")); @@ -1361,7 +1361,7 @@ void EditorPropertyLocalizableString::update_property() { String cs = key.get_construct_string(); prop->set_label(cs); - prop->set_tooltip(cs); + prop->set_tooltip_text(cs); remove_index = i + offset; prop->set_selectable(false); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 7e42c45b01..f717188b3b 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -61,8 +61,8 @@ void EditorResourcePicker::_update_resource() { if (edited_resource == Ref<Resource>()) { assign_button->set_icon(Ref<Texture2D>()); - assign_button->set_text(TTR("[empty]")); - assign_button->set_tooltip(""); + assign_button->set_text(TTR("<empty>")); + assign_button->set_tooltip_text(""); } else { assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object")); @@ -73,13 +73,13 @@ void EditorResourcePicker::_update_resource() { } else { assign_button->set_text(edited_resource->get_class()); } - assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class()); + assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class()); // Preview will override the above, so called at the end. EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id()); } } else if (edited_resource.is_valid()) { - assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class()); + assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class()); } assign_button->set_disabled(!editable && !edited_resource.is_valid()); @@ -108,7 +108,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const preview_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); thumbnail_size *= EDSCALE; - assign_button->set_custom_minimum_size(Size2(MIN(1, assign_button_min_size.x), MIN(thumbnail_size, assign_button_min_size.y))); + assign_button->set_custom_minimum_size(Size2(MAX(1, assign_button_min_size.x), MAX(thumbnail_size, assign_button_min_size.y))); } preview_rect->set_texture(p_preview); @@ -775,14 +775,14 @@ void EditorResourcePicker::_notification(int p_what) { case NOTIFICATION_DRAG_BEGIN: { if (editable && _is_drop_valid(get_viewport()->gui_get_drag_data())) { dropping = true; - assign_button->update(); + assign_button->queue_redraw(); } } break; case NOTIFICATION_DRAG_END: { if (dropping) { dropping = false; - assign_button->update(); + assign_button->queue_redraw(); } } break; } @@ -1049,7 +1049,7 @@ void EditorAudioStreamPicker::_notification(int p_what) { Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(audio_stream); if (preview.is_valid()) { if (preview->get_version() != last_preview_version) { - stream_preview_rect->update(); + stream_preview_rect->queue_redraw(); last_preview_version = preview->get_version(); } } @@ -1083,10 +1083,10 @@ void EditorAudioStreamPicker::_notification(int p_what) { } } - stream_preview_rect->update(); + stream_preview_rect->queue_redraw(); } else { if (tagged_frame_offset_count != 0) { - stream_preview_rect->update(); + stream_preview_rect->queue_redraw(); } tagged_frame_offset_count = 0; } @@ -1107,13 +1107,13 @@ void EditorAudioStreamPicker::_update_resource() { set_assign_button_min_size(Size2(1, font->get_height(font_size) * 1.5)); } - stream_preview_rect->update(); + stream_preview_rect->queue_redraw(); } void EditorAudioStreamPicker::_preview_draw() { Ref<AudioStream> audio_stream = get_edited_resource(); if (!audio_stream.is_valid()) { - get_assign_button()->set_text(TTR("[empty]")); + get_assign_button()->set_text(TTR("<empty>")); return; } diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index c0ea2b743e..706b77c142 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -244,7 +244,7 @@ void EditorResourcePreview::_iterate() { } else { String temp_path = EditorPaths::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text(); - cache_base = temp_path.plus_file("resthumb-" + cache_base); + cache_base = temp_path.path_join("resthumb-" + cache_base); //does not have it, try to load a cached thumbnail diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index 3b828951e4..b909129b18 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -258,6 +258,11 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) { } } + // Pass the debugger stop shortcut to the running instance(s). + String shortcut; + VariantWriter::write_to_string(ED_GET_SHORTCUT("editor/stop"), shortcut); + OS::get_singleton()->set_environment("__GODOT_EDITOR_STOP_SHORTCUT__", shortcut); + printf("Running: %s", exec.utf8().get_data()); for (const String &E : args) { printf(" %s", E.utf8().get_data()); diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index d8b738be17..3e8f17085d 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -77,9 +77,9 @@ void EditorRunNative::_notification(int p_what) { mb->get_popup()->clear(); mb->show(); if (dc == 1) { - mb->set_tooltip(eep->get_option_tooltip(0)); + mb->set_tooltip_text(eep->get_option_tooltip(0)); } else { - mb->set_tooltip(eep->get_options_tooltip()); + mb->set_tooltip_text(eep->get_options_tooltip()); for (int i = 0; i < dc; i++) { mb->get_popup()->add_icon_item(eep->get_option_icon(i), eep->get_option_label(i)); mb->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(i)); diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index 1faefb5af7..94ee741db5 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -283,7 +283,7 @@ void SectionedInspector::update_category_list() { const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style); ms->set_text(0, text); - ms->set_tooltip(0, tooltip); + ms->set_tooltip_text(0, tooltip); ms->set_metadata(0, metasection); ms->set_selectable(0, false); } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index dd4adbb28f..edd44b0a3a 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -856,7 +856,7 @@ void EditorSettings::create() { // Validate editor config file. Ref<DirAccess> dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir()); String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres"; - config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name); + config_file_path = EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name); if (!dir->file_exists(config_file_name)) { goto fail; } @@ -887,7 +887,7 @@ fail: if (extra_config->has_section("init_projects")) { Vector<String> list = extra_config->get_value("init_projects", "list"); for (int i = 0; i < list.size(); i++) { - list.write[i] = exe_path.plus_file(list[i]); + list.write[i] = exe_path.path_join(list[i]); } extra_config->set_value("init_projects", "list", list); } @@ -1106,7 +1106,7 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { Ref<ConfigFile> cf = memnew(ConfigFile); - String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg"); + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg"); Error err; err = cf->load(path); ERR_FAIL_COND_MSG(err != OK && err != ERR_FILE_NOT_FOUND, "Cannot load editor settings from file '" + path + "'."); @@ -1117,7 +1117,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const { Ref<ConfigFile> cf = memnew(ConfigFile); - String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg"); + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg"); Error err = cf->load(path); if (err != OK) { return p_default; @@ -1129,9 +1129,9 @@ void EditorSettings::set_favorites(const Vector<String> &p_favorites) { favorites = p_favorites; String favorites_file; if (Engine::get_singleton()->is_project_manager_hint()) { - favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs"); + favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs"); } else { - favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites"); + favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites"); } Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::WRITE); if (f.is_valid()) { @@ -1149,9 +1149,9 @@ void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) { recent_dirs = p_recent_dirs; String recent_dirs_file; if (Engine::get_singleton()->is_project_manager_hint()) { - recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs"); + recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs"); } else { - recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs"); + recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs"); } Ref<FileAccess> f = FileAccess::open(recent_dirs_file, FileAccess::WRITE); if (f.is_valid()) { @@ -1169,11 +1169,11 @@ void EditorSettings::load_favorites_and_recent_dirs() { String favorites_file; String recent_dirs_file; if (Engine::get_singleton()->is_project_manager_hint()) { - favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs"); - recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs"); + favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs"); + recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs"); } else { - favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites"); - recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs"); + favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites"); + recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs"); } Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::READ); if (f.is_valid()) { @@ -1236,7 +1236,7 @@ void EditorSettings::load_text_editor_theme() { return; // sorry for "Settings changed" console spam } - String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet"); + String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet"); Ref<ConfigFile> cf = memnew(ConfigFile); Error err = cf->load(theme_path); @@ -1273,7 +1273,7 @@ bool EditorSettings::import_text_editor_theme(String p_file) { Ref<DirAccess> d = DirAccess::open(EditorPaths::get_singleton()->get_text_editor_themes_dir()); if (d.is_valid()) { - d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file.get_file())); + d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file.get_file())); return true; } } @@ -1286,7 +1286,7 @@ bool EditorSettings::save_text_editor_theme() { if (_is_default_text_editor_theme(p_file.get_file().to_lower())) { return false; } - String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet"); + String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet"); return _save_text_editor_theme(theme_path); } @@ -1339,7 +1339,7 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c } String EditorSettings::get_editor_layouts_config() const { - return EditorPaths::get_singleton()->get_config_dir().plus_file("editor_layouts.cfg"); + return EditorPaths::get_singleton()->get_config_dir().path_join("editor_layouts.cfg"); } float EditorSettings::get_auto_display_scale() const { @@ -1477,8 +1477,11 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c } } - // Directly override the existing shortcut. - sc->set_events(events); + // Override the existing shortcut only if it wasn't customized by the user (i.e. still "original"). + if (Shortcut::is_event_array_equal(sc->get_events(), sc->get_meta("original"))) { + sc->set_events(events); + } + sc->set_meta("original", events.duplicate(true)); } diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 67c602ad2d..d190ab57c3 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -440,7 +440,7 @@ void EditorSettingsDialog::_update_shortcuts() { const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style); section->set_text(0, item_name); - section->set_tooltip(0, tooltip); + section->set_tooltip_text(0, tooltip); section->set_selectable(0, false); section->set_selectable(1, false); section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 5b98460e8e..33632649c8 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -82,7 +82,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) { if (grabbing_spinner) { Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); Input::get_singleton()->warp_mouse(grabbing_spinner_mouse_pos); - update(); + queue_redraw(); } else { _focus_entered(); } @@ -93,7 +93,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) { } } else if (mb->get_button_index() == MouseButton::WHEEL_UP || mb->get_button_index() == MouseButton::WHEEL_DOWN) { if (grabber->is_visible()) { - call_deferred(SNAME("update")); + call_deferred(SNAME("queue_redraw")); } } } @@ -137,7 +137,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) { bool new_hover = (mm->get_position().x > updown_offset); if (new_hover != hover_updown) { hover_updown = new_hover; - update(); + queue_redraw(); } } } @@ -149,8 +149,16 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) { } void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) { + if (read_only) { + return; + } + Ref<InputEventMouseButton> mb = p_event; + if (is_read_only()) { + return; + } + if (grabbing_grabber) { if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::WHEEL_UP) { @@ -186,13 +194,13 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(Math::is_zero_approx(scale_x)); float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range) / scale_x; set_as_ratio(grabbing_ratio + grabbing_ofs); - update(); + queue_redraw(); } } void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; - if (k.is_valid() && k->is_pressed()) { + if (k.is_valid() && k->is_pressed() && !is_read_only()) { double step = get_step(); double real_step = step; if (step < 1) { @@ -459,12 +467,12 @@ void EditorSpinSlider::_notification(int p_what) { case NOTIFICATION_MOUSE_ENTER: { mouse_over_spin = true; - update(); + queue_redraw(); } break; case NOTIFICATION_MOUSE_EXIT: { mouse_over_spin = false; - update(); + queue_redraw(); } break; case NOTIFICATION_FOCUS_ENTER: { @@ -494,7 +502,7 @@ Size2 EditorSpinSlider::get_minimum_size() const { void EditorSpinSlider::set_hide_slider(bool p_hide) { hide_slider = p_hide; - update(); + queue_redraw(); } bool EditorSpinSlider::is_hiding_slider() const { @@ -503,7 +511,7 @@ bool EditorSpinSlider::is_hiding_slider() const { void EditorSpinSlider::set_label(const String &p_label) { label = p_label; - update(); + queue_redraw(); } String EditorSpinSlider::get_label() const { @@ -512,7 +520,7 @@ String EditorSpinSlider::get_label() const { void EditorSpinSlider::set_suffix(const String &p_suffix) { suffix = p_suffix; - update(); + queue_redraw(); } String EditorSpinSlider::get_suffix() const { @@ -579,17 +587,17 @@ void EditorSpinSlider::_value_focus_exited() { void EditorSpinSlider::_grabber_mouse_entered() { mouse_over_grabber = true; - update(); + queue_redraw(); } void EditorSpinSlider::_grabber_mouse_exited() { mouse_over_grabber = false; - update(); + queue_redraw(); } void EditorSpinSlider::set_read_only(bool p_enable) { read_only = p_enable; - update(); + queue_redraw(); } bool EditorSpinSlider::is_read_only() const { @@ -598,7 +606,7 @@ bool EditorSpinSlider::is_read_only() const { void EditorSpinSlider::set_flat(bool p_enable) { flat = p_enable; - update(); + queue_redraw(); } bool EditorSpinSlider::is_flat() const { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 827a657a31..af0e40d1d4 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -476,6 +476,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color font_color = mono_color.lerp(base_color, 0.25); const Color font_hover_color = mono_color.lerp(base_color, 0.125); const Color font_focus_color = mono_color.lerp(base_color, 0.125); + const Color font_hover_pressed_color = font_hover_color.lerp(accent_color, 0.74); const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3); const Color font_readonly_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.65); const Color font_placeholder_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.6); @@ -655,45 +656,46 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // TabBar - Ref<StyleBoxFlat> style_tab_selected = style_widget->duplicate(); + Ref<StyleBoxFlat> style_tab_base = style_widget->duplicate(); - // Add a highlight line at the top of the selected tab. - style_tab_selected->set_border_width_all(0); - style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x - border_width); - style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * EDSCALE)); - // Make the highlight line prominent, but not too prominent as to not be distracting. - Color tab_highlight = dark_color_2.lerp(accent_color, 0.75); - style_tab_selected->set_border_color(tab_highlight); + style_tab_base->set_border_width_all(0); // Don't round the top corners to avoid creating a small blank space between the tabs and the main panel. // This also makes the top highlight look better. - style_tab_selected->set_corner_radius_all(0); + style_tab_base->set_corner_detail(corner_width); + style_tab_base->set_corner_radius_all(0); + style_tab_base->set_corner_radius(CORNER_TOP_LEFT, corner_radius * EDSCALE); + style_tab_base->set_corner_radius(CORNER_TOP_RIGHT, corner_radius * EDSCALE); // Prevent visible artifacts and cover the top-left rounded corner of the panel below the tab if selected // We can't prevent them with both rounded corners and non-zero border width, though - style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width); - + style_tab_base->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width); // When using a border width greater than 0, visually line up the left of the selected tab with the underlying panel. - style_tab_selected->set_expand_margin_size(SIDE_LEFT, -border_width); + style_tab_base->set_expand_margin_size(SIDE_LEFT, -border_width); + + style_tab_base->set_default_margin(SIDE_LEFT, widget_default_margin.x + 5 * EDSCALE); + style_tab_base->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 5 * EDSCALE); + style_tab_base->set_default_margin(SIDE_BOTTOM, widget_default_margin.y); + style_tab_base->set_default_margin(SIDE_TOP, widget_default_margin.y); + + Ref<StyleBoxFlat> style_tab_selected = style_tab_base->duplicate(); - style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE); - style_tab_selected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE); - style_tab_selected->set_default_margin(SIDE_BOTTOM, widget_default_margin.y); - style_tab_selected->set_default_margin(SIDE_TOP, widget_default_margin.y); style_tab_selected->set_bg_color(base_color); + // Add a highlight line at the top of the selected tab. + style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * EDSCALE)); + // Make the highlight line prominent, but not too prominent as to not be distracting. + Color tab_highlight = dark_color_2.lerp(accent_color, 0.75); + style_tab_selected->set_border_color(tab_highlight); + style_tab_selected->set_corner_radius_all(0); - Ref<StyleBoxFlat> style_tab_unselected = style_tab_selected->duplicate(); - style_tab_unselected->set_bg_color(dark_color_1); + Ref<StyleBoxFlat> style_tab_unselected = style_tab_base->duplicate(); style_tab_unselected->set_expand_margin_size(SIDE_BOTTOM, 0); + style_tab_unselected->set_bg_color(dark_color_1); // Add some spacing between unselected tabs to make them easier to distinguish from each other style_tab_unselected->set_border_color(Color(0, 0, 0, 0)); - style_tab_unselected->set_border_width(SIDE_LEFT, Math::round(1 * EDSCALE)); - style_tab_unselected->set_border_width(SIDE_RIGHT, Math::round(1 * EDSCALE)); - style_tab_unselected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE); - style_tab_unselected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE); - Ref<StyleBoxFlat> style_tab_disabled = style_tab_selected->duplicate(); - style_tab_disabled->set_bg_color(disabled_bg_color); + Ref<StyleBoxFlat> style_tab_disabled = style_tab_base->duplicate(); style_tab_disabled->set_expand_margin_size(SIDE_BOTTOM, 0); + style_tab_disabled->set_bg_color(disabled_bg_color); style_tab_disabled->set_border_color(disabled_bg_color); // Editor background @@ -739,8 +741,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("ScriptEditorPanel", "EditorStyles", make_empty_stylebox(default_margin_size, 0, default_margin_size, default_margin_size)); theme->set_stylebox("ScriptEditor", "EditorStyles", make_empty_stylebox(0, 0, 0, 0)); - // Play button group - theme->set_stylebox("PlayButtonPanel", "EditorStyles", style_empty); + // Launch Pad and Play buttons + Ref<StyleBoxFlat> style_launch_pad = make_flat_stylebox(dark_color_1, 2 * EDSCALE, 0, 2 * EDSCALE, 0, corner_width); + style_launch_pad->set_corner_radius_all(corner_radius * EDSCALE); + theme->set_stylebox("LaunchPadNormal", "EditorStyles", style_launch_pad); + Ref<StyleBoxFlat> style_launch_pad_movie = style_launch_pad->duplicate(); + style_launch_pad_movie->set_bg_color(accent_color * Color(1, 1, 1, 0.1)); + style_launch_pad_movie->set_border_color(accent_color); + style_launch_pad_movie->set_border_width_all(Math::round(2 * EDSCALE)); + theme->set_stylebox("LaunchPadMovieMode", "EditorStyles", style_launch_pad_movie); + + theme->set_stylebox("MovieWriterButtonNormal", "EditorStyles", make_empty_stylebox(0, 0, 0, 0)); + Ref<StyleBoxFlat> style_write_movie_button = style_widget_pressed->duplicate(); + style_write_movie_button->set_bg_color(accent_color); + style_write_movie_button->set_corner_radius_all(corner_radius * EDSCALE); + style_write_movie_button->set_default_margin(SIDE_TOP, 0); + style_write_movie_button->set_default_margin(SIDE_BOTTOM, 0); + style_write_movie_button->set_default_margin(SIDE_LEFT, 0); + style_write_movie_button->set_default_margin(SIDE_RIGHT, 0); + style_write_movie_button->set_expand_margin_size(SIDE_RIGHT, 2 * EDSCALE); + theme->set_stylebox("MovieWriterButtonPressed", "EditorStyles", style_write_movie_button); theme->set_stylebox("normal", "MenuButton", style_menu); theme->set_stylebox("hover", "MenuButton", style_widget_hover); @@ -750,6 +770,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "MenuButton", font_color); theme->set_color("font_hover_color", "MenuButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "MenuButton", font_hover_pressed_color); theme->set_color("font_focus_color", "MenuButton", font_focus_color); theme->set_stylebox("MenuHover", "EditorStyles", style_widget_hover); @@ -763,6 +784,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "Button", font_color); theme->set_color("font_hover_color", "Button", font_hover_color); + theme->set_color("font_hover_pressed_color", "Button", font_hover_pressed_color); theme->set_color("font_focus_color", "Button", font_focus_color); theme->set_color("font_pressed_color", "Button", accent_color); theme->set_color("font_disabled_color", "Button", font_disabled_color); @@ -815,6 +837,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "MenuBar", font_color); theme->set_color("font_hover_color", "MenuBar", font_hover_color); + theme->set_color("font_hover_pressed_color", "MenuBar", font_hover_pressed_color); theme->set_color("font_focus_color", "MenuBar", font_focus_color); theme->set_color("font_pressed_color", "MenuBar", accent_color); theme->set_color("font_disabled_color", "MenuBar", font_disabled_color); @@ -851,6 +874,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "OptionButton", font_color); theme->set_color("font_hover_color", "OptionButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "OptionButton", font_hover_pressed_color); theme->set_color("font_focus_color", "OptionButton", font_focus_color); theme->set_color("font_pressed_color", "OptionButton", accent_color); theme->set_color("font_disabled_color", "OptionButton", font_disabled_color); @@ -885,6 +909,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "CheckButton", font_color); theme->set_color("font_hover_color", "CheckButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckButton", font_hover_pressed_color); theme->set_color("font_focus_color", "CheckButton", font_focus_color); theme->set_color("font_pressed_color", "CheckButton", accent_color); theme->set_color("font_disabled_color", "CheckButton", font_disabled_color); @@ -921,6 +946,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "CheckBox", font_color); theme->set_color("font_hover_color", "CheckBox", font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckBox", font_hover_pressed_color); theme->set_color("font_focus_color", "CheckBox", font_focus_color); theme->set_color("font_pressed_color", "CheckBox", accent_color); theme->set_color("font_disabled_color", "CheckBox", font_disabled_color); @@ -1192,6 +1218,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_constant("line_separation", "ItemList", 3 * EDSCALE); // TabBar & TabContainer + Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(dark_color_1, 0, 0, 0, 0); + style_tabbar_background->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width); + style_tabbar_background->set_corner_detail(corner_width); + style_tabbar_background->set_corner_radius(CORNER_TOP_LEFT, corner_radius * EDSCALE); + style_tabbar_background->set_corner_radius(CORNER_TOP_RIGHT, corner_radius * EDSCALE); + theme->set_stylebox("tabbar_background", "TabContainer", style_tabbar_background); + theme->set_stylebox("tab_selected", "TabContainer", style_tab_selected); theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected); theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled); @@ -1227,14 +1260,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_content_panel = style_default->duplicate(); style_content_panel->set_border_color(dark_color_3); style_content_panel->set_border_width_all(border_width); + style_content_panel->set_border_width(Side::SIDE_TOP, 0); + style_content_panel->set_corner_radius(CORNER_TOP_LEFT, 0); + style_content_panel->set_corner_radius(CORNER_TOP_RIGHT, 0); // compensate the border style_content_panel->set_default_margin(SIDE_TOP, (2 + margin_size_extra) * EDSCALE); style_content_panel->set_default_margin(SIDE_RIGHT, margin_size_extra * EDSCALE); style_content_panel->set_default_margin(SIDE_BOTTOM, margin_size_extra * EDSCALE); style_content_panel->set_default_margin(SIDE_LEFT, margin_size_extra * EDSCALE); - // Display border to visually split the body of the container from its possible backgrounds. - style_content_panel->set_border_width(Side::SIDE_TOP, Math::round(2 * EDSCALE)); - style_content_panel->set_border_color(dark_color_2); theme->set_stylebox("panel", "TabContainer", style_content_panel); // TabContainerOdd can be used on tabs against the base color background (e.g. nested tabs). @@ -1478,6 +1511,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("focus", "LinkButton", style_empty); theme->set_color("font_color", "LinkButton", font_color); theme->set_color("font_hover_color", "LinkButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "LinkButton", font_hover_pressed_color); theme->set_color("font_focus_color", "LinkButton", font_focus_color); theme->set_color("font_pressed_color", "LinkButton", accent_color); theme->set_color("font_disabled_color", "LinkButton", font_disabled_color); @@ -1508,8 +1542,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { control_editor_popup_style->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE); control_editor_popup_style->set_border_width_all(0); - theme->set_stylebox("panel", "ControlEditorPopupButton", control_editor_popup_style); - theme->set_type_variation("ControlEditorPopupButton", "PopupPanel"); + theme->set_stylebox("panel", "ControlEditorPopupPanel", control_editor_popup_style); + theme->set_type_variation("ControlEditorPopupPanel", "PopupPanel"); // SpinBox theme->set_icon("updown", "SpinBox", theme->get_icon(SNAME("GuiSpinboxUpdown"), SNAME("EditorIcons"))); diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp index 050cde6069..5b015fc95c 100644 --- a/editor/editor_toaster.cpp +++ b/editor/editor_toaster.cpp @@ -62,7 +62,7 @@ void EditorToaster::_notification(int p_what) { if (toasts[element.key].remaining_time < 0) { close(element.key); } - element.key->update(); + element.key->queue_redraw(); } } else { // Reset the timers when hovered. @@ -71,7 +71,7 @@ void EditorToaster::_notification(int p_what) { continue; } toasts[element.key].remaining_time = element.value.duration; - element.key->update(); + element.key->queue_redraw(); } } @@ -101,7 +101,7 @@ void EditorToaster::_notification(int p_what) { if (needs_update) { _update_vbox_position(); _update_disable_notifications_button(); - main_button->update(); + main_button->queue_redraw(); } } break; @@ -132,8 +132,8 @@ void EditorToaster::_notification(int p_what) { error_panel_style_progress->set_bg_color(get_theme_color(SNAME("base_color"), SNAME("Editor")).lightened(0.03)); error_panel_style_progress->set_border_color(get_theme_color(SNAME("error_color"), SNAME("Editor"))); - main_button->update(); - disable_notifications_button->update(); + main_button->queue_redraw(); + disable_notifications_button->queue_redraw(); } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -236,11 +236,11 @@ void EditorToaster::_auto_hide_or_free_toasts() { } if (toasts.is_empty()) { - main_button->set_tooltip(TTR("No notifications.")); + main_button->set_tooltip_text(TTR("No notifications.")); main_button->set_modulate(Color(0.5, 0.5, 0.5)); main_button->set_disabled(true); } else { - main_button->set_tooltip(TTR("Show notifications.")); + main_button->set_tooltip_text(TTR("Show notifications.")); main_button->set_modulate(Color(1, 1, 1)); main_button->set_disabled(false); } @@ -334,14 +334,14 @@ void EditorToaster::_repop_old() { if (needs_update) { _update_vbox_position(); _update_disable_notifications_button(); - main_button->update(); + main_button->queue_redraw(); } } Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_time, String p_tooltip) { // Create the panel according to the severity. PanelContainer *panel = memnew(PanelContainer); - panel->set_tooltip(p_tooltip); + panel->set_tooltip_text(p_tooltip); switch (p_severity) { case SEVERITY_INFO: panel->add_theme_style_override("panel", info_panel_style_background); @@ -389,7 +389,7 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_ _auto_hide_or_free_toasts(); _update_vbox_position(); _update_disable_notifications_button(); - main_button->update(); + main_button->queue_redraw(); return panel; } @@ -438,7 +438,7 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t _auto_hide_or_free_toasts(); _update_vbox_position(); _update_disable_notifications_button(); - main_button->update(); + main_button->queue_redraw(); } // Retrieve the label back then update the text. @@ -518,7 +518,7 @@ EditorToaster::EditorToaster() { // Main button. main_button = memnew(Button); - main_button->set_tooltip(TTR("No notifications.")); + main_button->set_tooltip_text(TTR("No notifications.")); main_button->set_modulate(Color(0.5, 0.5, 0.5)); main_button->set_disabled(true); main_button->set_flat(true); @@ -534,7 +534,7 @@ EditorToaster::EditorToaster() { add_child(disable_notifications_panel); disable_notifications_button = memnew(Button); - disable_notifications_button->set_tooltip(TTR("Silence the notifications.")); + disable_notifications_button->set_tooltip_text(TTR("Silence the notifications.")); disable_notifications_button->set_flat(true); disable_notifications_button->connect("pressed", callable_mp(this, &EditorToaster::_set_notifications_enabled).bind(false)); disable_notifications_panel->add_child(disable_notifications_button); diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp index cb188f9c3e..0c6c876b2f 100644 --- a/editor/editor_vcs_interface.cpp +++ b/editor/editor_vcs_interface.cpp @@ -30,132 +30,371 @@ #include "editor_vcs_interface.h" +#include "editor_node.h" + +#define UNIMPLEMENTED() ERR_PRINT(vformat("Unimplemented virtual function in EditorVCSInterface based plugin: %s", __func__)) + EditorVCSInterface *EditorVCSInterface::singleton = nullptr; -void EditorVCSInterface::_bind_methods() { - // Proxy end points that act as fallbacks to unavailability of a function in the VCS addon - ClassDB::bind_method(D_METHOD("_initialize", "project_root_path"), &EditorVCSInterface::_initialize); - ClassDB::bind_method(D_METHOD("_is_vcs_initialized"), &EditorVCSInterface::_is_vcs_initialized); - ClassDB::bind_method(D_METHOD("_get_vcs_name"), &EditorVCSInterface::_get_vcs_name); - ClassDB::bind_method(D_METHOD("_shut_down"), &EditorVCSInterface::_shut_down); - ClassDB::bind_method(D_METHOD("_get_project_name"), &EditorVCSInterface::_get_project_name); - ClassDB::bind_method(D_METHOD("_get_modified_files_data"), &EditorVCSInterface::_get_modified_files_data); - ClassDB::bind_method(D_METHOD("_commit", "msg"), &EditorVCSInterface::_commit); - ClassDB::bind_method(D_METHOD("_get_file_diff", "file_path"), &EditorVCSInterface::_get_file_diff); - ClassDB::bind_method(D_METHOD("_stage_file", "file_path"), &EditorVCSInterface::_stage_file); - ClassDB::bind_method(D_METHOD("_unstage_file", "file_path"), &EditorVCSInterface::_unstage_file); +void EditorVCSInterface::popup_error(String p_msg) { + // TRANSLATORS: %s refers to the name of a version control system (e.g. "Git"). + EditorNode::get_singleton()->show_warning(p_msg.strip_edges(), vformat(TTR("%s Error"), get_vcs_name())); +} - ClassDB::bind_method(D_METHOD("is_addon_ready"), &EditorVCSInterface::is_addon_ready); +bool EditorVCSInterface::initialize(String p_project_path) { + bool result = false; + if (!GDVIRTUAL_CALL(_initialize, p_project_path, result)) { + UNIMPLEMENTED(); + return false; + } + return result; +} - // API methods that redirect calls to the proxy end points - ClassDB::bind_method(D_METHOD("initialize", "project_root_path"), &EditorVCSInterface::initialize); - ClassDB::bind_method(D_METHOD("is_vcs_initialized"), &EditorVCSInterface::is_vcs_initialized); - ClassDB::bind_method(D_METHOD("get_modified_files_data"), &EditorVCSInterface::get_modified_files_data); - ClassDB::bind_method(D_METHOD("stage_file", "file_path"), &EditorVCSInterface::stage_file); - ClassDB::bind_method(D_METHOD("unstage_file", "file_path"), &EditorVCSInterface::unstage_file); - ClassDB::bind_method(D_METHOD("commit", "msg"), &EditorVCSInterface::commit); - ClassDB::bind_method(D_METHOD("get_file_diff", "file_path"), &EditorVCSInterface::get_file_diff); - ClassDB::bind_method(D_METHOD("shut_down"), &EditorVCSInterface::shut_down); - ClassDB::bind_method(D_METHOD("get_project_name"), &EditorVCSInterface::get_project_name); - ClassDB::bind_method(D_METHOD("get_vcs_name"), &EditorVCSInterface::get_vcs_name); +void EditorVCSInterface::set_credentials(String p_username, String p_password, String p_ssh_public_key, String p_ssh_private_key, String p_ssh_passphrase) { + if (!GDVIRTUAL_CALL(_set_credentials, p_username, p_password, p_ssh_public_key, p_ssh_private_key, p_ssh_passphrase)) { + UNIMPLEMENTED(); + } } -bool EditorVCSInterface::_initialize(String p_project_root_path) { - WARN_PRINT("Selected VCS addon does not implement an initialization function. This warning will be suppressed."); - return true; +List<String> EditorVCSInterface::get_remotes() { + Array result; + if (!GDVIRTUAL_CALL(_get_remotes, result)) { + UNIMPLEMENTED(); + return {}; + } + + List<String> remotes; + for (int i = 0; i < result.size(); i++) { + remotes.push_back(result[i]); + } + return remotes; } -bool EditorVCSInterface::_is_vcs_initialized() { - return false; +List<EditorVCSInterface::StatusFile> EditorVCSInterface::get_modified_files_data() { + Array result; + if (!GDVIRTUAL_CALL(_get_modified_files_data, result)) { + UNIMPLEMENTED(); + return {}; + } + + List<EditorVCSInterface::StatusFile> status_files; + for (int i = 0; i < result.size(); i++) { + status_files.push_back(_convert_status_file(result[i])); + } + return status_files; } -Dictionary EditorVCSInterface::_get_modified_files_data() { - return Dictionary(); +void EditorVCSInterface::stage_file(String p_file_path) { + if (!GDVIRTUAL_CALL(_stage_file, p_file_path)) { + UNIMPLEMENTED(); + } } -void EditorVCSInterface::_stage_file(String p_file_path) { +void EditorVCSInterface::unstage_file(String p_file_path) { + if (!GDVIRTUAL_CALL(_unstage_file, p_file_path)) { + UNIMPLEMENTED(); + } } -void EditorVCSInterface::_unstage_file(String p_file_path) { +void EditorVCSInterface::discard_file(String p_file_path) { + if (!GDVIRTUAL_CALL(_discard_file, p_file_path)) { + UNIMPLEMENTED(); + } } -void EditorVCSInterface::_commit(String p_msg) { +void EditorVCSInterface::commit(String p_msg) { + if (!GDVIRTUAL_CALL(_commit, p_msg)) { + UNIMPLEMENTED(); + } } -TypedArray<Dictionary> EditorVCSInterface::_get_file_diff(String p_file_path) { - return TypedArray<Dictionary>(); +List<EditorVCSInterface::DiffFile> EditorVCSInterface::get_diff(String p_identifier, TreeArea p_area) { + TypedArray<Dictionary> result; + if (!GDVIRTUAL_CALL(_get_diff, p_identifier, int(p_area), result)) { + UNIMPLEMENTED(); + return {}; + } + + List<DiffFile> diff_files; + for (int i = 0; i < result.size(); i++) { + diff_files.push_back(_convert_diff_file(result[i])); + } + return diff_files; } -bool EditorVCSInterface::_shut_down() { - return false; +List<EditorVCSInterface::Commit> EditorVCSInterface::get_previous_commits(int p_max_commits) { + Array result; + if (!GDVIRTUAL_CALL(_get_previous_commits, p_max_commits, result)) { + UNIMPLEMENTED(); + return {}; + } + + List<EditorVCSInterface::Commit> commits; + for (int i = 0; i < result.size(); i++) { + commits.push_back(_convert_commit(result[i])); + } + return commits; } -String EditorVCSInterface::_get_project_name() { - return String(); +List<String> EditorVCSInterface::get_branch_list() { + Array result; + if (!GDVIRTUAL_CALL(_get_branch_list, result)) { + UNIMPLEMENTED(); + return {}; + } + + List<String> branch_list; + for (int i = 0; i < result.size(); i++) { + branch_list.push_back(result[i]); + } + return branch_list; } -String EditorVCSInterface::_get_vcs_name() { - return ""; +void EditorVCSInterface::create_branch(String p_branch_name) { + if (!GDVIRTUAL_CALL(_create_branch, p_branch_name)) { + UNIMPLEMENTED(); + } } -bool EditorVCSInterface::initialize(String p_project_root_path) { - is_initialized = call("_initialize", p_project_root_path); - return is_initialized; +void EditorVCSInterface::create_remote(String p_remote_name, String p_remote_url) { + if (!GDVIRTUAL_CALL(_create_remote, p_remote_name, p_remote_url)) { + UNIMPLEMENTED(); + } } -bool EditorVCSInterface::is_vcs_initialized() { - return call("_is_vcs_initialized"); +void EditorVCSInterface::remove_branch(String p_branch_name) { + if (!GDVIRTUAL_CALL(_remove_branch, p_branch_name)) { + UNIMPLEMENTED(); + } } -Dictionary EditorVCSInterface::get_modified_files_data() { - return call("_get_modified_files_data"); +void EditorVCSInterface::remove_remote(String p_remote_name) { + if (!GDVIRTUAL_CALL(_remove_remote, p_remote_name)) { + UNIMPLEMENTED(); + } } -void EditorVCSInterface::stage_file(String p_file_path) { - if (is_addon_ready()) { - call("_stage_file", p_file_path); +String EditorVCSInterface::get_current_branch_name() { + String result; + if (!GDVIRTUAL_CALL(_get_current_branch_name, result)) { + UNIMPLEMENTED(); + return ""; } + return result; } -void EditorVCSInterface::unstage_file(String p_file_path) { - if (is_addon_ready()) { - call("_unstage_file", p_file_path); +bool EditorVCSInterface::checkout_branch(String p_branch_name) { + bool result = false; + if (!GDVIRTUAL_CALL(_checkout_branch, p_branch_name, result)) { + UNIMPLEMENTED(); } + return result; } -bool EditorVCSInterface::is_addon_ready() { - return is_initialized; +void EditorVCSInterface::pull(String p_remote) { + if (!GDVIRTUAL_CALL(_pull, p_remote)) { + UNIMPLEMENTED(); + } } -void EditorVCSInterface::commit(String p_msg) { - if (is_addon_ready()) { - call("_commit", p_msg); +void EditorVCSInterface::push(String p_remote, bool p_force) { + if (!GDVIRTUAL_CALL(_push, p_remote, p_force)) { + UNIMPLEMENTED(); } } -TypedArray<Dictionary> EditorVCSInterface::get_file_diff(String p_file_path) { - if (is_addon_ready()) { - return call("_get_file_diff", p_file_path); +void EditorVCSInterface::fetch(String p_remote) { + if (!GDVIRTUAL_CALL(_fetch, p_remote)) { + UNIMPLEMENTED(); } - return TypedArray<Dictionary>(); } -bool EditorVCSInterface::shut_down() { - return call("_shut_down"); +List<EditorVCSInterface::DiffHunk> EditorVCSInterface::get_line_diff(String p_file_path, String p_text) { + Array result; + if (!GDVIRTUAL_CALL(_get_line_diff, p_file_path, p_text, result)) { + UNIMPLEMENTED(); + return {}; + } + + List<DiffHunk> diff_hunks; + for (int i = 0; i < result.size(); i++) { + diff_hunks.push_back(_convert_diff_hunk(result[i])); + } + return diff_hunks; } -String EditorVCSInterface::get_project_name() { - return call("_get_project_name"); +bool EditorVCSInterface::shut_down() { + bool result = false; + if (!GDVIRTUAL_CALL(_shut_down, result)) { + UNIMPLEMENTED(); + return false; + } + return result; } String EditorVCSInterface::get_vcs_name() { - return call("_get_vcs_name"); + String result; + if (!GDVIRTUAL_CALL(_get_vcs_name, result)) { + UNIMPLEMENTED(); + return {}; + } + return result; +} + +Dictionary EditorVCSInterface::create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status) { + Dictionary diff_line; + diff_line["new_line_no"] = p_new_line_no; + diff_line["old_line_no"] = p_old_line_no; + diff_line["content"] = p_content; + diff_line["status"] = p_status; + + return diff_line; +} + +Dictionary EditorVCSInterface::create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines) { + Dictionary diff_hunk; + diff_hunk["new_lines"] = p_new_lines; + diff_hunk["old_lines"] = p_old_lines; + diff_hunk["new_start"] = p_new_start; + diff_hunk["old_start"] = p_old_start; + diff_hunk["diff_lines"] = Array(); + return diff_hunk; +} + +Dictionary EditorVCSInterface::add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, Array p_line_diffs) { + p_diff_hunk["diff_lines"] = p_line_diffs; + return p_diff_hunk; +} + +Dictionary EditorVCSInterface::create_diff_file(String p_new_file, String p_old_file) { + Dictionary file_diff; + file_diff["new_file"] = p_new_file; + file_diff["old_file"] = p_old_file; + file_diff["diff_hunks"] = Array(); + return file_diff; +} + +Dictionary EditorVCSInterface::create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes) { + Dictionary commit_info; + commit_info["message"] = p_msg; + commit_info["author"] = p_author; + commit_info["unix_timestamp"] = p_unix_timestamp; + commit_info["offset_minutes"] = p_offset_minutes; + commit_info["id"] = p_id; + return commit_info; } -EditorVCSInterface::EditorVCSInterface() { +Dictionary EditorVCSInterface::add_diff_hunks_into_diff_file(Dictionary p_diff_file, Array p_diff_hunks) { + p_diff_file["diff_hunks"] = p_diff_hunks; + return p_diff_file; } -EditorVCSInterface::~EditorVCSInterface() { +Dictionary EditorVCSInterface::create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area) { + Dictionary sf; + sf["file_path"] = p_file_path; + sf["change_type"] = p_change; + sf["area"] = p_area; + return sf; +} + +EditorVCSInterface::DiffLine EditorVCSInterface::_convert_diff_line(Dictionary p_diff_line) { + DiffLine d; + d.new_line_no = p_diff_line["new_line_no"]; + d.old_line_no = p_diff_line["old_line_no"]; + d.content = p_diff_line["content"]; + d.status = p_diff_line["status"]; + return d; +} + +EditorVCSInterface::DiffHunk EditorVCSInterface::_convert_diff_hunk(Dictionary p_diff_hunk) { + DiffHunk dh; + dh.new_lines = p_diff_hunk["new_lines"]; + dh.old_lines = p_diff_hunk["old_lines"]; + dh.new_start = p_diff_hunk["new_start"]; + dh.old_start = p_diff_hunk["old_start"]; + Array diff_lines = p_diff_hunk["diff_lines"]; + for (int i = 0; i < diff_lines.size(); i++) { + DiffLine dl = _convert_diff_line(diff_lines[i]); + dh.diff_lines.push_back(dl); + } + return dh; +} + +EditorVCSInterface::DiffFile EditorVCSInterface::_convert_diff_file(Dictionary p_diff_file) { + DiffFile df; + df.new_file = p_diff_file["new_file"]; + df.old_file = p_diff_file["old_file"]; + Array diff_hunks = p_diff_file["diff_hunks"]; + for (int i = 0; i < diff_hunks.size(); i++) { + DiffHunk dh = _convert_diff_hunk(diff_hunks[i]); + df.diff_hunks.push_back(dh); + } + return df; +} + +EditorVCSInterface::Commit EditorVCSInterface::_convert_commit(Dictionary p_commit) { + EditorVCSInterface::Commit c; + c.msg = p_commit["message"]; + c.author = p_commit["author"]; + c.unix_timestamp = p_commit["unix_timestamp"]; + c.offset_minutes = p_commit["offset_minutes"]; + c.id = p_commit["id"]; + return c; +} + +EditorVCSInterface::StatusFile EditorVCSInterface::_convert_status_file(Dictionary p_status_file) { + StatusFile sf; + sf.file_path = p_status_file["file_path"]; + sf.change_type = (ChangeType)(int)p_status_file["change_type"]; + sf.area = (TreeArea)(int)p_status_file["area"]; + return sf; +} + +void EditorVCSInterface::_bind_methods() { + // Proxy end points that implement the VCS specific operations that the editor demands. + GDVIRTUAL_BIND(_initialize, "project_path"); + GDVIRTUAL_BIND(_set_credentials, "username", "password", "ssh_public_key_path", "ssh_private_key_path", "ssh_passphrase"); + GDVIRTUAL_BIND(_get_modified_files_data); + GDVIRTUAL_BIND(_stage_file, "file_path"); + GDVIRTUAL_BIND(_unstage_file, "file_path"); + GDVIRTUAL_BIND(_discard_file, "file_path"); + GDVIRTUAL_BIND(_commit, "msg"); + GDVIRTUAL_BIND(_get_diff, "identifier", "area"); + GDVIRTUAL_BIND(_shut_down); + GDVIRTUAL_BIND(_get_vcs_name); + GDVIRTUAL_BIND(_get_previous_commits, "max_commits"); + GDVIRTUAL_BIND(_get_branch_list); + GDVIRTUAL_BIND(_get_remotes); + GDVIRTUAL_BIND(_create_branch, "branch_name"); + GDVIRTUAL_BIND(_remove_branch, "branch_name"); + GDVIRTUAL_BIND(_create_remote, "remote_name", "remote_url"); + GDVIRTUAL_BIND(_remove_remote, "remote_name"); + GDVIRTUAL_BIND(_get_current_branch_name); + GDVIRTUAL_BIND(_checkout_branch, "branch_name"); + GDVIRTUAL_BIND(_pull, "remote"); + GDVIRTUAL_BIND(_push, "remote", "force"); + GDVIRTUAL_BIND(_fetch, "remote"); + GDVIRTUAL_BIND(_get_line_diff, "file_path", "text"); + + ClassDB::bind_method(D_METHOD("create_diff_line", "new_line_no", "old_line_no", "content", "status"), &EditorVCSInterface::create_diff_line); + ClassDB::bind_method(D_METHOD("create_diff_hunk", "old_start", "new_start", "old_lines", "new_lines"), &EditorVCSInterface::create_diff_hunk); + ClassDB::bind_method(D_METHOD("create_diff_file", "new_file", "old_file"), &EditorVCSInterface::create_diff_file); + ClassDB::bind_method(D_METHOD("create_commit", "msg", "author", "id", "unix_timestamp", "offset_minutes"), &EditorVCSInterface::create_commit); + ClassDB::bind_method(D_METHOD("create_status_file", "file_path", "change_type", "area"), &EditorVCSInterface::create_status_file); + ClassDB::bind_method(D_METHOD("add_diff_hunks_into_diff_file", "diff_file", "diff_hunks"), &EditorVCSInterface::add_diff_hunks_into_diff_file); + ClassDB::bind_method(D_METHOD("add_line_diffs_into_diff_hunk", "diff_hunk", "line_diffs"), &EditorVCSInterface::add_line_diffs_into_diff_hunk); + ClassDB::bind_method(D_METHOD("popup_error", "msg"), &EditorVCSInterface::popup_error); + + BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW); + BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED); + BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED); + BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED); + BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE); + BIND_ENUM_CONSTANT(CHANGE_TYPE_UNMERGED); + + BIND_ENUM_CONSTANT(TREE_AREA_COMMIT); + BIND_ENUM_CONSTANT(TREE_AREA_STAGED); + BIND_ENUM_CONSTANT(TREE_AREA_UNSTAGED); } EditorVCSInterface *EditorVCSInterface::get_singleton() { @@ -168,16 +407,16 @@ void EditorVCSInterface::set_singleton(EditorVCSInterface *p_singleton) { void EditorVCSInterface::create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir) { if (p_vcs_metadata_type == VCSMetadata::GIT) { - Ref<FileAccess> f = FileAccess::open(p_dir.plus_file(".gitignore"), FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(p_dir.path_join(".gitignore"), FileAccess::WRITE); if (f.is_null()) { - ERR_FAIL_MSG(TTR("Couldn't create .gitignore in project path.")); + ERR_FAIL_MSG("Couldn't create .gitignore in project path."); } else { f->store_line("# Godot 4+ specific ignores"); f->store_line(".godot/"); } - f = FileAccess::open(p_dir.plus_file(".gitattributes"), FileAccess::WRITE); + f = FileAccess::open(p_dir.path_join(".gitattributes"), FileAccess::WRITE); if (f.is_null()) { - ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path.")); + ERR_FAIL_MSG("Couldn't create .gitattributes in project path."); } else { f->store_line("# Normalize EOL for all files that Git considers text files."); f->store_line("* text=auto eol=lf"); diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h index d6d7ffa0e9..e23e032ab9 100644 --- a/editor/editor_vcs_interface.h +++ b/editor/editor_vcs_interface.h @@ -32,30 +32,103 @@ #define EDITOR_VCS_INTERFACE_H #include "core/object/class_db.h" +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language_extension.h" #include "core/string/ustring.h" -#include "scene/gui/panel_container.h" +#include "core/variant/type_info.h" class EditorVCSInterface : public Object { GDCLASS(EditorVCSInterface, Object) - bool is_initialized = false; +public: + enum ChangeType { + CHANGE_TYPE_NEW = 0, + CHANGE_TYPE_MODIFIED = 1, + CHANGE_TYPE_RENAMED = 2, + CHANGE_TYPE_DELETED = 3, + CHANGE_TYPE_TYPECHANGE = 4, + CHANGE_TYPE_UNMERGED = 5 + }; + + enum TreeArea { + TREE_AREA_COMMIT = 0, + TREE_AREA_STAGED = 1, + TREE_AREA_UNSTAGED = 2 + }; + + struct DiffLine { + int new_line_no; + int old_line_no; + String content; + String status; + + String old_text; + String new_text; + }; + + struct DiffHunk { + int new_start; + int old_start; + int new_lines; + int old_lines; + List<DiffLine> diff_lines; + }; + + struct DiffFile { + String new_file; + String old_file; + List<DiffHunk> diff_hunks; + }; + + struct Commit { + String author; + String msg; + String id; + int64_t unix_timestamp; + int64_t offset_minutes; + }; + + struct StatusFile { + TreeArea area; + ChangeType change_type; + String file_path; + }; protected: static EditorVCSInterface *singleton; static void _bind_methods(); - // Implemented by addons as end points for the proxy functions - virtual bool _initialize(String p_project_root_path); - virtual bool _is_vcs_initialized(); - virtual Dictionary _get_modified_files_data(); - virtual void _stage_file(String p_file_path); - virtual void _unstage_file(String p_file_path); - virtual void _commit(String p_msg); - virtual TypedArray<Dictionary> _get_file_diff(String p_file_path); - virtual bool _shut_down(); - virtual String _get_project_name(); - virtual String _get_vcs_name(); + DiffLine _convert_diff_line(Dictionary p_diff_line); + DiffHunk _convert_diff_hunk(Dictionary p_diff_hunk); + DiffFile _convert_diff_file(Dictionary p_diff_file); + Commit _convert_commit(Dictionary p_commit); + StatusFile _convert_status_file(Dictionary p_status_file); + + // Proxy endpoints for extensions to implement + GDVIRTUAL1R(bool, _initialize, String); + GDVIRTUAL5(_set_credentials, String, String, String, String, String); + GDVIRTUAL0R(Array, _get_modified_files_data); + GDVIRTUAL1(_stage_file, String); + GDVIRTUAL1(_unstage_file, String); + GDVIRTUAL1(_discard_file, String); + GDVIRTUAL1(_commit, String); + GDVIRTUAL2R(TypedArray<Dictionary>, _get_diff, String, int); + GDVIRTUAL0R(bool, _shut_down); + GDVIRTUAL0R(String, _get_vcs_name); + GDVIRTUAL1R(Array, _get_previous_commits, int); + GDVIRTUAL0R(Array, _get_branch_list); + GDVIRTUAL0R(Array, _get_remotes); + GDVIRTUAL1(_create_branch, String); + GDVIRTUAL1(_remove_branch, String); + GDVIRTUAL2(_create_remote, String, String); + GDVIRTUAL1(_remove_remote, String); + GDVIRTUAL0R(String, _get_current_branch_name); + GDVIRTUAL1R(bool, _checkout_branch, String); + GDVIRTUAL1(_pull, String); + GDVIRTUAL2(_push, String, bool); + GDVIRTUAL1(_fetch, String); + GDVIRTUAL2R(Array, _get_line_diff, String, String); public: static EditorVCSInterface *get_singleton(); @@ -67,22 +140,44 @@ public: }; static void create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir); - bool is_addon_ready(); - - // Proxy functions to the editor for use - bool initialize(String p_project_root_path); - bool is_vcs_initialized(); - Dictionary get_modified_files_data(); + // Proxies to the editor for use + bool initialize(String p_project_path); + void set_credentials(String p_username, String p_password, String p_ssh_public_key_path, String p_ssh_private_key_path, String p_ssh_passphrase); + List<StatusFile> get_modified_files_data(); void stage_file(String p_file_path); void unstage_file(String p_file_path); + void discard_file(String p_file_path); void commit(String p_msg); - TypedArray<Dictionary> get_file_diff(String p_file_path); + List<DiffFile> get_diff(String p_identifier, TreeArea p_area); bool shut_down(); - String get_project_name(); String get_vcs_name(); + List<Commit> get_previous_commits(int p_max_commits); + List<String> get_branch_list(); + List<String> get_remotes(); + void create_branch(String p_branch_name); + void remove_branch(String p_branch_name); + void create_remote(String p_remote_name, String p_remote_url); + void remove_remote(String p_remote_name); + String get_current_branch_name(); + bool checkout_branch(String p_branch_name); + void pull(String p_remote); + void push(String p_remote, bool p_force); + void fetch(String p_remote); + List<DiffHunk> get_line_diff(String p_file_path, String p_text); - EditorVCSInterface(); - virtual ~EditorVCSInterface(); + // Helper functions to create and convert Dictionary into data structures + Dictionary create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status); + Dictionary create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines); + Dictionary create_diff_file(String p_new_file, String p_old_file); + Dictionary create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes); + Dictionary create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area); + Dictionary add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, Array p_line_diffs); + Dictionary add_diff_hunks_into_diff_file(Dictionary p_diff_file, Array p_diff_hunks); + + void popup_error(String p_msg); }; +VARIANT_ENUM_CAST(EditorVCSInterface::ChangeType); +VARIANT_ENUM_CAST(EditorVCSInterface::TreeArea); + #endif // EDITOR_VCS_INTERFACE_H diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index d291040bd2..29b6a5e546 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -351,6 +351,8 @@ EditorExport::EditorExport() { singleton = this; set_process(true); + + GLOBAL_DEF("editor/export/convert_text_resources_to_binary", true); } EditorExport::~EditorExport() { diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 8283c24e61..525a962222 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -44,6 +44,7 @@ #include "editor/editor_settings.h" #include "editor/plugins/script_editor_plugin.h" #include "editor_export_plugin.h" +#include "scene/resources/packed_scene.h" static int _get_pad(int p_alignment, int p_n) { int rest = p_n % p_alignment; @@ -295,7 +296,7 @@ Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const { String EditorExportPlatform::find_export_template(String template_file_name, String *err) const { String current_version = VERSION_FULL_CONFIG; - String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(current_version).plus_file(template_file_name); + String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(current_version).path_join(template_file_name); if (FileAccess::exists(template_path)) { return template_path; @@ -488,6 +489,295 @@ EditorExportPlatform::ExportNotifier::~ExportNotifier() { } } +bool EditorExportPlatform::_export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) { + bool changed = false; + + List<Variant> keys; + dict.get_key_list(&keys); + for (const Variant &K : keys) { + Variant v = dict[K]; + switch (v.get_type()) { + case Variant::OBJECT: { + Ref<Resource> res = v; + if (res.is_valid()) { + for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) { + Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, ""); + if (new_res.is_valid()) { + changed = true; + if (new_res != res) { + dict[K] = new_res; + res = new_res; + } + break; + } + } + + // If it was not replaced, go through and see if there is something to replace. + if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) { + changed = true; + } + } + + } break; + case Variant::DICTIONARY: { + Dictionary d = v; + if (_export_customize_dictionary(d, customize_resources_plugins)) { + changed = true; + } + } break; + case Variant::ARRAY: { + Array a = v; + if (_export_customize_array(a, customize_resources_plugins)) { + changed = true; + } + } break; + default: { + } + } + } + return changed; +} + +bool EditorExportPlatform::_export_customize_array(Array &arr, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) { + bool changed = false; + + for (int i = 0; i < arr.size(); i++) { + Variant v = arr.get(i); + switch (v.get_type()) { + case Variant::OBJECT: { + Ref<Resource> res = v; + if (res.is_valid()) { + for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) { + Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, ""); + if (new_res.is_valid()) { + changed = true; + if (new_res != res) { + arr.set(i, new_res); + res = new_res; + } + break; + } + } + + // If it was not replaced, go through and see if there is something to replace. + if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) { + changed = true; + } + } + } break; + case Variant::DICTIONARY: { + Dictionary d = v; + if (_export_customize_dictionary(d, customize_resources_plugins)) { + changed = true; + } + } break; + case Variant::ARRAY: { + Array a = v; + if (_export_customize_array(a, customize_resources_plugins)) { + changed = true; + } + } break; + default: { + } + } + } + return changed; +} + +bool EditorExportPlatform::_export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) { + bool changed = false; + + List<PropertyInfo> props; + p_object->get_property_list(&props); + for (const PropertyInfo &E : props) { + switch (E.type) { + case Variant::OBJECT: { + Ref<Resource> res = p_object->get(E.name); + if (res.is_valid()) { + for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) { + Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, ""); + if (new_res.is_valid()) { + changed = true; + if (new_res != res) { + p_object->set(E.name, new_res); + res = new_res; + } + break; + } + } + + // If it was not replaced, go through and see if there is something to replace. + if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) { + changed = true; + } + } + + } break; + case Variant::DICTIONARY: { + Dictionary d = p_object->get(E.name); + if (_export_customize_dictionary(d, customize_resources_plugins)) { + // May have been generated, so set back just in case + p_object->set(E.name, d); + changed = true; + } + } break; + case Variant::ARRAY: { + Array a = p_object->get(E.name); + if (_export_customize_array(a, customize_resources_plugins)) { + // May have been generated, so set back just in case + p_object->set(E.name, a); + changed = true; + } + } break; + default: { + } + } + } + return changed; +} + +bool EditorExportPlatform::_export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) { + bool changed = false; + + if (p_node == p_root || p_node->get_owner() == p_root) { + if (_export_customize_object(p_node, customize_resources_plugins)) { + changed = true; + } + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + if (_export_customize_scene_resources(p_root, p_node->get_child(i), customize_resources_plugins)) { + changed = true; + } + } + + return changed; +} + +String EditorExportPlatform::_export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save) { + if (!p_force_save && customize_resources_plugins.is_empty() && customize_scenes_plugins.is_empty()) { + return p_path; // do none + } + + // Check if a cache exists + if (export_cache.has(p_path)) { + FileExportCache &fec = export_cache[p_path]; + + if (fec.saved_path.is_empty() || FileAccess::exists(fec.saved_path)) { + // Destination file exists (was not erased) or not needed + + uint64_t mod_time = FileAccess::get_modified_time(p_path); + if (fec.source_modified_time == mod_time) { + // Cached (modified time matches). + fec.used = true; + return fec.saved_path.is_empty() ? p_path : fec.saved_path; + } + + String md5 = FileAccess::get_md5(p_path); + if (FileAccess::exists(p_path + ".import")) { + // Also consider the import file in the string + md5 += FileAccess::get_md5(p_path + ".import"); + } + if (fec.source_md5 == md5) { + // Cached (md5 matches). + fec.source_modified_time = mod_time; + fec.used = true; + return fec.saved_path.is_empty() ? p_path : fec.saved_path; + } + } + } + + FileExportCache fec; + fec.used = true; + fec.source_modified_time = FileAccess::get_modified_time(p_path); + + String md5 = FileAccess::get_md5(p_path); + if (FileAccess::exists(p_path + ".import")) { + // Also consider the import file in the string + md5 += FileAccess::get_md5(p_path + ".import"); + } + + fec.source_md5 = md5; + + // Check if it should convert + + String type = ResourceLoader::get_resource_type(p_path); + + bool modified = false; + + String save_path; + + if (type == "PackedScene") { // Its a scene. + Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE); + ERR_FAIL_COND_V(ps.is_null(), p_path); + Node *node = ps->instantiate(); + ERR_FAIL_COND_V(node == nullptr, p_path); + if (customize_scenes_plugins.size()) { + for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) { + Node *customized = customize_scenes_plugins[i]->_customize_scene(node, p_path); + if (customized != nullptr) { + node = customized; + modified = true; + } + } + } + if (customize_resources_plugins.size()) { + if (_export_customize_scene_resources(node, node, customize_resources_plugins)) { + modified = true; + } + } + + if (modified || p_force_save) { + // If modified, save it again. This is also used for TSCN -> SCN conversion on export. + + String base_file = p_path.get_file().get_basename() + ".scn"; // use SCN for saving (binary) and repack (If conversting, TSCN PackedScene representation is inefficient, so repacking is also desired). + save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file); + + Ref<PackedScene> s; + s.instantiate(); + s->pack(node); + Error err = ResourceSaver::save(s, save_path); + ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export scene file to: " + save_path); + } + } else { + Ref<Resource> res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE); + ERR_FAIL_COND_V(res.is_null(), p_path); + + if (customize_resources_plugins.size()) { + for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) { + Ref<Resource> new_res = customize_resources_plugins[i]->_customize_resource(res, p_path); + if (new_res.is_valid()) { + modified = true; + if (new_res != res) { + res = new_res; + } + break; + } + } + + if (_export_customize_object(res.ptr(), customize_resources_plugins)) { + modified = true; + } + } + + if (modified || p_force_save) { + // If modified, save it again. This is also used for TRES -> RES conversion on export. + + String base_file = p_path.get_file().get_basename() + ".res"; // use RES for saving (binary) + save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file); + + Error err = ResourceSaver::save(res, save_path); + ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export resource file to: " + save_path); + } + } + + fec.saved_path = save_path; + + export_cache[p_path] = fec; + + return save_path.is_empty() ? p_path : save_path; +} + Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) { //figure out paths of files that will be exported HashSet<String> paths; @@ -601,6 +891,15 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & Error err = OK; Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins(); + struct SortByName { + bool operator()(const Ref<EditorExportPlugin> &left, const Ref<EditorExportPlugin> &right) const { + return left->_get_name() < right->_get_name(); + } + }; + + // Always sort by name, to so if for some reason theya are re-arranged, it still works. + export_plugins.sort_custom<SortByName>(); + for (int i = 0; i < export_plugins.size(); i++) { export_plugins.write[i]->set_export_preset(p_preset); @@ -623,6 +922,65 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } HashSet<String> features = get_features(p_preset, p_debug); + PackedStringArray features_psa; + for (const String &feature : features) { + features_psa.push_back(feature); + } + + // Check if custom processing is needed + uint32_t custom_resources_hash = HASH_MURMUR3_SEED; + uint32_t custom_scene_hash = HASH_MURMUR3_SEED; + + LocalVector<Ref<EditorExportPlugin>> customize_resources_plugins; + LocalVector<Ref<EditorExportPlugin>> customize_scenes_plugins; + + for (int i = 0; i < export_plugins.size(); i++) { + if (export_plugins[i]->_begin_customize_resources(Ref<EditorExportPlatform>(this), features_psa)) { + customize_resources_plugins.push_back(export_plugins[i]); + + custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash); + uint64_t hash = export_plugins[i]->_get_customization_configuration_hash(); + custom_resources_hash = hash_murmur3_one_64(hash, custom_resources_hash); + } + if (export_plugins[i]->_begin_customize_scenes(Ref<EditorExportPlatform>(this), features_psa)) { + customize_scenes_plugins.push_back(export_plugins[i]); + + custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash); + uint64_t hash = export_plugins[i]->_get_customization_configuration_hash(); + custom_scene_hash = hash_murmur3_one_64(hash, custom_scene_hash); + } + } + + HashMap<String, FileExportCache> export_cache; + String export_base_path = ProjectSettings::get_singleton()->get_project_data_path().path_join("exported/") + itos(custom_resources_hash); + + bool convert_text_to_binary = GLOBAL_GET("editor/export/convert_text_resources_to_binary"); + + if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) { + // See if we have something to open + Ref<FileAccess> f = FileAccess::open(export_base_path.path_join("file_cache"), FileAccess::READ); + if (f.is_valid()) { + String l = f->get_line(); + while (l != String()) { + Vector<String> fields = l.split("::"); + if (fields.size() == 4) { + FileExportCache fec; + String path = fields[0]; + fec.source_md5 = fields[1].strip_edges(); + fec.source_modified_time = fields[2].strip_edges().to_int(); + fec.saved_path = fields[3]; + fec.used = false; // Assume unused until used. + export_cache[path] = fec; + } + l = f->get_line(); + } + } else { + // create the path + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + d->change_dir(ProjectSettings::get_singleton()->get_project_data_path()); + d->make_dir_recursive("exported/" + itos(custom_resources_hash)); + } + } //store everything in the export medium int idx = 0; @@ -633,85 +991,133 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String type = ResourceLoader::get_resource_type(path); if (FileAccess::exists(path + ".import")) { - //file is imported, replace by what it imports - Ref<ConfigFile> config; - config.instantiate(); - err = config->load(path + ".import"); - if (err != OK) { - ERR_PRINT("Could not parse: '" + path + "', not exported."); - continue; - } + // Before doing this, try to see if it can be customized - String importer_type = config->get_value("remap", "importer"); + String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, false); - if (importer_type == "keep") { - //just keep file as-is - Vector<uint8_t> array = FileAccess::get_file_as_array(path); - err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key); + if (export_path != path) { + // It was actually customized.. + // Since the original file is likely not recognized, just use the import system + Ref<ConfigFile> config; + config.instantiate(); + err = config->load(path + ".import"); + if (err != OK) { + ERR_PRINT("Could not parse: '" + path + "', not exported."); + continue; + } + config->set_value("remap", "type", ResourceLoader::get_resource_type(export_path)); + + // Erase all PAths + List<String> keys; + config->get_section_keys("remap", &keys); + for (const String &K : keys) { + if (E.begins_with("path")) { + config->erase_section_key("remap", K); + } + } + // Set actual converted path. + config->set_value("remap", "path", export_path); + + // erase useless sections + config->erase_section("deps"); + config->erase_section("params"); + + String import_text = config->encode_to_text(); + CharString cs = import_text.utf8(); + Vector<uint8_t> sarr; + sarr.resize(cs.size()); + memcpy(sarr.ptrw(), cs.ptr(), sarr.size()); + + err = p_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; } + // Now actual remapped file: + sarr = FileAccess::get_file_as_array(export_path); + err = p_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key); + if (err != OK) { + return err; + } + } else { + // file is imported and not customized, replace by what it imports + Ref<ConfigFile> config; + config.instantiate(); + err = config->load(path + ".import"); + if (err != OK) { + ERR_PRINT("Could not parse: '" + path + "', not exported."); + continue; + } - continue; - } + String importer_type = config->get_value("remap", "importer"); - List<String> remaps; - config->get_section_keys("remap", &remaps); + if (importer_type == "keep") { + //just keep file as-is + Vector<uint8_t> array = FileAccess::get_file_as_array(path); + err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key); - HashSet<String> remap_features; + if (err != OK) { + return err; + } - for (const String &F : remaps) { - String remap = F; - String feature = remap.get_slice(".", 1); - if (features.has(feature)) { - remap_features.insert(feature); + continue; } - } - if (remap_features.size() > 1) { - this->resolve_platform_feature_priorities(p_preset, remap_features); - } + List<String> remaps; + config->get_section_keys("remap", &remaps); - err = OK; + HashSet<String> remap_features; - for (const String &F : remaps) { - String remap = F; - if (remap == "path") { - String remapped_path = config->get_value("remap", remap); - Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); - err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); - } else if (remap.begins_with("path.")) { + for (const String &F : remaps) { + String remap = F; String feature = remap.get_slice(".", 1); + if (features.has(feature)) { + remap_features.insert(feature); + } + } - if (remap_features.has(feature)) { + if (remap_features.size() > 1) { + this->resolve_platform_feature_priorities(p_preset, remap_features); + } + + err = OK; + + for (const String &F : remaps) { + String remap = F; + if (remap == "path") { String remapped_path = config->get_value("remap", remap); Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); + } else if (remap.begins_with("path.")) { + String feature = remap.get_slice(".", 1); + + if (remap_features.has(feature)) { + String remapped_path = config->get_value("remap", remap); + Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); + err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); + } } } - } - if (err != OK) { - return err; - } + if (err != OK) { + return err; + } - //also save the .import file - Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import"); - err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key); + //also save the .import file + Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import"); + err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key); - if (err != OK) { - return err; + if (err != OK) { + return err; + } } } else { + // Customize + bool do_export = true; for (int i = 0; i < export_plugins.size(); i++) { if (export_plugins[i]->get_script_instance()) { //script based - PackedStringArray features_psa; - for (const String &feature : features) { - features_psa.push_back(feature); - } export_plugins.write[i]->_export_file_script(path, type, features_psa); } else { export_plugins.write[i]->_export_file(path, type, features); @@ -748,8 +1154,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } //just store it as it comes if (do_export) { - Vector<uint8_t> array = FileAccess::get_file_as_array(path); - err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key); + // Customization only happens if plugins did not take care of it before + bool force_binary = convert_text_to_binary && (path.get_extension().to_lower() == "tres" || path.get_extension().to_lower() == "tscn"); + String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, force_binary); + + if (export_path != path) { + // Add a remap entry + path_remaps.push_back(path); + path_remaps.push_back(export_path); + } + + Vector<uint8_t> array = FileAccess::get_file_as_array(export_path); + err = p_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; } @@ -759,6 +1175,31 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & idx++; } + if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) { + // End scene customization + + String fcache = export_base_path.path_join("file_cache"); + Ref<FileAccess> f = FileAccess::open(fcache, FileAccess::WRITE); + + if (f.is_valid()) { + for (const KeyValue<String, FileExportCache> &E : export_cache) { + if (E.value.used) { // May be old, unused + String l = E.key + "::" + E.value.source_md5 + "::" + itos(E.value.source_modified_time) + "::" + E.value.saved_path; + f->store_line(l); + } + } + } else { + ERR_PRINT("Error opening export file cache: " + fcache); + } + + for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) { + customize_resources_plugins[i]->_end_customize_resources(); + } + + for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) { + customize_scenes_plugins[i]->_end_customize_scenes(); + } + } //save config! Vector<String> custom_list; @@ -848,7 +1289,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } } else { // Use default text server data. - String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_icu_data"); + String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_icu_data"); TS->save_support_data(icu_data_file); Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file); err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key); @@ -861,7 +1302,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } String config_file = "project.binary"; - String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); + String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); DirAccess::remove_file_or_error(engine_cfb); @@ -885,7 +1326,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir()); - String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp"); + String tmppath = EditorPaths::get_singleton()->get_cache_dir().path_join("packtmp"); Ref<FileAccess> ftmp = FileAccess::open(tmppath, FileAccess::WRITE); if (ftmp.is_null()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Cannot create file \"%s\"."), tmppath)); diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index bbdb47e041..93bc54284f 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -40,6 +40,8 @@ struct EditorProgress; #include "scene/gui/rich_text_label.h" #include "scene/main/node.h" +class EditorExportPlugin; + class EditorExportPlatform : public RefCounted { GDCLASS(EditorExportPlatform, RefCounted); @@ -99,6 +101,20 @@ private: static Error _add_shared_object(void *p_userdata, const SharedObject &p_so); + struct FileExportCache { + uint64_t source_modified_time = 0; + String source_md5; + String saved_path; + bool used = false; + }; + + bool _export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins); + bool _export_customize_array(Array &array, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins); + bool _export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins); + bool _export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins); + + String _export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save); + protected: struct ExportNotifier { ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags); diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp index 9fca4c908a..8538414523 100644 --- a/editor/export/editor_export_platform_pc.cpp +++ b/editor/export/editor_export_platform_pc.cpp @@ -185,9 +185,9 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset> String src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path); String target_path; if (so_files[i].target.is_empty()) { - target_path = p_path.get_base_dir().plus_file(src_path.get_file()); + target_path = p_path.get_base_dir().path_join(src_path.get_file()); } else { - target_path = p_path.get_base_dir().plus_file(so_files[i].target).plus_file(src_path.get_file()); + target_path = p_path.get_base_dir().path_join(so_files[i].target).path_join(src_path.get_file()); } if (da->dir_exists(src_path)) { diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index cf3a9b0810..971ea579cc 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/editor/export/editor_export_plugin.cpp @@ -138,6 +138,64 @@ void EditorExportPlugin::_export_end_script() { GDVIRTUAL_CALL(_export_end); } +// Customization + +bool EditorExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const { + bool ret = false; + if (GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret)) { + return ret; + } + return false; +} + +Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) { + Ref<Resource> ret; + if (GDVIRTUAL_REQUIRED_CALL(_customize_resource, p_resource, p_path, ret)) { + return ret; + } + return Ref<Resource>(); +} + +bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const { + bool ret = false; + if (GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret)) { + return ret; + } + return false; +} + +Node *EditorExportPlugin::_customize_scene(Node *p_root, const String &p_path) { + Node *ret = nullptr; + if (GDVIRTUAL_REQUIRED_CALL(_customize_scene, p_root, p_path, ret)) { + return ret; + } + return nullptr; +} + +uint64_t EditorExportPlugin::_get_customization_configuration_hash() const { + uint64_t ret = 0; + if (GDVIRTUAL_REQUIRED_CALL(_get_customization_configuration_hash, ret)) { + return ret; + } + return 0; +} + +void EditorExportPlugin::_end_customize_scenes() { + GDVIRTUAL_CALL(_end_customize_scenes); +} + +void EditorExportPlugin::_end_customize_resources() { + GDVIRTUAL_CALL(_end_customize_resources); +} + +String EditorExportPlugin::_get_name() const { + String ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_name, ret)) { + return ret; + } + return ""; +} + void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) { } @@ -164,38 +222,20 @@ void EditorExportPlugin::_bind_methods() { GDVIRTUAL_BIND(_export_file, "path", "type", "features"); GDVIRTUAL_BIND(_export_begin, "features", "is_debug", "path", "flags"); GDVIRTUAL_BIND(_export_end); -} -EditorExportPlugin::EditorExportPlugin() { -} + GDVIRTUAL_BIND(_begin_customize_resources, "platform", "features"); + GDVIRTUAL_BIND(_customize_resource, "resource", "path"); -/////////////////////// + GDVIRTUAL_BIND(_begin_customize_scenes, "platform", "features"); + GDVIRTUAL_BIND(_customize_scene, "scene", "path"); -void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) { - String extension = p_path.get_extension().to_lower(); - if (extension != "tres" && extension != "tscn") { - return; - } + GDVIRTUAL_BIND(_get_customization_configuration_hash); - bool convert = GLOBAL_GET("editor/export/convert_text_resources_to_binary"); - if (!convert) { - return; - } - String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res"); - Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path); - if (err != OK) { - DirAccess::remove_file_or_error(tmp_path); - ERR_FAIL(); - } - Vector<uint8_t> data = FileAccess::get_file_as_array(tmp_path); - if (data.size() == 0) { - DirAccess::remove_file_or_error(tmp_path); - ERR_FAIL(); - } - DirAccess::remove_file_or_error(tmp_path); - add_file(p_path + ".converted.res", data, true); + GDVIRTUAL_BIND(_end_customize_scenes); + GDVIRTUAL_BIND(_end_customize_resources); + + GDVIRTUAL_BIND(_get_name); } -EditorExportTextSceneToBinaryPlugin::EditorExportTextSceneToBinaryPlugin() { - GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false); +EditorExportPlugin::EditorExportPlugin() { } diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h index 04ebc1dfed..3f37ed40be 100644 --- a/editor/export/editor_export_plugin.h +++ b/editor/export/editor_export_plugin.h @@ -34,6 +34,7 @@ #include "core/extension/native_extension.h" #include "editor_export_preset.h" #include "editor_export_shared_object.h" +#include "scene/main/node.h" class EditorExportPlugin : public RefCounted { GDCLASS(EditorExportPlugin, RefCounted); @@ -77,6 +78,7 @@ class EditorExportPlugin : public RefCounted { macos_plugin_files.clear(); } + // Export void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features); void _export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags); void _export_end_script(); @@ -108,6 +110,31 @@ protected: GDVIRTUAL4(_export_begin, Vector<String>, bool, String, uint32_t) GDVIRTUAL0(_export_end) + GDVIRTUAL2RC(bool, _begin_customize_resources, const Ref<EditorExportPlatform> &, const Vector<String> &) + GDVIRTUAL2R(Ref<Resource>, _customize_resource, const Ref<Resource> &, String) + + GDVIRTUAL2RC(bool, _begin_customize_scenes, const Ref<EditorExportPlatform> &, const Vector<String> &) + GDVIRTUAL2R(Node *, _customize_scene, Node *, String) + GDVIRTUAL0RC(uint64_t, _get_customization_configuration_hash) + + GDVIRTUAL0(_end_customize_scenes) + GDVIRTUAL0(_end_customize_resources) + + GDVIRTUAL0RC(String, _get_name) + + bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization + Ref<Resource> _customize_resource(const Ref<Resource> &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made. + + bool _begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization + Node *_customize_scene(Node *p_root, const String &p_path); // Return true if a change was made + + uint64_t _get_customization_configuration_hash() const; // Hash used for caching customized resources and scenes. + + void _end_customize_scenes(); + void _end_customize_resources(); + + virtual String _get_name() const; + public: Vector<String> get_ios_frameworks() const; Vector<String> get_ios_embedded_frameworks() const; @@ -121,12 +148,4 @@ public: EditorExportPlugin(); }; -class EditorExportTextSceneToBinaryPlugin : public EditorExportPlugin { - GDCLASS(EditorExportTextSceneToBinaryPlugin, EditorExportPlugin); - -public: - virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override; - EditorExportTextSceneToBinaryPlugin(); -}; - #endif // EDITOR_EXPORT_PLUGIN_H diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp index a7d9d7f068..0ecbc9a8a3 100644 --- a/editor/export/export_template_manager.cpp +++ b/editor/export/export_template_manager.cpp @@ -91,7 +91,7 @@ void ExportTemplateManager::_update_template_status() { install_options_vb->show(); if (templates.has(current_version)) { - current_installed_path->set_text(templates_dir.plus_file(current_version)); + current_installed_path->set_text(templates_dir.path_join(current_version)); } } @@ -146,7 +146,7 @@ void ExportTemplateManager::_download_template(const String &p_url, bool p_skip_ download_progress_hb->show(); _set_current_progress_status(TTR("Starting the download...")); - download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz")); + download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_templates.tpz")); download_templates->set_use_threads(true); const String proxy_host = EDITOR_GET("network/http_proxy/host"); @@ -440,7 +440,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ } Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(version); + String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(version); Error err = d->make_dir_recursive(template_path); if (err != OK) { EditorNode::get_singleton()->show_warning(TTR("Error creating path for extracting templates:") + "\n" + template_path); @@ -486,12 +486,12 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ if (base_dir != contents_dir && base_dir.begins_with(contents_dir)) { base_dir = base_dir.substr(contents_dir.length(), file_path.length()).trim_prefix("/"); - file = base_dir.plus_file(file); + file = base_dir.path_join(file); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_CONTINUE(da.is_null()); - String output_dir = template_path.plus_file(base_dir); + String output_dir = template_path.path_join(base_dir); if (!DirAccess::exists(output_dir)) { Error mkdir_err = da->make_dir_recursive(output_dir); @@ -503,7 +503,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ p->step(TTR("Importing:") + " " + file, fc); } - String to_write = template_path.plus_file(file); + String to_write = template_path.path_join(file); Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE); if (f.is_null()) { @@ -544,14 +544,14 @@ void ExportTemplateManager::_uninstall_template_confirmed() { Error err = da->change_dir(templates_dir); ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'."); err = da->change_dir(uninstall_version); - ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(uninstall_version) + "'."); + ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.path_join(uninstall_version) + "'."); err = da->erase_contents_recursive(); - ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(uninstall_version) + "'."); + ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.path_join(uninstall_version) + "'."); da->change_dir(".."); err = da->remove(uninstall_version); - ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(uninstall_version) + "'."); + ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.path_join(uninstall_version) + "'."); _update_template_status(); } @@ -618,7 +618,7 @@ void ExportTemplateManager::_installed_table_button_cbk(Object *p_item, int p_co void ExportTemplateManager::_open_template_folder(const String &p_version) { const String &templates_dir = EditorPaths::get_singleton()->get_export_templates_dir(); - OS::get_singleton()->shell_open("file://" + templates_dir.plus_file(p_version)); + OS::get_singleton()->shell_open("file://" + templates_dir.path_join(p_version)); } void ExportTemplateManager::popup_manager() { @@ -641,13 +641,13 @@ void ExportTemplateManager::_hide_dialog() { } bool ExportTemplateManager::can_install_android_template() { - const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG); - return FileAccess::exists(templates_dir.plus_file("android_source.zip")); + const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG); + return FileAccess::exists(templates_dir.path_join("android_source.zip")); } Error ExportTemplateManager::install_android_template() { - const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG); - const String &source_zip = templates_path.plus_file("android_source.zip"); + const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG); + const String &source_zip = templates_path.path_join("android_source.zip"); ERR_FAIL_COND_V(!FileAccess::exists(source_zip), ERR_CANT_OPEN); return install_android_template_from_file(source_zip); } @@ -723,11 +723,11 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_ unzCloseCurrentFile(pkg); if (!dirs_tested.has(base_dir)) { - da->make_dir_recursive(String("android/build").plus_file(base_dir)); + da->make_dir_recursive(String("android/build").path_join(base_dir)); dirs_tested.insert(base_dir); } - String to_write = String("res://android/build").plus_file(path); + String to_write = String("res://android/build").path_join(path); Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE); if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); @@ -868,13 +868,13 @@ ExportTemplateManager::ExportTemplateManager() { current_open_button = memnew(Button); current_open_button->set_text(TTR("Open Folder")); - current_open_button->set_tooltip(TTR("Open the folder containing installed templates for the current version.")); + current_open_button->set_tooltip_text(TTR("Open the folder containing installed templates for the current version.")); current_installed_hb->add_child(current_open_button); current_open_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_open_template_folder).bind(VERSION_FULL_CONFIG)); current_uninstall_button = memnew(Button); current_uninstall_button->set_text(TTR("Uninstall")); - current_uninstall_button->set_tooltip(TTR("Uninstall templates for the current version.")); + current_uninstall_button->set_tooltip_text(TTR("Uninstall templates for the current version.")); current_installed_hb->add_child(current_uninstall_button); current_uninstall_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template).bind(VERSION_FULL_CONFIG)); @@ -915,14 +915,14 @@ ExportTemplateManager::ExportTemplateManager() { Button *download_current_button = memnew(Button); download_current_button->set_text(TTR("Download and Install")); - download_current_button->set_tooltip(TTR("Download and install templates for the current version from the best possible mirror.")); + download_current_button->set_tooltip_text(TTR("Download and install templates for the current version from the best possible mirror.")); download_install_hb->add_child(download_current_button); download_current_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_current)); // Update downloads buttons to prevent unsupported downloads. if (!downloads_available) { download_current_button->set_disabled(true); - download_current_button->set_tooltip(TTR("Official export templates aren't available for development builds.")); + download_current_button->set_tooltip_text(TTR("Official export templates aren't available for development builds.")); } HBoxContainer *install_file_hb = memnew(HBoxContainer); @@ -931,7 +931,7 @@ ExportTemplateManager::ExportTemplateManager() { install_file_button = memnew(Button); install_file_button->set_text(TTR("Install from File")); - install_file_button->set_tooltip(TTR("Install templates from a local file.")); + install_file_button->set_tooltip_text(TTR("Install templates from a local file.")); install_file_hb->add_child(install_file_button); install_file_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_install_file)); @@ -956,7 +956,7 @@ ExportTemplateManager::ExportTemplateManager() { Button *download_cancel_button = memnew(Button); download_cancel_button->set_text(TTR("Cancel")); - download_cancel_button->set_tooltip(TTR("Cancel the download of the templates.")); + download_cancel_button->set_tooltip_text(TTR("Cancel the download of the templates.")); download_progress_hb->add_child(download_cancel_button); download_cancel_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_cancel_template_download)); diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 76493d330f..00a0e08d3a 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -185,9 +185,9 @@ void ProjectExportDialog::_update_export_all() { export_all_button->set_disabled(!can_export); if (can_export) { - export_all_button->set_tooltip(TTR("Export the project for all the presets defined.")); + export_all_button->set_tooltip_text(TTR("Export the project for all the presets defined.")); } else { - export_all_button->set_tooltip(TTR("All presets must have an export path defined for Export All to work.")); + export_all_button->set_tooltip_text(TTR("All presets must have an export path defined for Export All to work.")); } } @@ -1020,12 +1020,12 @@ ProjectExportDialog::ProjectExportDialog() { mc->add_child(presets); presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset)); duplicate_preset = memnew(Button); - duplicate_preset->set_tooltip(TTR("Duplicate")); + duplicate_preset->set_tooltip_text(TTR("Duplicate")); duplicate_preset->set_flat(true); preset_hb->add_child(duplicate_preset); duplicate_preset->connect("pressed", callable_mp(this, &ProjectExportDialog::_duplicate_preset)); delete_preset = memnew(Button); - delete_preset->set_tooltip(TTR("Delete")); + delete_preset->set_tooltip_text(TTR("Delete")); delete_preset->set_flat(true); preset_hb->add_child(delete_preset); delete_preset->connect("pressed", callable_mp(this, &ProjectExportDialog::_delete_preset)); @@ -1041,7 +1041,7 @@ ProjectExportDialog::ProjectExportDialog() { name->connect("text_changed", callable_mp(this, &ProjectExportDialog::_name_changed)); runnable = memnew(CheckButton); runnable->set_text(TTR("Runnable")); - runnable->set_tooltip(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable.")); + runnable->set_tooltip_text(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable.")); runnable->connect("pressed", callable_mp(this, &ProjectExportDialog::_runnable_pressed)); settings_vb->add_child(runnable); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index b823db68f0..19788e70da 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -146,7 +146,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory file_item->set_text(0, fi.name); file_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE); file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type)); - String file_metadata = lpath.plus_file(fi.name); + String file_metadata = lpath.path_join(fi.name); file_item->set_metadata(0, file_metadata); if (!p_select_in_favorites && path == file_metadata) { file_item->select(0); @@ -276,7 +276,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo ti->set_text(0, text); ti->set_icon(0, icon); ti->set_icon_modulate(0, color); - ti->set_tooltip(0, fave); + ti->set_tooltip_text(0, fave); ti->set_selectable(0, true); ti->set_metadata(0, fave); if (p_select_in_favorites && fave == path) { @@ -614,11 +614,11 @@ void FileSystemDock::_set_file_display(bool p_active) { if (p_active) { file_list_display_mode = FILE_LIST_DISPLAY_LIST; button_file_list_display_mode->set_icon(get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons"))); - button_file_list_display_mode->set_tooltip(TTR("View items as a grid of thumbnails.")); + button_file_list_display_mode->set_tooltip_text(TTR("View items as a grid of thumbnails.")); } else { file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS; button_file_list_display_mode->set_icon(get_theme_icon(SNAME("FileList"), SNAME("EditorIcons"))); - button_file_list_display_mode->set_tooltip(TTR("View items as a list.")); + button_file_list_display_mode->set_tooltip_text(TTR("View items as a list.")); } _update_file_list(true); @@ -867,7 +867,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { String dname = efd->get_subdir(i)->get_name(); files->add_item(dname, folder_icon, true); - files->set_item_metadata(-1, directory.plus_file(dname) + "/"); + files->set_item_metadata(-1, directory.path_join(dname) + "/"); files->set_item_icon_modulate(-1, folder_color); if (cselection.has(dname)) { @@ -880,7 +880,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { for (int i = 0; i < efd->get_file_count(); i++) { FileInfo fi; fi.name = efd->get_file(i); - fi.path = directory.plus_file(fi.name); + fi.path = directory.path_join(fi.name); fi.type = efd->get_file_type(i); fi.import_broken = !efd->get_file_import_is_valid(i); fi.modified_time = efd->get_file_modified_time(i); @@ -1545,7 +1545,7 @@ void FileSystemDock::_rename_operation_confirm() { } String old_path = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1) : to_rename.path; - String new_path = old_path.get_base_dir().plus_file(new_name); + String new_path = old_path.get_base_dir().path_join(new_name); if (old_path == new_path) { return; } @@ -1605,7 +1605,7 @@ void FileSystemDock::_duplicate_operation_confirm() { base_dir = base_dir.get_base_dir(); } - String new_path = base_dir.plus_file(new_name); + String new_path = base_dir.path_join(new_name); // Present a more user friendly warning for name conflict Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); @@ -1630,7 +1630,7 @@ Vector<String> FileSystemDock::_check_existing() { String &p_to_path = to_move_path; for (int i = 0; i < to_move.size(); i++) { String ol_pth = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path; - String p_new_path = p_to_path.plus_file(ol_pth.get_file()); + String p_new_path = p_to_path.path_join(ol_pth.get_file()); FileOrFolder p_item = to_move[i]; String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/"); @@ -1662,7 +1662,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove // Check groups. for (int i = 0; i < to_move.size(); i++) { if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) { - EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.plus_file(to_move[i].path.get_file())); + EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.path_join(to_move[i].path.get_file())); } } @@ -1671,7 +1671,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove bool is_moved = false; for (int i = 0; i < to_move.size(); i++) { String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path; - String new_path = p_to_path.plus_file(old_path.get_file()); + String new_path = p_to_path.path_join(old_path.get_file()); if (old_path != new_path) { _try_move_item(to_move[i], new_path, file_renames, folder_renames); is_moved = true; @@ -2005,7 +2005,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } - make_script_dialog->config("Node", fpath.plus_file("new_script.gd"), false, false); + make_script_dialog->config("Node", fpath.path_join("new_script.gd"), false, false); make_script_dialog->popup_centered(); } break; @@ -2047,15 +2047,15 @@ void FileSystemDock::_resource_created() { String type_name = new_resource_dialog->get_selected_type(); if (type_name == "Shader") { - make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 0); + make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 0); make_shader_dialog->popup_centered(); return; } else if (type_name == "VisualShader") { - make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 1); + make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 1); make_shader_dialog->popup_centered(); return; } else if (type_name == "ShaderInclude") { - make_shader_dialog->config(fpath.plus_file("new_shader_include"), false, false, 2); + make_shader_dialog->config(fpath.path_join("new_shader_include"), false, false, 2); make_shader_dialog->popup_centered(); return; } @@ -2370,11 +2370,11 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, String new_path_base; if (to_move[i].is_file) { - new_path = to_dir.plus_file(to_move[i].path.get_file()); + new_path = to_dir.path_join(to_move[i].path.get_file()); new_path_base = new_path.get_basename() + " (%d)." + new_path.get_extension(); } else { PackedStringArray path_split = to_move[i].path.split("/"); - new_path = to_dir.plus_file(path_split[path_split.size() - 2]); + new_path = to_dir.path_join(path_split[path_split.size() - 2]); new_path_base = new_path + " (%d)"; } @@ -2977,7 +2977,7 @@ void FileSystemDock::_file_sort_popup(int p_id) { MenuButton *FileSystemDock::_create_file_menu_button() { MenuButton *button = memnew(MenuButton); button->set_flat(true); - button->set_tooltip(TTR("Sort files")); + button->set_tooltip_text(TTR("Sort files")); PopupMenu *p = button->get_popup(); p->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_sort_popup)); @@ -3040,14 +3040,14 @@ FileSystemDock::FileSystemDock() { button_hist_prev->set_flat(true); button_hist_prev->set_disabled(true); button_hist_prev->set_focus_mode(FOCUS_NONE); - button_hist_prev->set_tooltip(TTR("Previous Folder/File")); + button_hist_prev->set_tooltip_text(TTR("Previous Folder/File")); toolbar_hbc->add_child(button_hist_prev); button_hist_next = memnew(Button); button_hist_next->set_flat(true); button_hist_next->set_disabled(true); button_hist_next->set_focus_mode(FOCUS_NONE); - button_hist_next->set_tooltip(TTR("Next Folder/File")); + button_hist_next->set_tooltip_text(TTR("Next Folder/File")); toolbar_hbc->add_child(button_hist_next); current_path = memnew(LineEdit); @@ -3059,7 +3059,7 @@ FileSystemDock::FileSystemDock() { button_reload = memnew(Button); button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan)); button_reload->set_focus_mode(FOCUS_NONE); - button_reload->set_tooltip(TTR("Re-Scan Filesystem")); + button_reload->set_tooltip_text(TTR("Re-Scan Filesystem")); button_reload->hide(); toolbar_hbc->add_child(button_reload); @@ -3067,7 +3067,7 @@ FileSystemDock::FileSystemDock() { button_toggle_display_mode->set_toggle_mode(true); button_toggle_display_mode->connect("toggled", callable_mp(this, &FileSystemDock::_toggle_split_mode)); button_toggle_display_mode->set_focus_mode(FOCUS_NONE); - button_toggle_display_mode->set_tooltip(TTR("Toggle Split Mode")); + button_toggle_display_mode->set_tooltip_text(TTR("Toggle Split Mode")); button_toggle_display_mode->set_flat(true); toolbar_hbc->add_child(button_toggle_display_mode); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 81b71b5609..16c5003fdc 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -168,7 +168,7 @@ void FindInFiles::_iterate() { String folder_name = folders_to_scan[folders_to_scan.size() - 1]; pop_back(folders_to_scan); - _current_dir = _current_dir.plus_file(folder_name); + _current_dir = _current_dir.path_join(folder_name); PackedStringArray sub_dirs; _scan_dir("res://" + _current_dir, sub_dirs); @@ -246,7 +246,7 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) { } else { String file_ext = file.get_extension(); if (_extension_filter.has(file_ext)) { - _files_to_scan.push_back(path.plus_file(file)); + _files_to_scan.push_back(path.path_join(file)); } } } @@ -373,7 +373,7 @@ FindInFilesDialog::FindInFilesDialog() { Label *filter_label = memnew(Label); filter_label->set_text(TTR("Filters:")); - filter_label->set_tooltip(TTR("Include the files with the following extensions. Add or remove them in ProjectSettings.")); + filter_label->set_tooltip_text(TTR("Include the files with the following extensions. Add or remove them in ProjectSettings.")); gc->add_child(filter_label); _filters_container = memnew(HBoxContainer); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 15add50fd4..dac86acae4 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -89,7 +89,7 @@ void GroupDialog::_load_nodes(Node *p_current) { if (keep) { node->set_text(0, item_name); node->set_metadata(0, path); - node->set_tooltip(0, path); + node->set_tooltip_text(0, path); Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(p_current, "Node"); node->set_icon(0, icon); diff --git a/editor/icons/CameraEffects.svg b/editor/icons/CameraAttributes.svg index 1ee7e15c87..1ee7e15c87 100644 --- a/editor/icons/CameraEffects.svg +++ b/editor/icons/CameraAttributes.svg diff --git a/editor/icons/InterpCubicAngle.svg b/editor/icons/InterpCubicAngle.svg new file mode 100644 index 0000000000..e302d556dc --- /dev/null +++ b/editor/icons/InterpCubicAngle.svg @@ -0,0 +1 @@ +<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#5fff95" stroke-linecap="round"><path d="m2 6c5 0 3-4 6-4s1 4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5" stroke-linejoin="round"/></g></svg> diff --git a/editor/icons/InterpLinearAngle.svg b/editor/icons/InterpLinearAngle.svg new file mode 100644 index 0000000000..af4e87a6cb --- /dev/null +++ b/editor/icons/InterpLinearAngle.svg @@ -0,0 +1 @@ +<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fd995f" stroke-linecap="round" stroke-linejoin="round"><path d="m2 6 6-4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5"/></g></svg> diff --git a/editor/icons/VcsBranches.svg b/editor/icons/VcsBranches.svg new file mode 100644 index 0000000000..e79019590f --- /dev/null +++ b/editor/icons/VcsBranches.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-rule="nonzero"><path d="m3.755 1.396c-1.599 0-2.914 1.315-2.914 2.913 0 1.599 1.315 2.914 2.914 2.914 1.598 0 2.913-1.315 2.913-2.914 0-1.598-1.315-2.913-2.913-2.913zm0 1.462c.796 0 1.451.655 1.451 1.451 0 .797-.655 1.452-1.451 1.452-.797 0-1.452-.655-1.452-1.452 0-.796.655-1.451 1.452-1.451z"/><path d="m12.073 8.956c-1.599 0-2.914 1.316-2.914 2.914s1.315 2.914 2.914 2.914c1.598 0 2.914-1.316 2.914-2.914s-1.316-2.914-2.914-2.914zm0 1.463c.796 0 1.451.655 1.451 1.451s-.655 1.451-1.451 1.451-1.451-.655-1.451-1.451.655-1.451 1.451-1.451z"/><path d="m12.073 1.396c-1.599 0-2.914 1.315-2.914 2.913 0 1.599 1.315 2.914 2.914 2.914 1.598 0 2.914-1.315 2.914-2.914 0-1.598-1.316-2.913-2.914-2.913zm0 1.462c.796 0 1.451.655 1.451 1.451 0 .797-.655 1.452-1.451 1.452s-1.451-.655-1.451-1.452c0-.796.655-1.451 1.451-1.451z"/></g><path d="m9.159 11.87h-2.491l-2.913-2.914v-1.733" fill="none" stroke="#e0e0e0" stroke-width="1.5"/><path d="m9.159 4.309h-2.491" fill="none" stroke="#e0e0e0" stroke-width="1.5"/></svg> diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp index f3709efab6..e3da82a5cb 100644 --- a/editor/import/audio_stream_import_settings.cpp +++ b/editor/import/audio_stream_import_settings.cpp @@ -57,13 +57,13 @@ void AudioStreamImportSettings::_notification(int p_what) { zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons"))); zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons"))); - _indicator->update(); - _preview->update(); + _indicator->queue_redraw(); + _preview->queue_redraw(); } break; case NOTIFICATION_PROCESS: { _current = _player->get_playback_position(); - _indicator->update(); + _indicator->queue_redraw(); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -167,7 +167,7 @@ void AudioStreamImportSettings::_draw_preview() { void AudioStreamImportSettings::_preview_changed(ObjectID p_which) { if (stream.is_valid() && stream->get_instance_id() == p_which) { - _preview->update(); + _preview->queue_redraw(); } } @@ -179,8 +179,8 @@ void AudioStreamImportSettings::_preview_zoom_in() { zoom_bar->set_page(page_size * 0.5); zoom_bar->set_value(zoom_bar->get_value() + page_size * 0.25); - _preview->update(); - _indicator->update(); + _preview->queue_redraw(); + _indicator->queue_redraw(); } void AudioStreamImportSettings::_preview_zoom_out() { @@ -191,8 +191,8 @@ void AudioStreamImportSettings::_preview_zoom_out() { zoom_bar->set_page(MIN(zoom_bar->get_max(), page_size * 2.0)); zoom_bar->set_value(zoom_bar->get_value() - page_size * 0.5); - _preview->update(); - _indicator->update(); + _preview->queue_redraw(); + _indicator->queue_redraw(); } void AudioStreamImportSettings::_preview_zoom_reset() { @@ -202,22 +202,22 @@ void AudioStreamImportSettings::_preview_zoom_reset() { zoom_bar->set_max(stream->get_length()); zoom_bar->set_page(zoom_bar->get_max()); zoom_bar->set_value(0); - _preview->update(); - _indicator->update(); + _preview->queue_redraw(); + _indicator->queue_redraw(); } void AudioStreamImportSettings::_preview_zoom_offset_changed(double) { - _preview->update(); - _indicator->update(); + _preview->queue_redraw(); + _indicator->queue_redraw(); } void AudioStreamImportSettings::_audio_changed() { if (!is_visible()) { return; } - _preview->update(); - _indicator->update(); - color_rect->update(); + _preview->queue_redraw(); + _indicator->queue_redraw(); + color_rect->queue_redraw(); } void AudioStreamImportSettings::_play() { @@ -238,7 +238,7 @@ void AudioStreamImportSettings::_stop() { _player->stop(); _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); _current = 0; - _indicator->update(); + _indicator->queue_redraw(); set_process(false); } @@ -246,7 +246,7 @@ void AudioStreamImportSettings::_on_finished() { _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); if (!_pausing) { _current = 0; - _indicator->update(); + _indicator->queue_redraw(); } else { _pausing = false; } @@ -310,7 +310,7 @@ void AudioStreamImportSettings::_draw_indicator() { void AudioStreamImportSettings::_on_indicator_mouse_exited() { _hovering_beat = -1; - _indicator->update(); + _indicator->queue_redraw(); } void AudioStreamImportSettings::_on_input_indicator(Ref<InputEvent> p_event) { @@ -353,11 +353,11 @@ void AudioStreamImportSettings::_on_input_indicator(Ref<InputEvent> p_event) { int new_hovering_beat = _get_beat_at_pos(mm->get_position().x); if (new_hovering_beat != _hovering_beat) { _hovering_beat = new_hovering_beat; - _indicator->update(); + _indicator->queue_redraw(); } } else if (_hovering_beat != -1) { _hovering_beat = -1; - _indicator->update(); + _indicator->queue_redraw(); } } } @@ -391,7 +391,7 @@ void AudioStreamImportSettings::_seek_to(real_t p_x) { _current = zoom_bar->get_value() + p_x / _preview->get_rect().size.x * zoom_bar->get_page(); _current = CLAMP(_current, 0, stream->get_length()); _player->seek(_current); - _indicator->update(); + _indicator->queue_redraw(); } void AudioStreamImportSettings::edit(const String &p_path, const String &p_importer, const Ref<AudioStream> &p_stream) { @@ -410,9 +410,9 @@ void AudioStreamImportSettings::edit(const String &p_path, const String &p_impor if (!stream.is_null()) { stream->connect("changed", callable_mp(this, &AudioStreamImportSettings::_audio_changed)); - _preview->update(); - _indicator->update(); - color_rect->update(); + _preview->queue_redraw(); + _indicator->queue_redraw(); + color_rect->queue_redraw(); } else { hide(); } @@ -500,9 +500,9 @@ void AudioStreamImportSettings::_settings_changed() { updating_settings = false; - _preview->update(); - _indicator->update(); - color_rect->update(); + _preview->queue_redraw(); + _indicator->queue_redraw(); + color_rect->queue_redraw(); } void AudioStreamImportSettings::_reimport() { @@ -526,7 +526,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() { loop_hb->add_theme_constant_override("separation", 4 * EDSCALE); loop = memnew(CheckBox); loop->set_text(TTR("Enable")); - loop->set_tooltip(TTR("Enable looping.")); + loop->set_tooltip_text(TTR("Enable looping.")); loop->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); loop_hb->add_child(loop); loop_hb->add_spacer(); @@ -535,7 +535,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() { loop_offset->set_max(10000); loop_offset->set_step(0.001); loop_offset->set_suffix("sec"); - loop_offset->set_tooltip(TTR("Loop offset (from beginning). Note that if BPM is set, this setting will be ignored.")); + loop_offset->set_tooltip_text(TTR("Loop offset (from beginning). Note that if BPM is set, this setting will be ignored.")); loop_offset->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); loop_hb->add_child(loop_offset); main_vbox->add_margin_child(TTR("Loop:"), loop_hb); @@ -549,14 +549,14 @@ AudioStreamImportSettings::AudioStreamImportSettings() { bpm_edit = memnew(SpinBox); bpm_edit->set_max(400); bpm_edit->set_step(0.01); - bpm_edit->set_tooltip(TTR("Configure the Beats Per Measure (tempo) used for the interactive streams.\nThis is required in order to configure beat information.")); + bpm_edit->set_tooltip_text(TTR("Configure the Beats Per Measure (tempo) used for the interactive streams.\nThis is required in order to configure beat information.")); bpm_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); interactive_hb->add_child(bpm_edit); interactive_hb->add_spacer(); bar_beats_label = memnew(Label(TTR("Beats/Bar:"))); interactive_hb->add_child(bar_beats_label); bar_beats_edit = memnew(SpinBox); - bar_beats_edit->set_tooltip(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams.")); + bar_beats_edit->set_tooltip_text(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams.")); bar_beats_edit->set_min(2); bar_beats_edit->set_max(32); bar_beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); @@ -567,7 +567,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() { beats_enabled->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); interactive_hb->add_child(beats_enabled); beats_edit = memnew(SpinBox); - beats_edit->set_tooltip(TTR("Configure the amount of Beats used for music-aware looping. If zero, it will be autodetected from the length.\nIt is recommended to set this value (either manually or by clicking on a beat number in the preview) to ensure looping works properly.")); + beats_edit->set_tooltip_text(TTR("Configure the amount of Beats used for music-aware looping. If zero, it will be autodetected from the length.\nIt is recommended to set this value (either manually or by clicking on a beat number in the preview) to ensure looping works properly.")); beats_edit->set_max(99999); beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); interactive_hb->add_child(beats_edit); diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp index 5b9ed2c1d2..5d8e453395 100644 --- a/editor/import/collada.cpp +++ b/editor/import/collada.cpp @@ -289,7 +289,7 @@ void Collada::_parse_image(XMLParser &parser) { String path = parser.get_attribute_value("source").strip_edges(); if (!path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path - image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.uri_decode())); + image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode())); } } else { while (parser.read() == OK) { @@ -302,7 +302,7 @@ void Collada::_parse_image(XMLParser &parser) { if (!path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path - path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path)); } else if (path.find("file:///") == 0) { path = path.replace_first("file:///", ""); diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index b9be8fb792..405d8d2169 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -474,7 +474,7 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper font_preview_label->add_theme_font_override("font", font_preview); font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE); - font_preview_label->update(); + font_preview_label->queue_redraw(); } /*************************************************************************/ @@ -1096,7 +1096,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { } font_preview_label->add_theme_font_override("font", font_preview); font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE); - font_preview_label->update(); + font_preview_label->queue_redraw(); _variations_validate(); @@ -1239,7 +1239,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { add_var = memnew(Button); page2_hb_vars->add_child(add_var); - add_var->set_tooltip(TTR("Add configuration")); + add_var->set_tooltip_text(TTR("Add configuration")); add_var->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); add_var->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_variation_add)); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index d1c4e1f8dd..fe70fd58b5 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -129,7 +129,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S if (p.is_absolute_path()) { path = p; } else { - path = base_path.plus_file(p); + path = base_path.path_join(p); } Ref<Texture2D> texture = ResourceLoader::load(path); @@ -149,7 +149,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S if (p.is_absolute_path()) { path = p; } else { - path = base_path.plus_file(p); + path = base_path.path_join(p); } Ref<Texture2D> texture = ResourceLoader::load(path); @@ -169,7 +169,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S if (p.is_absolute_path()) { path = p; } else { - path = base_path.plus_file(p); + path = base_path.path_join(p); } Ref<Texture2D> texture = ResourceLoader::load(path); @@ -184,7 +184,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT); String p = l.replace("map_bump", "").replace("\\", "/").strip_edges(); - String path = base_path.plus_file(p); + String path = base_path.path_join(p); Ref<Texture2D> texture = ResourceLoader::load(path); @@ -405,7 +405,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ HashMap<String, Ref<StandardMaterial3D>> lib; String lib_path = current_material_library; if (lib_path.is_relative_path()) { - lib_path = p_path.get_base_dir().plus_file(current_material_library); + lib_path = p_path.get_base_dir().path_join(current_material_library); } Error err = _parse_material_library(lib_path, lib, r_missing_deps); if (err == OK) { diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp index d3079141e0..55afd71c76 100644 --- a/editor/import/resource_importer_shader_file.cpp +++ b/editor/import/resource_importer_shader_file.cpp @@ -79,7 +79,7 @@ static String _include_function(const String &p_path, void *userpointer) { String include = p_path; if (include.is_relative_path()) { - include = base_path->plus_file(include); + include = base_path->path_join(include); } Ref<FileAccess> file_inc = FileAccess::open(include, FileAccess::READ, &err); diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 6c12464b5a..730aa3bd61 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -30,6 +30,7 @@ #include "scene_import_settings.h" +#include "core/config/project_settings.h" #include "editor/editor_file_dialog.h" #include "editor/editor_file_system.h" #include "editor/editor_inspector.h" @@ -176,7 +177,7 @@ void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_ma item->set_meta("type", "Material"); item->set_meta("import_id", import_id); - item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id)); + item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id)); item->set_selectable(0, true); if (p_tree == scene_tree) { @@ -232,7 +233,7 @@ void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, Tree item->set_meta("type", "Mesh"); item->set_meta("import_id", import_id); - item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id)); + item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id)); item->set_selectable(0, true); @@ -331,7 +332,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) { item->set_meta("type", "Node"); item->set_meta("class", type); item->set_meta("import_id", import_id); - item->set_tooltip(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id)); + item->set_tooltip_text(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id)); item->set_selectable(0, true); @@ -979,7 +980,7 @@ void SceneImportSettings::_save_path_changed(const String &p_path) { if (FileAccess::exists(p_path)) { save_path_item->set_text(2, "Warning: File exists"); - save_path_item->set_tooltip(2, TTR("Existing file with the same name will be replaced.")); + save_path_item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced.")); save_path_item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { @@ -1024,12 +1025,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { if (md.has_import_id) { if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) { item->set_text(2, "Already External"); - item->set_tooltip(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again.")); + item->set_tooltip_text(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again.")); } else { item->set_metadata(0, E.key); item->set_editable(0, true); item->set_checked(0, true); - String path = p_path.plus_file(name); + String path = p_path.path_join(name); if (external_extension_type->get_selected() == 0) { path += ".tres"; } else { @@ -1039,7 +1040,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { item->set_text(1, path); if (FileAccess::exists(path)) { item->set_text(2, "Warning: File exists"); - item->set_tooltip(2, TTR("Existing file with the same name will be replaced.")); + item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced.")); item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { @@ -1052,7 +1053,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { } else { item->set_text(2, "No import ID"); - item->set_tooltip(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); + item->set_tooltip_text(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"))); } @@ -1077,12 +1078,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { if (md.has_import_id) { if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) { item->set_text(2, "Already Saving"); - item->set_tooltip(2, TTR("This mesh already saves to an external resource, no action will be taken.")); + item->set_tooltip_text(2, TTR("This mesh already saves to an external resource, no action will be taken.")); } else { item->set_metadata(0, E.key); item->set_editable(0, true); item->set_checked(0, true); - String path = p_path.plus_file(name); + String path = p_path.path_join(name); if (external_extension_type->get_selected() == 0) { path += ".tres"; } else { @@ -1092,7 +1093,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { item->set_text(1, path); if (FileAccess::exists(path)) { item->set_text(2, "Warning: File exists"); - item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import.")); + item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import.")); item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { @@ -1105,7 +1106,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { } else { item->set_text(2, "No import ID"); - item->set_tooltip(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); + item->set_tooltip_text(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"))); } @@ -1129,12 +1130,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) { item->set_text(2, "Already Saving"); - item->set_tooltip(2, TTR("This animation already saves to an external resource, no action will be taken.")); + item->set_tooltip_text(2, TTR("This animation already saves to an external resource, no action will be taken.")); } else { item->set_metadata(0, E.key); item->set_editable(0, true); item->set_checked(0, true); - String path = p_path.plus_file(name); + String path = p_path.path_join(name); if (external_extension_type->get_selected() == 0) { path += ".tres"; } else { @@ -1144,7 +1145,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { item->set_text(1, path); if (FileAccess::exists(path)) { item->set_text(2, "Warning: File exists"); - item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import.")); + item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import.")); item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { @@ -1288,6 +1289,11 @@ SceneImportSettings::SceneImportSettings() { base_viewport->add_child(camera); camera->make_current(); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + camera_attributes.instantiate(); + camera->set_attributes(camera_attributes); + } + light = memnew(DirectionalLight3D); light->set_transform(Transform3D().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0))); base_viewport->add_child(light); diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h index b5cf82f64b..104a7a9f7e 100644 --- a/editor/import/scene_import_settings.h +++ b/editor/import/scene_import_settings.h @@ -74,6 +74,7 @@ class SceneImportSettings : public ConfirmationDialog { SubViewport *base_viewport = nullptr; Camera3D *camera = nullptr; + Ref<CameraAttributesPractical> camera_attributes; bool first_aabb = false; AABB contents_aabb; diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 087ef48b56..4732268256 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -584,12 +584,12 @@ void ImportDock::_set_dirty(bool p_dirty) { // Add a dirty marker to notify the user that they should reimport the selected resource to see changes. import->set_text(TTR("Reimport") + " (*)"); import->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor"))); - import->set_tooltip(TTR("You have pending changes that haven't been applied yet. Click Reimport to apply changes made to the import options.\nSelecting another resource in the FileSystem dock without clicking Reimport first will discard changes made in the Import dock.")); + import->set_tooltip_text(TTR("You have pending changes that haven't been applied yet. Click Reimport to apply changes made to the import options.\nSelecting another resource in the FileSystem dock without clicking Reimport first will discard changes made in the Import dock.")); } else { // Remove the dirty marker on the Reimport button. import->set_text(TTR("Reimport")); import->remove_theme_color_override("font_color"); - import->set_tooltip(""); + import->set_tooltip_text(""); } } @@ -628,6 +628,9 @@ ImportDock::ImportDock() { content->add_margin_child(TTR("Import As:"), hb); import_as = memnew(OptionButton); import_as->set_disabled(true); + import_as->set_fit_to_longest_item(false); + import_as->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); + import_as->set_h_size_flags(SIZE_EXPAND_FILL); import_as->connect("item_selected", callable_mp(this, &ImportDock::_importer_selected)); hb->add_child(import_as); import_as->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index b0ff678a3e..7af04e17c1 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -633,20 +633,20 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { resource_new_button = memnew(Button); resource_new_button->set_flat(true); - resource_new_button->set_tooltip(TTR("Create a new resource in memory and edit it.")); + resource_new_button->set_tooltip_text(TTR("Create a new resource in memory and edit it.")); general_options_hb->add_child(resource_new_button); resource_new_button->connect("pressed", callable_mp(this, &InspectorDock::_new_resource)); resource_new_button->set_focus_mode(Control::FOCUS_NONE); resource_load_button = memnew(Button); resource_load_button->set_flat(true); - resource_load_button->set_tooltip(TTR("Load an existing resource from disk and edit it.")); + resource_load_button->set_tooltip_text(TTR("Load an existing resource from disk and edit it.")); general_options_hb->add_child(resource_load_button); resource_load_button->connect("pressed", callable_mp(this, &InspectorDock::_open_resource_selector)); resource_load_button->set_focus_mode(Control::FOCUS_NONE); resource_save_button = memnew(MenuButton); - resource_save_button->set_tooltip(TTR("Save the currently edited resource.")); + resource_save_button->set_tooltip_text(TTR("Save the currently edited resource.")); general_options_hb->add_child(resource_save_button); resource_save_button->get_popup()->add_item(TTR("Save"), RESOURCE_SAVE); resource_save_button->get_popup()->add_item(TTR("Save As..."), RESOURCE_SAVE_AS); @@ -655,7 +655,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { resource_save_button->set_disabled(true); resource_extra_button = memnew(MenuButton); - resource_extra_button->set_tooltip(TTR("Extra resource options.")); + resource_extra_button->set_tooltip_text(TTR("Extra resource options.")); general_options_hb->add_child(resource_extra_button); resource_extra_button->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_resource_extra_popup)); resource_extra_button->get_popup()->add_icon_shortcut(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")), ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource from Clipboard")), RESOURCE_EDIT_CLIPBOARD); @@ -671,19 +671,19 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { backward_button = memnew(Button); backward_button->set_flat(true); general_options_hb->add_child(backward_button); - backward_button->set_tooltip(TTR("Go to the previous edited object in history.")); + backward_button->set_tooltip_text(TTR("Go to the previous edited object in history.")); backward_button->set_disabled(true); backward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_back)); forward_button = memnew(Button); forward_button->set_flat(true); general_options_hb->add_child(forward_button); - forward_button->set_tooltip(TTR("Go to the next edited object in history.")); + forward_button->set_tooltip_text(TTR("Go to the next edited object in history.")); forward_button->set_disabled(true); forward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_forward)); history_menu = memnew(MenuButton); - history_menu->set_tooltip(TTR("History of recently edited objects.")); + history_menu->set_tooltip_text(TTR("History of recently edited objects.")); general_options_hb->add_child(history_menu); history_menu->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_history)); history_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_select_history)); @@ -697,7 +697,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { open_docs_button = memnew(Button); open_docs_button->set_flat(true); open_docs_button->set_disabled(true); - open_docs_button->set_tooltip(TTR("Open documentation for this object.")); + open_docs_button->set_tooltip_text(TTR("Open documentation for this object.")); open_docs_button->set_shortcut(ED_SHORTCUT("property_editor/open_help", TTR("Open Documentation"))); subresource_hb->add_child(open_docs_button); open_docs_button->connect("pressed", callable_mp(this, &InspectorDock::_menu_option).bind(OBJECT_REQUEST_HELP)); @@ -719,7 +719,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { object_menu = memnew(MenuButton); object_menu->set_shortcut_context(this); property_tools_hb->add_child(object_menu); - object_menu->set_tooltip(TTR("Manage object properties.")); + object_menu->set_tooltip_text(TTR("Manage object properties.")); object_menu->get_popup()->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_menu)); object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index 77a1700ebf..683481ecc1 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -193,7 +193,7 @@ void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) { TreeItem *ed = translation_remap_options->get_edited(); ERR_FAIL_COND(!ed); - locale_select->set_locale(ed->get_tooltip(1)); + locale_select->set_locale(ed->get_tooltip_text(1)); locale_select->popup_locale_dialog(); } @@ -202,7 +202,7 @@ void LocalizationEditor::_translation_res_option_selected(const String &p_locale ERR_FAIL_COND(!ed); ed->set_text(1, TranslationServer::get_singleton()->get_locale_name(p_locale)); - ed->set_tooltip(1, p_locale); + ed->set_tooltip_text(1, p_locale); LocalizationEditor::_translation_res_option_changed(); } @@ -226,7 +226,7 @@ void LocalizationEditor::_translation_res_option_changed() { String key = k->get_metadata(0); int idx = ed->get_metadata(0); String path = ed->get_metadata(1); - String locale = ed->get_tooltip(1); + String locale = ed->get_tooltip_text(1); ERR_FAIL_COND(!remaps.has(key)); PackedStringArray r = remaps[key]; @@ -486,7 +486,7 @@ void LocalizationEditor::update_translations() { TreeItem *t = translation_list->create_item(root); t->set_editable(0, false); t->set_text(0, translations[i].replace_first("res://", "")); - t->set_tooltip(0, translations[i]); + t->set_tooltip_text(0, translations[i]); t->set_metadata(0, i); t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); } @@ -520,14 +520,14 @@ void LocalizationEditor::update_translations() { TreeItem *t = translation_remap->create_item(root); t->set_editable(0, false); t->set_text(0, keys[i].replace_first("res://", "")); - t->set_tooltip(0, keys[i]); + t->set_tooltip_text(0, keys[i]); t->set_metadata(0, keys[i]); t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); // Display that it has been removed if this is the case. if (!FileAccess::exists(keys[i])) { t->set_text(0, t->get_text(0) + vformat(" (%s)", TTR("Removed"))); - t->set_tooltip(0, vformat(TTR("%s cannot be found."), t->get_tooltip(0))); + t->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t->get_tooltip_text(0))); } if (keys[i] == remap_selected) { @@ -544,19 +544,19 @@ void LocalizationEditor::update_translations() { TreeItem *t2 = translation_remap_options->create_item(root2); t2->set_editable(0, false); t2->set_text(0, path.replace_first("res://", "")); - t2->set_tooltip(0, path); + t2->set_tooltip_text(0, path); t2->set_metadata(0, j); t2->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); t2->set_cell_mode(1, TreeItem::CELL_MODE_CUSTOM); t2->set_text(1, TranslationServer::get_singleton()->get_locale_name(locale)); t2->set_editable(1, true); t2->set_metadata(1, path); - t2->set_tooltip(1, locale); + t2->set_tooltip_text(1, locale); // Display that it has been removed if this is the case. if (!FileAccess::exists(path)) { t2->set_text(0, t2->get_text(0) + vformat(" (%s)", TTR("Removed"))); - t2->set_tooltip(0, vformat(TTR("%s cannot be found."), t2->get_tooltip(0))); + t2->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t2->get_tooltip_text(0))); } } } @@ -573,7 +573,7 @@ void LocalizationEditor::update_translations() { TreeItem *t = translation_pot_list->create_item(root); t->set_editable(0, false); t->set_text(0, pot_translations[i].replace_first("res://", "")); - t->set_tooltip(0, pot_translations[i]); + t->set_tooltip_text(0, pot_translations[i]); t->set_metadata(0, i); t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); } diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index 6d323572e6..71ff77e9bc 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -62,7 +62,7 @@ void PluginConfigDialog::_on_confirmed() { if (script_name.get_extension().is_empty()) { script_name += "." + ext; } - String script_path = path.plus_file(script_name); + String script_path = path.path_join(script_name); Ref<ConfigFile> cf = memnew(ConfigFile); cf->set_value("plugin", "name", name_edit->get_text()); @@ -71,7 +71,7 @@ void PluginConfigDialog::_on_confirmed() { cf->set_value("plugin", "version", version_edit->get_text()); cf->set_value("plugin", "script", script_name); - cf->save(path.plus_file("plugin.cfg")); + cf->save(path.path_join("plugin.cfg")); if (!_edit_mode) { String class_name = script_name.get_basename(); @@ -111,32 +111,32 @@ void PluginConfigDialog::_on_required_text_changed(const String &) { name_validation->set_texture(valid_icon); subfolder_validation->set_texture(valid_icon); script_validation->set_texture(valid_icon); - name_validation->set_tooltip(""); - subfolder_validation->set_tooltip(""); - script_validation->set_tooltip(""); + name_validation->set_tooltip_text(""); + subfolder_validation->set_tooltip_text(""); + script_validation->set_tooltip_text(""); // Change valid status to invalid depending on conditions. Vector<String> errors; if (name_edit->get_text().is_empty()) { is_valid = false; name_validation->set_texture(invalid_icon); - name_validation->set_tooltip(TTR("Plugin name cannot be blank.")); + name_validation->set_tooltip_text(TTR("Plugin name cannot be blank.")); } if ((!script_edit->get_text().get_extension().is_empty() && script_edit->get_text().get_extension() != ext) || script_edit->get_text().ends_with(".")) { is_valid = false; script_validation->set_texture(invalid_icon); - script_validation->set_tooltip(vformat(TTR("Script extension must match chosen language extension (.%s)."), ext)); + script_validation->set_tooltip_text(vformat(TTR("Script extension must match chosen language extension (.%s)."), ext)); } if (!subfolder_edit->get_text().is_empty() && !subfolder_edit->get_text().is_valid_filename()) { is_valid = false; subfolder_validation->set_texture(invalid_icon); - subfolder_validation->set_tooltip(TTR("Subfolder name is not a valid folder name.")); + subfolder_validation->set_tooltip_text(TTR("Subfolder name is not a valid folder name.")); } else { String path = "res://addons/" + _get_subfolder(); if (!_edit_mode && DirAccess::exists(path)) { // Only show this error if in "create" mode. is_valid = false; subfolder_validation->set_texture(invalid_icon); - subfolder_validation->set_tooltip(TTR("Subfolder cannot be one which already exists.")); + subfolder_validation->set_tooltip_text(TTR("Subfolder cannot be one which already exists.")); } } diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 275859f528..c928b95642 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -235,13 +235,13 @@ void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_r button_delete->set_disabled(p_disable); if (p_disable) { - button_create->set_tooltip(p_reason); - button_edit->set_tooltip(p_reason); - button_delete->set_tooltip(p_reason); + button_create->set_tooltip_text(p_reason); + button_edit->set_tooltip_text(p_reason); + button_delete->set_tooltip_text(p_reason); } else { - button_create->set_tooltip(TTR("Create points.")); - button_edit->set_tooltip(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point")); - button_delete->set_tooltip(TTR("Erase points.")); + button_create->set_tooltip_text(TTR("Create points.")); + button_edit->set_tooltip_text(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point")); + button_delete->set_tooltip_text(TTR("Erase points.")); } } diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 2578099a9f..b79f4c90bf 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -48,7 +48,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) { if (selected_point != -1) { - _erase_selected(); + if (!read_only) { + _erase_selected(); + } accept_event(); } } @@ -56,67 +58,69 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) { - menu->clear(); - animations_menu->clear(); - animations_to_add.clear(); + if (!read_only) { + menu->clear(); + animations_menu->clear(); + animations_to_add.clear(); - List<StringName> classes; - ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); - classes.sort_custom<StringName::AlphCompare>(); + List<StringName> classes; + ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); + classes.sort_custom<StringName::AlphCompare>(); - menu->add_submenu_item(TTR("Add Animation"), "animations"); + menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); - ERR_FAIL_COND(!gp); + AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); + ERR_FAIL_COND(!gp); - if (gp->has_node(gp->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); + if (gp->has_node(gp->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); - if (ap) { - List<StringName> names; - ap->get_animation_list(&names); + if (ap) { + List<StringName> names; + ap->get_animation_list(&names); - for (const StringName &E : names) { - animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E); - animations_to_add.push_back(E); + for (const StringName &E : names) { + animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E); + animations_to_add.push_back(E); + } } } - } - for (const StringName &E : classes) { - String name = String(E).replace_first("AnimationNode", ""); - if (name == "Animation" || name == "StartState" || name == "EndState") { - continue; - } + for (const StringName &E : classes) { + String name = String(E).replace_first("AnimationNode", ""); + if (name == "Animation" || name == "StartState" || name == "EndState") { + continue; + } - int idx = menu->get_item_count(); - menu->add_item(vformat(TTR("Add %s"), name), idx); - menu->set_item_metadata(idx, E); - } + int idx = menu->get_item_count(); + menu->add_item(vformat(TTR("Add %s"), name), idx); + menu->set_item_metadata(idx, E); + } - Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); - if (clipb.is_valid()) { + Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); + if (clipb.is_valid()) { + menu->add_separator(); + menu->add_item(TTR("Paste"), MENU_PASTE); + } menu->add_separator(); - menu->add_item(TTR("Paste"), MENU_PASTE); - } - menu->add_separator(); - menu->add_item(TTR("Load..."), MENU_LOAD_FILE); + menu->add_item(TTR("Load..."), MENU_LOAD_FILE); - menu->set_position(blend_space_draw->get_screen_position() + mb->get_position()); - menu->reset_size(); - menu->popup(); + menu->set_position(blend_space_draw->get_screen_position() + mb->get_position()); + menu->reset_size(); + menu->popup(); - add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x; - add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); - add_point_pos += blend_space->get_min_space(); + add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x; + add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); + add_point_pos += blend_space->get_min_space(); - if (snap->is_pressed()) { - add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap()); + if (snap->is_pressed()) { + add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap()); + } } } if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - blend_space_draw->update(); // why not + blend_space_draw->queue_redraw(); // why not // try to see if a point can be selected selected_point = -1; @@ -138,31 +142,33 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven } if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) { - if (dragging_selected) { - // move - float point = blend_space->get_blend_point_position(selected_point); - point += drag_ofs.x; + if (!read_only) { + if (dragging_selected) { + // move + float point = blend_space->get_blend_point_position(selected_point); + point += drag_ofs.x; + + if (snap->is_pressed()) { + point = Math::snapped(point, blend_space->get_snap()); + } - if (snap->is_pressed()) { - point = Math::snapped(point, blend_space->get_snap()); + updating = true; + undo_redo->create_action(TTR("Move Node Point")); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->add_do_method(this, "_update_edited_point_pos"); + undo_redo->add_undo_method(this, "_update_edited_point_pos"); + undo_redo->commit_action(); + updating = false; + _update_edited_point_pos(); } - updating = true; - undo_redo->create_action(TTR("Move Node Point")); - undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); - undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); - undo_redo->add_do_method(this, "_update_space"); - undo_redo->add_undo_method(this, "_update_space"); - undo_redo->add_do_method(this, "_update_edited_point_pos"); - undo_redo->add_undo_method(this, "_update_edited_point_pos"); - undo_redo->commit_action(); - updating = false; - _update_edited_point_pos(); + dragging_selected_attempt = false; + dragging_selected = false; + blend_space_draw->queue_redraw(); } - - dragging_selected_attempt = false; - dragging_selected = false; - blend_space_draw->update(); } // *set* the blend @@ -172,20 +178,20 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos += blend_space->get_min_space(); AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && !blend_space_draw->has_focus()) { blend_space_draw->grab_focus(); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } if (mm.is_valid() && dragging_selected_attempt) { dragging_selected = true; drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0)); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); _update_edited_point_pos(); } @@ -196,7 +202,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } } @@ -255,10 +261,12 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { for (int i = 0; i < blend_space->get_blend_point_count(); i++) { float point = blend_space->get_blend_point_position(i); - if (dragging_selected && selected_point == i) { - point += drag_ofs.x; - if (snap->is_pressed()) { - point = Math::snapped(point, blend_space->get_snap()); + if (!read_only) { + if (dragging_selected && selected_point == i) { + point += drag_ofs.x; + if (snap->is_pressed()) { + point = Math::snapped(point, blend_space->get_snap()); + } } } @@ -322,7 +330,7 @@ void AnimationNodeBlendSpace1DEditor::_update_space() { snap_value->set_value(blend_space->get_snap()); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); updating = false; } @@ -347,7 +355,7 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace1DEditor::_labels_changed(String) { @@ -366,7 +374,7 @@ void AnimationNodeBlendSpace1DEditor::_labels_changed(String) { } void AnimationNodeBlendSpace1DEditor::_snap_toggled() { - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) { @@ -417,7 +425,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { @@ -435,7 +443,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) { @@ -448,7 +456,7 @@ void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) { } _update_tool_erase(); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() { @@ -475,7 +483,7 @@ void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() { void AnimationNodeBlendSpace1DEditor::_update_tool_erase() { bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count(); - tool_erase->set_disabled(!point_valid); + tool_erase->set_disabled(!point_valid || read_only); if (point_valid) { Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); @@ -486,7 +494,11 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() { open_editor->hide(); } - edit_hb->show(); + if (!read_only) { + edit_hb->show(); + } else { + edit_hb->hide(); + } } else { edit_hb->hide(); } @@ -505,7 +517,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() { updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } } @@ -525,7 +537,7 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace1DEditor::_open_editor() { @@ -590,10 +602,20 @@ bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) { blend_space = p_node; + read_only = false; if (!blend_space.is_null()) { + read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space); + _update_space(); } + + tool_create->set_disabled(read_only); + edit_value->set_editable(!read_only); + label_value->set_editable(!read_only); + min_value->set_editable(!read_only); + max_value->set_editable(!read_only); + sync->set_disabled(read_only); } AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr; @@ -613,7 +635,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { tool_blend->set_button_group(bg); top_hb->add_child(tool_blend); tool_blend->set_pressed(true); - tool_blend->set_tooltip(TTR("Set the blending position within the space")); + tool_blend->set_tooltip_text(TTR("Set the blending position within the space")); tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(3)); tool_select = memnew(Button); @@ -621,7 +643,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { tool_select->set_toggle_mode(true); tool_select->set_button_group(bg); top_hb->add_child(tool_select); - tool_select->set_tooltip(TTR("Select and move points, create points with RMB.")); + tool_select->set_tooltip_text(TTR("Select and move points, create points with RMB.")); tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(0)); tool_create = memnew(Button); @@ -629,7 +651,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { tool_create->set_toggle_mode(true); tool_create->set_button_group(bg); top_hb->add_child(tool_create); - tool_create->set_tooltip(TTR("Create points.")); + tool_create->set_tooltip_text(TTR("Create points.")); tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(1)); tool_erase_sep = memnew(VSeparator); @@ -637,7 +659,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { tool_erase = memnew(Button); tool_erase->set_flat(true); top_hb->add_child(tool_erase); - tool_erase->set_tooltip(TTR("Erase points.")); + tool_erase->set_tooltip_text(TTR("Erase points.")); tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected)); top_hb->add_child(memnew(VSeparator)); @@ -647,7 +669,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { snap->set_toggle_mode(true); top_hb->add_child(snap); snap->set_pressed(true); - snap->set_tooltip(TTR("Enable snap and show grid.")); + snap->set_tooltip_text(TTR("Enable snap and show grid.")); snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_snap_toggled)); snap_value = memnew(SpinBox); diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h index 125a3382fa..c8b01cb54b 100644 --- a/editor/plugins/animation_blend_space_1d_editor.h +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -46,6 +46,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin); Ref<AnimationNodeBlendSpace1D> blend_space; + bool read_only = false; HBoxContainer *goto_parent_hb = nullptr; Button *goto_parent = nullptr; diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index c0723cef87..1646a1cef4 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -52,7 +52,7 @@ bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) } void AnimationNodeBlendSpace2DEditor::_blend_space_changed() { - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) { @@ -60,11 +60,29 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) { blend_space->disconnect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed)); } blend_space = p_node; + read_only = false; if (!blend_space.is_null()) { + read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space); + blend_space->connect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed)); _update_space(); } + + tool_create->set_disabled(read_only); + interpolation->set_disabled(read_only); + max_x_value->set_editable(!read_only); + min_x_value->set_editable(!read_only); + max_y_value->set_editable(!read_only); + min_y_value->set_editable(!read_only); + label_x->set_editable(!read_only); + label_y->set_editable(!read_only); + edit_x->set_editable(!read_only); + edit_y->set_editable(!read_only); + tool_triangle->set_disabled(read_only); + auto_triangles->set_disabled(read_only); + sync->set_disabled(read_only); + interpolation->set_disabled(read_only); } StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const { @@ -76,7 +94,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) { if (selected_point != -1 || selected_triangle != -1) { - _erase_selected(); + if (!read_only) { + _erase_selected(); + } accept_event(); } } @@ -84,62 +104,64 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) { - menu->clear(); - animations_menu->clear(); - animations_to_add.clear(); - List<StringName> classes; - classes.sort_custom<StringName::AlphCompare>(); - - ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); - menu->add_submenu_item(TTR("Add Animation"), "animations"); - - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); - ERR_FAIL_COND(!gp); - if (gp && gp->has_node(gp->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); - if (ap) { - List<StringName> names; - ap->get_animation_list(&names); - for (const StringName &E : names) { - animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E); - animations_to_add.push_back(E); + if (!read_only) { + menu->clear(); + animations_menu->clear(); + animations_to_add.clear(); + List<StringName> classes; + classes.sort_custom<StringName::AlphCompare>(); + + ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); + menu->add_submenu_item(TTR("Add Animation"), "animations"); + + AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree(); + ERR_FAIL_COND(!gp); + if (gp && gp->has_node(gp->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); + if (ap) { + List<StringName> names; + ap->get_animation_list(&names); + for (const StringName &E : names) { + animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E); + animations_to_add.push_back(E); + } } } - } - for (const StringName &E : classes) { - String name = String(E).replace_first("AnimationNode", ""); - if (name == "Animation" || name == "StartState" || name == "EndState") { - continue; // nope + for (const StringName &E : classes) { + String name = String(E).replace_first("AnimationNode", ""); + if (name == "Animation" || name == "StartState" || name == "EndState") { + continue; // nope + } + int idx = menu->get_item_count(); + menu->add_item(vformat(TTR("Add %s"), name), idx); + menu->set_item_metadata(idx, E); } - int idx = menu->get_item_count(); - menu->add_item(vformat(TTR("Add %s"), name), idx); - menu->set_item_metadata(idx, E); - } - Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); - if (clipb.is_valid()) { + Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard(); + if (clipb.is_valid()) { + menu->add_separator(); + menu->add_item(TTR("Paste"), MENU_PASTE); + } menu->add_separator(); - menu->add_item(TTR("Paste"), MENU_PASTE); - } - menu->add_separator(); - menu->add_item(TTR("Load..."), MENU_LOAD_FILE); - - menu->set_position(blend_space_draw->get_screen_position() + mb->get_position()); - menu->reset_size(); - menu->popup(); - add_point_pos = (mb->get_position() / blend_space_draw->get_size()); - add_point_pos.y = 1.0 - add_point_pos.y; - add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); - add_point_pos += blend_space->get_min_space(); - - if (snap->is_pressed()) { - add_point_pos = add_point_pos.snapped(blend_space->get_snap()); + menu->add_item(TTR("Load..."), MENU_LOAD_FILE); + + menu->set_position(blend_space_draw->get_screen_position() + mb->get_position()); + menu->reset_size(); + menu->popup(); + add_point_pos = (mb->get_position() / blend_space_draw->get_size()); + add_point_pos.y = 1.0 - add_point_pos.y; + add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); + add_point_pos += blend_space->get_min_space(); + + if (snap->is_pressed()) { + add_point_pos = add_point_pos.snapped(blend_space->get_snap()); + } } } if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - blend_space_draw->update(); //update anyway + blend_space_draw->queue_redraw(); //update anyway //try to see if a point can be selected selected_point = -1; selected_triangle = -1; @@ -179,7 +201,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - blend_space_draw->update(); //update anyway + blend_space_draw->queue_redraw(); //update anyway //try to see if a point can be selected selected_point = -1; @@ -222,21 +244,23 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven point = point.snapped(blend_space->get_snap()); } - updating = true; - undo_redo->create_action(TTR("Move Node Point")); - undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); - undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); - undo_redo->add_do_method(this, "_update_space"); - undo_redo->add_undo_method(this, "_update_space"); - undo_redo->add_do_method(this, "_update_edited_point_pos"); - undo_redo->add_undo_method(this, "_update_edited_point_pos"); - undo_redo->commit_action(); - updating = false; - _update_edited_point_pos(); + if (!read_only) { + updating = true; + undo_redo->create_action(TTR("Move Node Point")); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->add_do_method(this, "_update_edited_point_pos"); + undo_redo->add_undo_method(this, "_update_edited_point_pos"); + undo_redo->commit_action(); + updating = false; + _update_edited_point_pos(); + } } dragging_selected_attempt = false; dragging_selected = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { @@ -247,30 +271,32 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && !blend_space_draw->has_focus()) { blend_space_draw->grab_focus(); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } if (mm.is_valid() && dragging_selected_attempt) { dragging_selected = true; - drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1); - blend_space_draw->update(); + if (!read_only) { + drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1); + } + blend_space_draw->queue_redraw(); _update_edited_point_pos(); } if (mm.is_valid() && tool_triangle->is_pressed() && making_triangle.size()) { - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } if (mm.is_valid() && !tool_triangle->is_pressed() && making_triangle.size()) { making_triangle.clear(); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } if (mm.is_valid() && tool_blend->is_pressed() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) { @@ -281,7 +307,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } } @@ -333,7 +359,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { @@ -351,11 +377,14 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace2DEditor::_update_tool_erase() { - tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())); + tool_erase->set_disabled( + (!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())) || + read_only); + if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); if (AnimationTreeEditor::get_singleton()->can_edit(an)) { @@ -363,7 +392,11 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() { } else { open_editor->hide(); } - edit_hb->show(); + if (!read_only) { + edit_hb->show(); + } else { + edit_hb->hide(); + } } else { edit_hb->hide(); } @@ -391,7 +424,7 @@ void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) { tool_erase_sep->hide(); } _update_tool_erase(); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { @@ -503,10 +536,12 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { points.clear(); for (int i = 0; i < blend_space->get_blend_point_count(); i++) { Vector2 point = blend_space->get_blend_point_position(i); - if (dragging_selected && selected_point == i) { - point += drag_ofs; - if (snap->is_pressed()) { - point = point.snapped(blend_space->get_snap()); + if (!read_only) { + if (dragging_selected && selected_point == i) { + point += drag_ofs; + if (snap->is_pressed()) { + point = point.snapped(blend_space->get_snap()); + } } } point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); @@ -579,7 +614,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } void AnimationNodeBlendSpace2DEditor::_snap_toggled() { - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace2DEditor::_update_space() { @@ -612,7 +647,7 @@ void AnimationNodeBlendSpace2DEditor::_update_space() { snap_x->set_value(blend_space->get_snap().x); snap_y->set_value(blend_space->get_snap().y); - blend_space_draw->update(); + blend_space_draw->queue_redraw(); updating = false; } @@ -639,7 +674,7 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { @@ -681,7 +716,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } else if (selected_triangle != -1) { updating = true; undo_redo->create_action(TTR("Remove BlendSpace2D Triangle")); @@ -693,7 +728,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } } @@ -732,7 +767,7 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) { undo_redo->commit_action(); updating = false; - blend_space_draw->update(); + blend_space_draw->queue_redraw(); } void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { @@ -833,7 +868,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { tool_blend->set_button_group(bg); top_hb->add_child(tool_blend); tool_blend->set_pressed(true); - tool_blend->set_tooltip(TTR("Set the blending position within the space")); + tool_blend->set_tooltip_text(TTR("Set the blending position within the space")); tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(3)); tool_select = memnew(Button); @@ -841,7 +876,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { tool_select->set_toggle_mode(true); tool_select->set_button_group(bg); top_hb->add_child(tool_select); - tool_select->set_tooltip(TTR("Select and move points, create points with RMB.")); + tool_select->set_tooltip_text(TTR("Select and move points, create points with RMB.")); tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(0)); tool_create = memnew(Button); @@ -849,7 +884,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { tool_create->set_toggle_mode(true); tool_create->set_button_group(bg); top_hb->add_child(tool_create); - tool_create->set_tooltip(TTR("Create points.")); + tool_create->set_tooltip_text(TTR("Create points.")); tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(1)); tool_triangle = memnew(Button); @@ -857,7 +892,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { tool_triangle->set_toggle_mode(true); tool_triangle->set_button_group(bg); top_hb->add_child(tool_triangle); - tool_triangle->set_tooltip(TTR("Create triangles by connecting points.")); + tool_triangle->set_tooltip_text(TTR("Create triangles by connecting points.")); tool_triangle->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(2)); tool_erase_sep = memnew(VSeparator); @@ -865,7 +900,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { tool_erase = memnew(Button); tool_erase->set_flat(true); top_hb->add_child(tool_erase); - tool_erase->set_tooltip(TTR("Erase points and triangles.")); + tool_erase->set_tooltip_text(TTR("Erase points and triangles.")); tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_erase_selected)); tool_erase->set_disabled(true); @@ -876,7 +911,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { top_hb->add_child(auto_triangles); auto_triangles->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled)); auto_triangles->set_toggle_mode(true); - auto_triangles->set_tooltip(TTR("Generate blend triangles automatically (instead of manually)")); + auto_triangles->set_tooltip_text(TTR("Generate blend triangles automatically (instead of manually)")); top_hb->add_child(memnew(VSeparator)); @@ -885,7 +920,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { snap->set_toggle_mode(true); top_hb->add_child(snap); snap->set_pressed(true); - snap->set_tooltip(TTR("Enable snap and show grid.")); + snap->set_tooltip_text(TTR("Enable snap and show grid.")); snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_snap_toggled)); snap_x = memnew(SpinBox); diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index df2bcf254d..1f015a1804 100644 --- a/editor/plugins/animation_blend_space_2d_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -46,6 +46,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin); Ref<AnimationNodeBlendSpace2D> blend_space; + bool read_only = false; PanelContainer *panel = nullptr; Button *tool_blend = nullptr; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index e4f5576d66..8dd3223b19 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -134,6 +134,8 @@ void AnimationNodeBlendTreeEditor::_update_graph() { GraphNode *node = memnew(GraphNode); graph->add_child(node); + node->set_draggable(!read_only); + Ref<AnimationNode> agnode = blend_tree->get_node(E); ERR_CONTINUE(!agnode.is_valid()); @@ -146,9 +148,10 @@ void AnimationNodeBlendTreeEditor::_update_graph() { if (String(E) != "output") { LineEdit *name = memnew(LineEdit); name->set_text(E); + name->set_editable(!read_only); name->set_expand_to_text_length_enabled(true); node->add_child(name); - node->set_slot(0, false, 0, Color(), true, 0, get_theme_color(SNAME("font_color"), SNAME("Label"))); + node->set_slot(0, false, 0, Color(), true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label"))); name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed).bind(agnode), CONNECT_DEFERRED); name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(name, agnode), CONNECT_DEFERRED); base = 1; @@ -160,7 +163,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { Label *in_name = memnew(Label); node->add_child(in_name); in_name->set_text(agnode->get_input_name(i)); - node->set_slot(base + i, true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color()); + node->set_slot(base + i, true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color()); } List<PropertyInfo> pinfo; @@ -172,6 +175,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name; EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F.type, base_path, F.hint, F.hint_string, F.usage); if (prop) { + prop->set_read_only(read_only); prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path); prop->update_property(); prop->set_name_split_ratio(0); @@ -195,12 +199,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() { if (agnode->has_filter()) { node->add_child(memnew(HSeparator)); - Button *edit_filters = memnew(Button); - edit_filters->set_text(TTR("Edit Filters")); - edit_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons"))); - node->add_child(edit_filters); - edit_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_edit_filters).bind(E), CONNECT_DEFERRED); - edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER); + Button *inspect_filters = memnew(Button); + if (read_only) { + inspect_filters->set_text(TTR("Inspect Filters")); + } else { + inspect_filters->set_text(TTR("Edit Filters")); + } + inspect_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons"))); + node->add_child(inspect_filters); + inspect_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_inspect_filters).bind(E), CONNECT_DEFERRED); + inspect_filters->set_h_size_flags(SIZE_SHRINK_CENTER); } Ref<AnimationNodeAnimation> anim = agnode; @@ -208,6 +216,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { MenuButton *mb = memnew(MenuButton); mb->set_text(anim->get_animation()); mb->set_icon(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons"))); + mb->set_disabled(read_only); Array options; node->add_child(memnew(HSeparator)); @@ -370,10 +379,18 @@ void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2 } void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) { + if (read_only) { + return; + } + _popup(false, graph->get_screen_position() + graph->get_local_mouse_position(), p_position); } void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) { + if (read_only) { + return; + } + Ref<AnimationNode> node = blend_tree->get_node(p_from); if (node.is_valid()) { from_node = p_from; @@ -382,6 +399,10 @@ void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, in } void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) { + if (read_only) { + return; + } + Ref<AnimationNode> node = blend_tree->get_node(p_to); if (node.is_valid()) { to_node = p_to; @@ -402,6 +423,10 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve } void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) { + if (read_only) { + return; + } + AnimationNodeBlendTree::ConnectionError err = blend_tree->can_connect_node(p_to, p_to_index, p_from); if (err != AnimationNodeBlendTree::CONNECTION_OK) { @@ -418,6 +443,10 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int } void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) { + if (read_only) { + return; + } + graph->disconnect_node(p_from, p_from_index, p_to, p_to_index); updating = true; @@ -445,6 +474,10 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, } void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { + if (read_only) { + return; + } + undo_redo->create_action(TTR("Delete Node")); undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which); undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which)); @@ -464,6 +497,10 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { } void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<StringName> &p_nodes) { + if (read_only) { + return; + } + List<StringName> to_erase; if (p_nodes.is_empty()) { @@ -495,6 +532,10 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String } void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) { + if (read_only) { + return; + } + GraphNode *gn = Object::cast_to<GraphNode>(p_node); ERR_FAIL_COND(!gn); @@ -679,7 +720,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano } } - ti->set_editable(0, true); + ti->set_editable(0, !read_only); ti->set_selectable(0, true); ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_text(0, concat); @@ -692,7 +733,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano ti = filters->create_item(ti); ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_text(0, concat); - ti->set_editable(0, true); + ti->set_editable(0, !read_only); ti->set_selectable(0, true); ti->set_checked(0, anode->is_path_filtered(path)); ti->set_metadata(0, path); @@ -714,7 +755,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano ti = filters->create_item(ti); ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_text(0, types_text); - ti->set_editable(0, true); + ti->set_editable(0, !read_only); ti->set_selectable(0, true); ti->set_checked(0, anode->is_path_filtered(path)); ti->set_metadata(0, path); @@ -727,7 +768,15 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano return true; } -void AnimationNodeBlendTreeEditor::_edit_filters(const String &p_which) { +void AnimationNodeBlendTreeEditor::_inspect_filters(const String &p_which) { + if (read_only) { + filter_dialog->set_title(TTR("Inspect Filtered Tracks:")); + } else { + filter_dialog->set_title(TTR("Edit Filtered Tracks:")); + } + + filter_enabled->set_disabled(read_only); + Ref<AnimationNode> anode = blend_tree->get_node(p_which); ERR_FAIL_COND(!anode.is_valid()); @@ -838,6 +887,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { } void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) { + if (read_only) { + return; + } + if (updating) { return; } @@ -944,13 +997,20 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) { blend_tree = p_node; + read_only = false; + if (blend_tree.is_null()) { hide(); } else { + read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree); + blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph)); _update_graph(); } + + add_node->set_disabled(read_only); + graph->set_arrange_nodes_button_hidden(read_only); } AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { @@ -986,6 +1046,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { graph->get_zoom_hbox()->move_child(add_node, 0); add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node)); add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu).bind(false)); + add_node->set_disabled(read_only); add_options.push_back(AddOption("Animation", "AnimationNodeAnimation")); add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot", 2)); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index af43da6197..30a54930a2 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -47,6 +47,9 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin); Ref<AnimationNodeBlendTree> blend_tree; + + bool read_only = false; + GraphEdit *graph = nullptr; MenuButton *add_node = nullptr; Vector2 position_from_popup_menu; @@ -106,7 +109,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _delete_nodes_request(const TypedArray<StringName> &p_nodes); bool _update_filters(const Ref<AnimationNode> &anode); - void _edit_filters(const String &p_which); + void _inspect_filters(const String &p_which); void _filter_edited(); void _filter_toggled(); Ref<AnimationNode> _filter_edit; diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index f9e5aa799a..50ba1a71c0 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -635,7 +635,7 @@ void AnimationLibraryEditor::update_tree() { String al_path = al->get_path(); if (!al_path.is_resource_file()) { libitem->set_text(1, TTR("[built-in]")); - libitem->set_tooltip(1, al_path); + libitem->set_tooltip_text(1, al_path); int srpos = al_path.find("::"); if (srpos != -1) { String base = al_path.substr(0, srpos); @@ -687,7 +687,7 @@ void AnimationLibraryEditor::update_tree() { String anim_path = anim->get_path(); if (!anim_path.is_resource_file()) { anitem->set_text(1, TTR("[built-in]")); - anitem->set_tooltip(1, anim_path); + anitem->set_tooltip_text(1, anim_path); int srpos = anim_path.find("::"); if (srpos != -1) { String base = anim_path.substr(0, srpos); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index f374f48fb2..1ab60e8fc8 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -843,15 +843,16 @@ void AnimationPlayerEditor::_update_player() { animation->clear(); + tool_anim->set_disabled(player == nullptr); + pin->set_disabled(player == nullptr); + if (!player) { AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying(); return; } List<StringName> libraries; - if (player) { - player->get_animation_library_list(&libraries); - } + player->get_animation_library_list(&libraries); int active_idx = -1; bool no_anims_found = true; @@ -926,10 +927,8 @@ void AnimationPlayerEditor::_update_player() { frame->set_editable(!no_anims_found); animation->set_disabled(no_anims_found); autoplay->set_disabled(no_anims_found); - tool_anim->set_disabled(player == nullptr); onion_toggle->set_disabled(no_anims_found); onion_skinning->set_disabled(no_anims_found); - pin->set_disabled(player == nullptr); _update_animation_list_icons(); @@ -1646,28 +1645,28 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug play_bw_from = memnew(Button); play_bw_from->set_flat(true); - play_bw_from->set_tooltip(TTR("Play selected animation backwards from current pos. (A)")); + play_bw_from->set_tooltip_text(TTR("Play selected animation backwards from current pos. (A)")); hb->add_child(play_bw_from); play_bw = memnew(Button); play_bw->set_flat(true); - play_bw->set_tooltip(TTR("Play selected animation backwards from end. (Shift+A)")); + play_bw->set_tooltip_text(TTR("Play selected animation backwards from end. (Shift+A)")); hb->add_child(play_bw); stop = memnew(Button); stop->set_flat(true); stop->set_toggle_mode(true); hb->add_child(stop); - stop->set_tooltip(TTR("Stop animation playback. (S)")); + stop->set_tooltip_text(TTR("Stop animation playback. (S)")); play = memnew(Button); play->set_flat(true); - play->set_tooltip(TTR("Play selected animation from start. (Shift+D)")); + play->set_tooltip_text(TTR("Play selected animation from start. (Shift+D)")); hb->add_child(play); play_from = memnew(Button); play_from->set_flat(true); - play_from->set_tooltip(TTR("Play selected animation from current pos. (D)")); + play_from->set_tooltip_text(TTR("Play selected animation from current pos. (D)")); hb->add_child(play_from); frame = memnew(SpinBox); @@ -1675,7 +1674,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug frame->set_custom_minimum_size(Size2(80, 0) * EDSCALE); frame->set_stretch_ratio(2); frame->set_step(0.0001); - frame->set_tooltip(TTR("Animation position (in seconds).")); + frame->set_tooltip_text(TTR("Animation position (in seconds).")); hb->add_child(memnew(VSeparator)); @@ -1683,7 +1682,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug hb->add_child(scale); scale->set_h_size_flags(SIZE_EXPAND_FILL); scale->set_stretch_ratio(1); - scale->set_tooltip(TTR("Scale animation playback globally for the node.")); + scale->set_tooltip_text(TTR("Scale animation playback globally for the node.")); scale->hide(); delete_dialog = memnew(ConfirmationDialog); @@ -1693,7 +1692,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug tool_anim = memnew(MenuButton); tool_anim->set_shortcut_context(this); tool_anim->set_flat(false); - tool_anim->set_tooltip(TTR("Animation Tools")); + tool_anim->set_tooltip_text(TTR("Animation Tools")); tool_anim->set_text(TTR("Animation")); tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/new_animation", TTR("New")), TOOL_NEW_ANIM); tool_anim->get_popup()->add_separator(); @@ -1712,13 +1711,13 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug animation = memnew(OptionButton); hb->add_child(animation); animation->set_h_size_flags(SIZE_EXPAND_FILL); - animation->set_tooltip(TTR("Display list of animations in player.")); + animation->set_tooltip_text(TTR("Display list of animations in player.")); animation->set_clip_text(true); autoplay = memnew(Button); autoplay->set_flat(true); hb->add_child(autoplay); - autoplay->set_tooltip(TTR("Autoplay on Load")); + autoplay->set_tooltip_text(TTR("Autoplay on Load")); hb->add_child(memnew(VSeparator)); @@ -1731,12 +1730,12 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug onion_toggle = memnew(Button); onion_toggle->set_flat(true); onion_toggle->set_toggle_mode(true); - onion_toggle->set_tooltip(TTR("Enable Onion Skinning")); + onion_toggle->set_tooltip_text(TTR("Enable Onion Skinning")); onion_toggle->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu).bind(ONION_SKINNING_ENABLE)); hb->add_child(onion_toggle); onion_skinning = memnew(MenuButton); - onion_skinning->set_tooltip(TTR("Onion Skinning Options")); + onion_skinning->set_tooltip_text(TTR("Onion Skinning Options")); onion_skinning->get_popup()->add_separator(TTR("Directions")); // TRANSLATORS: Opposite of "Future", refers to a direction in animation onion skinning. onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST); @@ -1759,7 +1758,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug pin = memnew(Button); pin->set_flat(true); pin->set_toggle_mode(true); - pin->set_tooltip(TTR("Pin AnimationPlayer")); + pin->set_tooltip_text(TTR("Pin AnimationPlayer")); hb->add_child(pin); pin->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed)); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index ef4ae3dca4..2809eb01cd 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -56,7 +56,11 @@ bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { state_machine = p_node; + read_only = false; + if (state_machine.is_valid()) { + read_only = EditorNode::get_singleton()->is_resource_read_only(state_machine); + selected_transition_from = StringName(); selected_transition_to = StringName(); selected_transition_index = -1; @@ -66,6 +70,9 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { _update_mode(); _update_graph(); } + + tool_create->set_disabled(read_only); + tool_connect->set_disabled(read_only); } void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { @@ -77,7 +84,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) { if (selected_node != StringName() || !selected_nodes.is_empty() || selected_transition_to != StringName() || selected_transition_from != StringName()) { - _erase_selected(); + if (!read_only) { + _erase_selected(); + } accept_event(); } } @@ -95,9 +104,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv Ref<InputEventMouseButton> mb = p_event; // Add new node - if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) { - connecting_from = StringName(); - _open_menu(mb->get_position()); + if (!read_only) { + if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) { + connecting_from = StringName(); + _open_menu(mb->get_position()); + } } // Select node or push a field inside @@ -117,26 +128,28 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv //travel playback->travel(node_rects[i].node_name); } - state_machine_draw->update(); + state_machine_draw->queue_redraw(); return; } - if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name - Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit")); + if (!read_only) { + if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name + Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit")); - Rect2 edit_rect = node_rects[i].name; - edit_rect.position -= line_sb->get_offset(); - edit_rect.size += line_sb->get_minimum_size(); + Rect2 edit_rect = node_rects[i].name; + edit_rect.position -= line_sb->get_offset(); + edit_rect.size += line_sb->get_minimum_size(); - name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position); - name_edit_popup->set_size(edit_rect.size); - name_edit->set_text(node_rects[i].node_name); - name_edit_popup->popup(); - name_edit->grab_focus(); - name_edit->select_all(); + name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position); + name_edit_popup->set_size(edit_rect.size); + name_edit->set_text(node_rects[i].node_name); + name_edit_popup->popup(); + name_edit->grab_focus(); + name_edit->select_all(); - prev_name = node_rects[i].node_name; - return; + prev_name = node_rects[i].node_name; + return; + } } if (node_rects[i].edit.has_point(mb->get_position())) { //edit name @@ -155,7 +168,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv Ref<AnimationNode> anode = state_machine->get_node(selected_node); EditorNode::get_singleton()->push_item(anode.ptr(), "", true); - state_machine_draw->update(); + state_machine_draw->queue_redraw(); dragging_selected_attempt = true; dragging_selected = false; drag_from = mb->get_position(); @@ -215,7 +228,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } } - state_machine_draw->update(); + state_machine_draw->queue_redraw(); _update_mode(); } @@ -246,7 +259,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv dragging_selected_attempt = false; dragging_selected = false; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } // Connect nodes @@ -283,7 +296,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv _open_menu(mb->get_position()); } connecting_to_node = StringName(); - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } // Start box selecting @@ -306,7 +319,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv // End box selecting if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed() && box_selecting) { box_selecting = false; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); _update_mode(); } @@ -319,10 +332,10 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } // Move mouse while connecting - if (mm.is_valid() && connecting) { + if (mm.is_valid() && connecting && !read_only) { connecting_to = mm->get_position(); connecting_to_node = StringName(); - state_machine_draw->update(); + state_machine_draw->queue_redraw(); for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].node_name != connecting_from && node_rects[i].node.has_point(connecting_to)) { //select node since nothing else was selected @@ -333,7 +346,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } // Move mouse while moving a node - if (mm.is_valid() && dragging_selected_attempt) { + if (mm.is_valid() && dragging_selected_attempt && !read_only) { dragging_selected = true; drag_ofs = mm->get_position() - drag_from; snap_x = StringName(); @@ -369,7 +382,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } } - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } // Move mouse while moving box select @@ -399,7 +412,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } } - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } if (mm.is_valid()) { @@ -429,7 +442,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv if (new_over_node != over_node || new_over_node_what != over_node_what) { over_node = new_over_node; over_node_what = new_over_node_what; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } // set tooltip for transition @@ -463,9 +476,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv to = String(transition_lines[closest].multi_transitions[i].to_node); tooltip += "\n" + from + " -> " + to; } - state_machine_draw->set_tooltip(tooltip); + state_machine_draw->set_tooltip_text(tooltip); } else { - state_machine_draw->set_tooltip(""); + state_machine_draw->set_tooltip_text(""); } } } @@ -478,17 +491,21 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Point2 &p_pos) const { - // Put ibeam (text cursor) over names to make it clearer that they are editable. - Transform2D xform = panel->get_transform() * state_machine_draw->get_transform(); - Point2 pos = xform.xform_inv(p_pos); Control::CursorShape cursor_shape = get_default_cursor_shape(); - - for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order. - if (node_rects[i].node.has_point(pos)) { - if (node_rects[i].name.has_point(pos)) { - cursor_shape = Control::CURSOR_IBEAM; + if (!read_only) { + // Put ibeam (text cursor) over names to make it clearer that they are editable. + Transform2D xform = panel->get_transform() * state_machine_draw->get_transform(); + Point2 pos = xform.xform_inv(p_pos); + + for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order. + if (node_rects[i].node.has_point(pos)) { + if (node_rects[i].name.has_point(pos)) { + if (state_machine->can_edit_node(node_rects[i].node_name)) { + cursor_shape = Control::CURSOR_IBEAM; + } + } + break; } - break; } } return cursor_shape; @@ -603,7 +620,7 @@ void AnimationNodeStateMachineEditor::_group_selected_nodes() { selected_nodes.clear(); selected_nodes.insert(group_name); - state_machine_draw->update(); + state_machine_draw->queue_redraw(); accept_event(); _update_mode(); } @@ -704,7 +721,7 @@ void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() { if (find) { selected_nodes = new_selected_nodes; selected_node = StringName(); - state_machine_draw->update(); + state_machine_draw->queue_redraw(); accept_event(); _update_mode(); } @@ -785,8 +802,7 @@ void AnimationNodeStateMachineEditor::_open_connect_menu(const Vector2 &p_positi if (anodesm.is_valid()) { _create_submenu(connect_menu, anodesm, connecting_to_node, connecting_to_node); } else { - Ref<AnimationNodeStateMachine> prev = state_machine; - _create_submenu(connect_menu, prev, connecting_to_node, connecting_to_node, true); + _create_submenu(connect_menu, state_machine, connecting_to_node, connecting_to_node, true); } connect_menu->add_submenu_item(TTR("To") + " Animation", connecting_to_node); @@ -818,6 +834,10 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani String prev_path; Vector<Ref<AnimationNodeStateMachine>> parents = p_parents; + if (from_root && p_nodesm->get_prev_state_machine() == nullptr) { + return false; + } + if (from_root) { AnimationNodeStateMachine *prev = p_nodesm->get_prev_state_machine(); @@ -827,6 +847,8 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani prev_path += "../"; prev = prev->get_prev_state_machine(); } + end_menu->add_item("Root", nodes_to_connect.size()); + nodes_to_connect.push_back(prev_path + state_machine->end_node); prev_path.remove_at(prev_path.size() - 1); } @@ -857,22 +879,22 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani } if (ansm.is_valid()) { - bool found = false; + bool parent_found = false; for (int i = 0; i < parents.size(); i++) { if (parents[i] == ansm) { path = path.replace_first("/../" + E, ""); - found = true; + parent_found = true; break; } } - if (!found) { - state_machine_menu->add_item(E, nodes_to_connect.size()); - nodes_to_connect.push_back(path); - } else { + if (parent_found) { end_menu->add_item(E, nodes_to_connect.size()); nodes_to_connect.push_back(path + "/" + state_machine->end_node); + } else { + state_machine_menu->add_item(E, nodes_to_connect.size()); + nodes_to_connect.push_back(path); } if (_create_submenu(nodes_menu, ansm, E, path, false, parents)) { @@ -892,7 +914,7 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani void AnimationNodeStateMachineEditor::_stop_connecting() { connecting = false; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } void AnimationNodeStateMachineEditor::_delete_selected() { @@ -1011,7 +1033,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { undo_redo->commit_action(); updating = false; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { @@ -1039,7 +1061,7 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { undo_redo->commit_action(); updating = false; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } void AnimationNodeStateMachineEditor::_connect_to(int p_index) { @@ -1458,7 +1480,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { v_scroll->set_value(state_machine->get_graph_offset().y); updating = false; - state_machine_play_pos->update(); + state_machine_play_pos->queue_redraw(); } void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { @@ -1520,7 +1542,7 @@ void AnimationNodeStateMachineEditor::_update_graph() { updating = true; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); updating = false; } @@ -1592,34 +1614,34 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } if (tidx == -1) { //missing transition, should redraw - state_machine_draw->update(); + state_machine_draw->queue_redraw(); break; } if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) { - state_machine_draw->update(); + state_machine_draw->queue_redraw(); break; } if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) { - state_machine_draw->update(); + state_machine_draw->queue_redraw(); break; } if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) { - state_machine_draw->update(); + state_machine_draw->queue_redraw(); break; } if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) { - state_machine_draw->update(); + state_machine_draw->queue_redraw(); break; } bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name))); if (transition_lines[i].advance_condition_state != acstate) { - state_machine_draw->update(); + state_machine_draw->queue_redraw(); break; } } @@ -1654,14 +1676,14 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } } - //update if travel state changed + //redraw if travel state changed if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) { - state_machine_draw->update(); + state_machine_draw->queue_redraw(); last_travel_path = tp; last_current_node = current_node; last_active = is_playing; last_blend_from_node = blend_from_node; - state_machine_play_pos->update(); + state_machine_play_pos->queue_redraw(); } { @@ -1686,7 +1708,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { if (last_play_pos != play_pos) { last_play_pos = play_pos; - state_machine_play_pos->update(); + state_machine_play_pos->queue_redraw(); } } break; @@ -1732,7 +1754,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { name_edit_popup->hide(); updating = false; - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } void AnimationNodeStateMachineEditor::_name_edited_focus_out() { @@ -1749,7 +1771,7 @@ void AnimationNodeStateMachineEditor::_scroll_changed(double) { } state_machine->set_graph_offset(Vector2(h_scroll->get_value(), v_scroll->get_value())); - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action) { @@ -1840,7 +1862,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action selected_multi_transition = TransitionLine(); } - state_machine_draw->update(); + state_machine_draw->queue_redraw(); } void AnimationNodeStateMachineEditor::_update_mode() { @@ -1848,9 +1870,9 @@ void AnimationNodeStateMachineEditor::_update_mode() { tool_erase_hb->show(); bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName(); bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node); - tool_erase->set_disabled(nothing_selected || start_end_selected); + tool_erase->set_disabled(nothing_selected || start_end_selected || read_only); - if (selected_nodes.is_empty() || start_end_selected) { + if (selected_nodes.is_empty() || start_end_selected || read_only) { tool_group->set_disabled(true); tool_group->set_visible(true); tool_ungroup->set_visible(false); @@ -1900,7 +1922,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { tool_select->set_toggle_mode(true); tool_select->set_button_group(bg); tool_select->set_pressed(true); - tool_select->set_tooltip(TTR("Select and move nodes.\nRMB: Add node at position clicked.\nShift+LMB+Drag: Connects the selected node with another node or creates a new node if you select an area without nodes.")); + tool_select->set_tooltip_text(TTR("Select and move nodes.\nRMB: Add node at position clicked.\nShift+LMB+Drag: Connects the selected node with another node or creates a new node if you select an area without nodes.")); tool_select->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED); tool_create = memnew(Button); @@ -1908,7 +1930,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { top_hb->add_child(tool_create); tool_create->set_toggle_mode(true); tool_create->set_button_group(bg); - tool_create->set_tooltip(TTR("Create new nodes.")); + tool_create->set_tooltip_text(TTR("Create new nodes.")); tool_create->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED); tool_connect = memnew(Button); @@ -1916,7 +1938,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { top_hb->add_child(tool_connect); tool_connect->set_toggle_mode(true); tool_connect->set_button_group(bg); - tool_connect->set_tooltip(TTR("Connect nodes.")); + tool_connect->set_tooltip_text(TTR("Connect nodes.")); tool_connect->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED); tool_erase_hb = memnew(HBoxContainer); @@ -1925,21 +1947,21 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { tool_group = memnew(Button); tool_group->set_flat(true); - tool_group->set_tooltip(TTR("Group Selected Node(s)") + " (Ctrl+G)"); + tool_group->set_tooltip_text(TTR("Group Selected Node(s)") + " (Ctrl+G)"); tool_group->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_group_selected_nodes)); tool_group->set_disabled(true); tool_erase_hb->add_child(tool_group); tool_ungroup = memnew(Button); tool_ungroup->set_flat(true); - tool_ungroup->set_tooltip(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)"); + tool_ungroup->set_tooltip_text(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)"); tool_ungroup->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_ungroup_selected_nodes)); tool_ungroup->set_visible(false); tool_erase_hb->add_child(tool_ungroup); tool_erase = memnew(Button); tool_erase->set_flat(true); - tool_erase->set_tooltip(TTR("Remove selected node or transition.")); + tool_erase->set_tooltip_text(TTR("Remove selected node or transition.")); tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected).bind(false)); tool_erase->set_disabled(true); tool_erase_hb->add_child(tool_erase); diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index fdd1af0f6d..3a59e94a5f 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -47,6 +47,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { Ref<AnimationNodeStateMachine> state_machine; + bool read_only = false; + Button *tool_select = nullptr; Button *tool_create = nullptr; Button *tool_connect = nullptr; diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index bce4c9de8e..ed231c446b 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -59,10 +59,11 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) { Vector<String> path; if (tree && tree->has_meta("_tree_edit_path")) { path = tree->get_meta("_tree_edit_path"); - edit_path(path); } else { current_root = ObjectID(); } + + edit_path(path); } void AnimationTreeEditor::_path_button_pressed(int p_path) { @@ -129,6 +130,11 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) { } else { current_root = ObjectID(); edited_path = button_path; + + for (int i = 0; i < editors.size(); i++) { + editors[i]->edit(Ref<AnimationNode>()); + editors[i]->hide(); + } } _update_path(); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 8ee162d085..41383edafe 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -487,7 +487,7 @@ void EditorAssetLibraryItemDownload::_make_request() { retry_button->hide(); download->cancel_request(); - download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip"); + download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_asset_" + itos(asset_id)) + ".zip"); Error err = download->request(host); if (err != OK) { @@ -730,7 +730,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB PackedByteArray image_data = p_data; if (use_cache) { - String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ); if (file.is_valid()) { @@ -804,7 +804,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { if (headers[i].findn("ETag:") == 0) { // Save etag - String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges(); Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE); if (file.is_valid()) { @@ -846,7 +846,7 @@ void EditorAssetLibrary::_update_image_queue() { List<int> to_delete; for (KeyValue<int, ImageQueue> &E : image_queue) { if (!E.value.active && current_images < max_images) { - String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + E.value.image_url.md5_text()); + String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + E.value.image_url.md5_text()); Vector<String> headers; if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) { @@ -1595,7 +1595,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { /////// bool AssetLibraryEditorPlugin::is_available() { -#ifdef JAVASCRIPT_ENABLED +#ifdef WEB_ENABLED // Asset Library can't work on Web editor for now as most assets are sourced // directly from GitHub which does not set CORS. return false; diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index 5db9249af1..988f9cc394 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -294,7 +294,7 @@ void BoneMapper::create_editor() { clear_mapping_button = memnew(Button); clear_mapping_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons"))); - clear_mapping_button->set_tooltip(TTR("Clear mappings in current group.")); + clear_mapping_button->set_tooltip_text(TTR("Clear mappings in current group.")); clear_mapping_button->connect("pressed", callable_mp(this, &BoneMapper::_clear_mapping_current_group)); group_hbox->add_child(clear_mapping_button); @@ -609,7 +609,7 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic } BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(String p_bone_name) { - String fixed_bn = p_bone_name.camelcase_to_underscore().to_lower(); + String fixed_bn = p_bone_name.to_snake_case(); LocalVector<String> left_words; left_words.push_back("(?<![a-zA-Z])left"); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 3505d7fedf..c4a32d6d4b 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -487,21 +487,21 @@ void CanvasItemEditor::shortcut_input(const Ref<InputEvent> &p_ev) { if (k.is_valid()) { if (k->get_keycode() == Key::CTRL || k->get_keycode() == Key::ALT || k->get_keycode() == Key::SHIFT) { - viewport->update(); + viewport->queue_redraw(); } if (k->is_pressed() && !k->is_ctrl_pressed() && !k->is_echo() && (grid_snap_active || _is_grid_visible())) { if (multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->matches_event(p_ev)) { // Multiply the grid size grid_step_multiplier = MIN(grid_step_multiplier + 1, 12); - viewport->update(); + viewport->queue_redraw(); } else if (divide_grid_step_shortcut.is_valid() && divide_grid_step_shortcut->matches_event(p_ev)) { // Divide the grid size Point2 new_grid_step = grid_step * Math::pow(2.0, grid_step_multiplier - 1); if (new_grid_step.x >= 1.0 && new_grid_step.y >= 1.0) { grid_step_multiplier--; } - viewport->update(); + viewport->queue_redraw(); } } } @@ -758,7 +758,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po } } } - viewport->update(); + viewport->queue_redraw(); return still_selected; } @@ -875,15 +875,15 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite } } } - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_do_method(viewport, "queue_redraw"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } void CanvasItemEditor::_snap_changed() { static_cast<SnapDialog *>(snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step); grid_step_multiplier = 0; - viewport->update(); + viewport->queue_redraw(); } void CanvasItemEditor::_selection_result_pressed(int p_result) { @@ -983,7 +983,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) { case GRID_VISIBILITY_SHOW_WHEN_SNAPPING: case GRID_VISIBILITY_HIDE: grid_visibility = (GridVisibility)p_id; - viewport->update(); + viewport->queue_redraw(); view_menu->get_popup()->hide(); return; } @@ -1010,7 +1010,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) { break; } } - viewport->update(); + viewport->queue_redraw(); } bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) { @@ -1105,7 +1105,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve drag_to = xform.affine_inverse().xform(m->get_position()); dragged_guide_pos = xform.xform(snap_point(drag_to, SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES)); - viewport->update(); + viewport->queue_redraw(); return true; } @@ -1128,14 +1128,14 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve undo_redo->create_action(TTR("Move Vertical Guide")); undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } else { vguides.push_back(edited.x); undo_redo->create_action(TTR("Create Vertical Guide")); undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } } else { @@ -1148,7 +1148,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); } undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } } @@ -1161,14 +1161,14 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve undo_redo->create_action(TTR("Move Horizontal Guide")); undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } else { hguides.push_back(edited.y); undo_redo->create_action(TTR("Create Horizontal Guide")); undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } } else { @@ -1181,7 +1181,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); } undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } } @@ -1197,7 +1197,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } } @@ -1205,7 +1205,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve snap_target[0] = SNAP_TARGET_NONE; snap_target[1] = SNAP_TARGET_NONE; _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -1380,7 +1380,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) { _restore_canvas_item_state(drag_selection); _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -1430,7 +1430,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { //Rotate the opposite way if the canvas item's compounded scale has an uneven number of negative elements bool opposite = (canvas_item->get_global_transform().get_scale().sign().dot(canvas_item->get_transform().get_scale().sign()) == 0); canvas_item->_edit_set_rotation(snap_angle(canvas_item->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), canvas_item->_edit_get_rotation())); - viewport->update(); + viewport->queue_redraw(); } return true; } @@ -1463,7 +1463,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) { _restore_canvas_item_state(drag_selection); _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -1625,7 +1625,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) { _restore_canvas_item_state(drag_selection); _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -1824,7 +1824,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { snap_target[0] = SNAP_TARGET_NONE; snap_target[1] = SNAP_TARGET_NONE; _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } @@ -1834,7 +1834,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { snap_target[0] = SNAP_TARGET_NONE; snap_target[1] = SNAP_TARGET_NONE; _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -1963,7 +1963,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { } _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } @@ -1971,7 +1971,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { if (b.is_valid() && b->get_button_index() == MouseButton::RIGHT && b->is_pressed()) { _restore_canvas_item_state(drag_selection); _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -2096,7 +2096,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { snap_target[1] = SNAP_TARGET_NONE; _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } @@ -2106,7 +2106,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { snap_target[0] = SNAP_TARGET_NONE; snap_target[1] = SNAP_TARGET_NONE; _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -2214,7 +2214,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } _reset_drag(); } - viewport->update(); + viewport->queue_redraw(); return true; } @@ -2339,7 +2339,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { if (!b->is_shift_pressed()) { // Clear the selection if not additive editor_selection->clear(); - viewport->update(); + viewport->queue_redraw(); selected_from_canvas = true; }; @@ -2415,21 +2415,21 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } if (b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) { // Cancel box selection _reset_drag(); - viewport->update(); + viewport->queue_redraw(); return true; } if (m.is_valid()) { // Update box selection box_selecting_to = transform.affine_inverse().xform(m->get_position()); - viewport->update(); + viewport->queue_redraw(); return true; } } @@ -2437,7 +2437,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { if (k.is_valid() && k->is_pressed() && k->get_keycode() == Key::ESCAPE && drag_type == DRAG_NONE && tool == TOOL_SELECT) { // Unselect everything editor_selection->clear(); - viewport->update(); + viewport->queue_redraw(); } return false; } @@ -2463,12 +2463,12 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) { ruler_tool_active = false; } - viewport->update(); + viewport->queue_redraw(); return true; } if (m.is_valid() && (ruler_tool_active || (grid_snap_active && previous_origin != ruler_tool_origin))) { - viewport->update(); + viewport->queue_redraw(); return true; } @@ -2480,7 +2480,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) { if (m.is_valid()) { Point2 click = transform.affine_inverse().xform(m->get_position()); - // Checks if the hovered items changed, update the viewport if so + // Checks if the hovered items changed, redraw the viewport if so Vector<_SelectResult> hovering_results_items; _get_canvas_items_at_pos(click, hovering_results_items); hovering_results_items.sort(); @@ -2502,7 +2502,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) { hovering_results_tmp.push_back(hover_result); } - // Check if changed, if so, update. + // Check if changed, if so, redraw. bool changed = false; if (hovering_results_tmp.size() == hovering_results.size()) { for (int i = 0; i < hovering_results_tmp.size(); i++) { @@ -2519,7 +2519,7 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) { if (changed) { hovering_results = hovering_results_tmp; - viewport->update(); + viewport->queue_redraw(); } return true; @@ -3827,7 +3827,7 @@ void CanvasItemEditor::_draw_viewport() { void CanvasItemEditor::update_viewport() { _update_scrollbars(); - viewport->update(); + viewport->queue_redraw(); } void CanvasItemEditor::set_current_tool(Tool p_tool) { @@ -3895,7 +3895,7 @@ void CanvasItemEditor::_notification(int p_what) { Transform2D xform = canvas_item->get_transform(); if (rect != se->prev_rect || xform != se->prev_xform) { - viewport->update(); + viewport->queue_redraw(); se->prev_rect = rect; se->prev_xform = xform; } @@ -3917,7 +3917,7 @@ void CanvasItemEditor::_notification(int p_what) { se->prev_anchors[SIDE_RIGHT] = anchors[SIDE_RIGHT]; se->prev_anchors[SIDE_TOP] = anchors[SIDE_TOP]; se->prev_anchors[SIDE_BOTTOM] = anchors[SIDE_BOTTOM]; - viewport->update(); + viewport->queue_redraw(); } } @@ -3933,7 +3933,7 @@ void CanvasItemEditor::_notification(int p_what) { for (KeyValue<BoneKey, BoneList> &E : bone_list) { Object *b = ObjectDB::get_instance(E.key.from); if (!b) { - viewport->update(); + viewport->queue_redraw(); break; } @@ -3946,13 +3946,13 @@ void CanvasItemEditor::_notification(int p_what) { if (global_xform != E.value.xform) { E.value.xform = global_xform; - viewport->update(); + viewport->queue_redraw(); } Bone2D *bone = Object::cast_to<Bone2D>(b); if (bone && bone->get_length() != E.value.length) { E.value.length = bone->get_length(); - viewport->update(); + viewport->queue_redraw(); } } } break; @@ -4106,7 +4106,7 @@ void CanvasItemEditor::_update_scroll(real_t) { view_offset.x = h_scroll->get_value(); view_offset.y = v_scroll->get_value(); - viewport->update(); + viewport->queue_redraw(); } void CanvasItemEditor::_zoom_on_position(real_t p_zoom, Point2 p_position) { @@ -4148,12 +4148,12 @@ void CanvasItemEditor::_shortcut_zoom_set(real_t p_zoom) { void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) { smart_snap_active = p_status; - viewport->update(); + viewport->queue_redraw(); } void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) { grid_snap_active = p_status; - viewport->update(); + viewport->queue_redraw(); } void CanvasItemEditor::_button_override_camera(bool p_pressed) { @@ -4174,7 +4174,7 @@ void CanvasItemEditor::_button_tool_select(int p_index) { tool = (Tool)p_index; - viewport->update(); + viewport->queue_redraw(); _update_cursor(); } @@ -4261,11 +4261,11 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, void CanvasItemEditor::_update_override_camera_button(bool p_game_running) { if (p_game_running) { override_camera_button->set_disabled(false); - override_camera_button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera.")); + override_camera_button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera.")); } else { override_camera_button->set_disabled(true); override_camera_button->set_pressed(false); - override_camera_button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature.")); + override_camera_button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature.")); } } @@ -4276,25 +4276,25 @@ void CanvasItemEditor::_popup_callback(int p_op) { show_origin = !show_origin; int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN); view_menu->get_popup()->set_item_checked(idx, show_origin); - viewport->update(); + viewport->queue_redraw(); } break; case SHOW_VIEWPORT: { show_viewport = !show_viewport; int idx = view_menu->get_popup()->get_item_index(SHOW_VIEWPORT); view_menu->get_popup()->set_item_checked(idx, show_viewport); - viewport->update(); + viewport->queue_redraw(); } break; case SHOW_EDIT_LOCKS: { show_edit_locks = !show_edit_locks; int idx = view_menu->get_popup()->get_item_index(SHOW_EDIT_LOCKS); view_menu->get_popup()->set_item_checked(idx, show_edit_locks); - viewport->update(); + viewport->queue_redraw(); } break; case SHOW_TRANSFORMATION_GIZMOS: { show_transformation_gizmos = !show_transformation_gizmos; int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS); view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos); - viewport->update(); + viewport->queue_redraw(); } break; case SNAP_USE_NODE_PARENT: { snap_node_parent = !snap_node_parent; @@ -4340,7 +4340,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { snap_relative = !snap_relative; int idx = snap_config_menu->get_popup()->get_item_index(SNAP_RELATIVE); snap_config_menu->get_popup()->set_item_checked(idx, snap_relative); - viewport->update(); + viewport->queue_redraw(); } break; case SNAP_USE_PIXEL: { snap_pixel = !snap_pixel; @@ -4370,20 +4370,20 @@ void CanvasItemEditor::_popup_callback(int p_op) { show_helpers = !show_helpers; int idx = view_menu->get_popup()->get_item_index(SHOW_HELPERS); view_menu->get_popup()->set_item_checked(idx, show_helpers); - viewport->update(); + viewport->queue_redraw(); } break; case SHOW_RULERS: { show_rulers = !show_rulers; int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS); view_menu->get_popup()->set_item_checked(idx, show_rulers); _update_scrollbars(); - viewport->update(); + viewport->queue_redraw(); } break; case SHOW_GUIDES: { show_guides = !show_guides; int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES); view_menu->get_popup()->set_item_checked(idx, show_guides); - viewport->update(); + viewport->queue_redraw(); } break; case LOCK_SELECTED: { undo_redo->create_action(TTR("Lock Selected")); @@ -4403,8 +4403,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_do_method(viewport, "queue_redraw"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } break; case UNLOCK_SELECTED: { @@ -4425,8 +4425,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed"); undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_do_method(viewport, "queue_redraw"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } break; case GROUP_SELECTED: { @@ -4447,8 +4447,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_do_method(viewport, "queue_redraw"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } break; case UNGROUP_SELECTED: { @@ -4469,8 +4469,8 @@ void CanvasItemEditor::_popup_callback(int p_op) { undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed"); undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_do_method(viewport, "queue_redraw"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } break; @@ -4590,7 +4590,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { undo_redo->add_do_method(root, "remove_meta", "_edit_vertical_guides_"); undo_redo->add_undo_method(root, "set_meta", "_edit_vertical_guides_", vguides); } - undo_redo->add_undo_method(viewport, "update"); + undo_redo->add_undo_method(viewport, "queue_redraw"); undo_redo->commit_action(); } @@ -4704,7 +4704,7 @@ void CanvasItemEditor::_focus_selection(int p_op) { real_t scale_y = viewport->get_size().y / rect.size.y; zoom = scale_x < scale_y ? scale_x : scale_y; zoom *= 0.90; - viewport->update(); + viewport->queue_redraw(); zoom_widget->set_zoom(zoom); call_deferred(SNAME("_popup_callback"), VIEW_CENTER_TO_SELECTION); } @@ -4930,7 +4930,7 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { if (update_scrollbars) { _update_scrollbars(); } - viewport->update(); + viewport->queue_redraw(); } void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) { @@ -4980,7 +4980,7 @@ CanvasItemEditor::CanvasItemEditor() { undo_redo = EditorNode::get_singleton()->get_undo_redo(); editor_selection = EditorNode::get_singleton()->get_editor_selection(); editor_selection->add_editor_plugin(this); - editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); + editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed)); SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created)); @@ -5104,7 +5104,7 @@ CanvasItemEditor::CanvasItemEditor() { select_button->set_pressed(true); select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), Key::Q)); select_button->set_shortcut_context(this); - select_button->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Alt+Drag: Scale selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("RMB: Add node at position clicked.")); + select_button->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Alt+Drag: Scale selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("RMB: Add node at position clicked.")); main_menu_hbox->add_child(memnew(VSeparator)); @@ -5115,7 +5115,7 @@ CanvasItemEditor::CanvasItemEditor() { move_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_MOVE)); move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), Key::W)); move_button->set_shortcut_context(this); - move_button->set_tooltip(TTR("Move Mode")); + move_button->set_tooltip_text(TTR("Move Mode")); rotate_button = memnew(Button); rotate_button->set_flat(true); @@ -5124,7 +5124,7 @@ CanvasItemEditor::CanvasItemEditor() { rotate_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_ROTATE)); rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), Key::E)); rotate_button->set_shortcut_context(this); - rotate_button->set_tooltip(TTR("Rotate Mode")); + rotate_button->set_tooltip_text(TTR("Rotate Mode")); scale_button = memnew(Button); scale_button->set_flat(true); @@ -5133,7 +5133,7 @@ CanvasItemEditor::CanvasItemEditor() { scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_SCALE)); scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), Key::S)); scale_button->set_shortcut_context(this); - scale_button->set_tooltip(TTR("Shift: Scale proportionally.")); + scale_button->set_tooltip_text(TTR("Shift: Scale proportionally.")); main_menu_hbox->add_child(memnew(VSeparator)); @@ -5142,14 +5142,14 @@ CanvasItemEditor::CanvasItemEditor() { main_menu_hbox->add_child(list_select_button); list_select_button->set_toggle_mode(true); list_select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_LIST_SELECT)); - list_select_button->set_tooltip(TTR("Show list of selectable nodes at position clicked.")); + list_select_button->set_tooltip_text(TTR("Show list of selectable nodes at position clicked.")); pivot_button = memnew(Button); pivot_button->set_flat(true); main_menu_hbox->add_child(pivot_button); pivot_button->set_toggle_mode(true); pivot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_EDIT_PIVOT)); - pivot_button->set_tooltip(TTR("Click to change object's rotation pivot.")); + pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot.")); pan_button = memnew(Button); pan_button->set_flat(true); @@ -5158,7 +5158,7 @@ CanvasItemEditor::CanvasItemEditor() { pan_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_PAN)); pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), Key::G)); pan_button->set_shortcut_context(this); - pan_button->set_tooltip(TTR("You can also use Pan View shortcut (Space by default) to pan in any mode.")); + pan_button->set_tooltip_text(TTR("You can also use Pan View shortcut (Space by default) to pan in any mode.")); ruler_button = memnew(Button); ruler_button->set_flat(true); @@ -5167,7 +5167,7 @@ CanvasItemEditor::CanvasItemEditor() { ruler_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_RULER)); ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), Key::R)); ruler_button->set_shortcut_context(this); - ruler_button->set_tooltip(TTR("Ruler Mode")); + ruler_button->set_tooltip_text(TTR("Ruler Mode")); main_menu_hbox->add_child(memnew(VSeparator)); @@ -5176,7 +5176,7 @@ CanvasItemEditor::CanvasItemEditor() { main_menu_hbox->add_child(smart_snap_button); smart_snap_button->set_toggle_mode(true); smart_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_smart_snap)); - smart_snap_button->set_tooltip(TTR("Toggle smart snapping.")); + smart_snap_button->set_tooltip_text(TTR("Toggle smart snapping.")); smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KeyModifierMask::SHIFT | Key::S)); smart_snap_button->set_shortcut_context(this); @@ -5185,7 +5185,7 @@ CanvasItemEditor::CanvasItemEditor() { main_menu_hbox->add_child(grid_snap_button); grid_snap_button->set_toggle_mode(true); grid_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_grid_snap)); - grid_snap_button->set_tooltip(TTR("Toggle grid snapping.")); + grid_snap_button->set_tooltip_text(TTR("Toggle grid snapping.")); grid_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_grid_snap", TTR("Use Grid Snap"), KeyModifierMask::SHIFT | Key::G)); grid_snap_button->set_shortcut_context(this); @@ -5193,7 +5193,7 @@ CanvasItemEditor::CanvasItemEditor() { snap_config_menu->set_shortcut_context(this); main_menu_hbox->add_child(snap_config_menu); snap_config_menu->set_h_size_flags(SIZE_SHRINK_END); - snap_config_menu->set_tooltip(TTR("Snapping Options")); + snap_config_menu->set_tooltip_text(TTR("Snapping Options")); snap_config_menu->set_switch_on_hover(true); PopupMenu *p = snap_config_menu->get_popup(); @@ -5227,7 +5227,7 @@ CanvasItemEditor::CanvasItemEditor() { main_menu_hbox->add_child(lock_button); lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(LOCK_SELECTED)); - lock_button->set_tooltip(TTR("Lock selected node, preventing selection and movement.")); + lock_button->set_tooltip_text(TTR("Lock selected node, preventing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD | Key::L)); @@ -5235,7 +5235,7 @@ CanvasItemEditor::CanvasItemEditor() { unlock_button->set_flat(true); main_menu_hbox->add_child(unlock_button); unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNLOCK_SELECTED)); - unlock_button->set_tooltip(TTR("Unlock selected node, allowing selection and movement.")); + unlock_button->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L)); @@ -5243,7 +5243,7 @@ CanvasItemEditor::CanvasItemEditor() { group_button->set_flat(true); main_menu_hbox->add_child(group_button); group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(GROUP_SELECTED)); - group_button->set_tooltip(TTR("Make selected node's children not selectable.")); + group_button->set_tooltip_text(TTR("Make selected node's children not selectable.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G)); @@ -5251,7 +5251,7 @@ CanvasItemEditor::CanvasItemEditor() { ungroup_button->set_flat(true); main_menu_hbox->add_child(ungroup_button); ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNGROUP_SELECTED)); - ungroup_button->set_tooltip(TTR("Make selected node's children selectable.")); + ungroup_button->set_tooltip_text(TTR("Make selected node's children selectable.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G)); @@ -5260,7 +5260,7 @@ CanvasItemEditor::CanvasItemEditor() { skeleton_menu = memnew(MenuButton); skeleton_menu->set_shortcut_context(this); main_menu_hbox->add_child(skeleton_menu); - skeleton_menu->set_tooltip(TTR("Skeleton Options")); + skeleton_menu->set_tooltip_text(TTR("Skeleton Options")); skeleton_menu->set_switch_on_hover(true); p = skeleton_menu->get_popup(); @@ -5340,7 +5340,7 @@ CanvasItemEditor::CanvasItemEditor() { key_loc_button->set_pressed(true); key_loc_button->set_focus_mode(FOCUS_NONE); key_loc_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_POS)); - key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); + key_loc_button->set_tooltip_text(TTR("Translation mask for inserting keys.")); animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button); @@ -5349,7 +5349,7 @@ CanvasItemEditor::CanvasItemEditor() { key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); key_rot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_ROT)); - key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); + key_rot_button->set_tooltip_text(TTR("Rotation mask for inserting keys.")); animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button); @@ -5357,14 +5357,14 @@ CanvasItemEditor::CanvasItemEditor() { key_scale_button->set_toggle_mode(true); key_scale_button->set_focus_mode(FOCUS_NONE); key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_SCALE)); - key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); + key_scale_button->set_tooltip_text(TTR("Scale mask for inserting keys.")); animation_hb->add_child(key_scale_button); key_insert_button = memnew(Button); key_insert_button->set_flat(true); key_insert_button->set_focus_mode(FOCUS_NONE); key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_KEY)); - key_insert_button->set_tooltip(TTR("Insert keys (based on mask).")); + key_insert_button->set_tooltip_text(TTR("Insert keys (based on mask).")); key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), Key::INSERT)); key_insert_button->set_shortcut_context(this); animation_hb->add_child(key_insert_button); @@ -5373,14 +5373,14 @@ CanvasItemEditor::CanvasItemEditor() { key_auto_insert_button->set_flat(true); key_auto_insert_button->set_toggle_mode(true); key_auto_insert_button->set_focus_mode(FOCUS_NONE); - key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time.")); + key_auto_insert_button->set_tooltip_text(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time.")); key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key"))); key_auto_insert_button->set_shortcut_context(this); animation_hb->add_child(key_auto_insert_button); animation_menu = memnew(MenuButton); animation_menu->set_shortcut_context(this); - animation_menu->set_tooltip(TTR("Animation Key and Pose Options")); + animation_menu->set_tooltip_text(TTR("Animation Key and Pose Options")); animation_hb->add_child(animation_menu); animation_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); animation_menu->set_switch_on_hover(true); diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index 2a12dc0e89..bb6092755e 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -69,14 +69,14 @@ void ControlPositioningWarning::_update_toggler() { Ref<Texture2D> arrow; if (hint_label->is_visible()) { arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree")); - set_tooltip(TTR("Collapse positioning hint.")); + set_tooltip_text(TTR("Collapse positioning hint.")); } else { if (is_layout_rtl()) { arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree")); } else { arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree")); } - set_tooltip(TTR("Expand positioning hint.")); + set_tooltip_text(TTR("Expand positioning hint.")); } hint_icon->set_texture(arrow); @@ -523,7 +523,7 @@ ControlEditorPopupButton::ControlEditorPopupButton() { set_focus_mode(FOCUS_NONE); popup_panel = memnew(PopupPanel); - popup_panel->set_theme_type_variation("ControlEditorPopupButton"); + 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)); @@ -538,7 +538,7 @@ void ControlEditorPresetPicker::_add_row_button(HBoxContainer *p_row, const int Button *b = memnew(Button); b->set_custom_minimum_size(Size2i(36, 36) * EDSCALE); b->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER); - b->set_tooltip(p_name); + b->set_tooltip_text(p_name); b->set_flat(true); p_row->add_child(b); b->connect("pressed", callable_mp(this, &ControlEditorPresetPicker::_preset_button_pressed).bind(p_preset)); @@ -658,10 +658,10 @@ void SizeFlagPresetPicker::set_allowed_flags(Vector<SizeFlags> &p_flags) { expand_button->set_disabled(!p_flags.has(SIZE_EXPAND)); if (p_flags.has(SIZE_EXPAND)) { - expand_button->set_tooltip(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags.")); + expand_button->set_tooltip_text(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags.")); } else { expand_button->set_pressed(false); - expand_button->set_tooltip(TTR("Some parents of the selected nodes do not support the Expand flag.")); + expand_button->set_tooltip_text(TTR("Some parents of the selected nodes do not support the Expand flag.")); } } @@ -710,7 +710,7 @@ SizeFlagPresetPicker::SizeFlagPresetPicker(bool p_vertical) { expand_button = memnew(CheckBox); expand_button->set_flat(true); expand_button->set_text(TTR("Align with Expand")); - expand_button->set_tooltip(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags.")); + expand_button->set_tooltip_text(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags.")); main_vb->add_child(expand_button); } @@ -988,7 +988,7 @@ ControlEditorToolbar::ControlEditorToolbar() { // Anchor and offset tools. anchors_button = memnew(ControlEditorPopupButton); - anchors_button->set_tooltip(TTR("Presets for the anchor and offset values of a Control node.")); + anchors_button->set_tooltip_text(TTR("Presets for the anchor and offset values of a Control node.")); add_child(anchors_button); Label *anchors_label = memnew(Label); @@ -1004,20 +1004,20 @@ ControlEditorToolbar::ControlEditorToolbar() { Button *keep_ratio_button = memnew(Button); keep_ratio_button->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); keep_ratio_button->set_text(TTR("Set to Current Ratio")); - keep_ratio_button->set_tooltip(TTR("Adjust anchors and offsets to match the current rect size.")); + keep_ratio_button->set_tooltip_text(TTR("Adjust anchors and offsets to match the current rect size.")); anchors_button->get_popup_hbox()->add_child(keep_ratio_button); keep_ratio_button->connect("pressed", callable_mp(this, &ControlEditorToolbar::_anchors_to_current_ratio)); anchor_mode_button = memnew(Button); anchor_mode_button->set_flat(true); anchor_mode_button->set_toggle_mode(true); - anchor_mode_button->set_tooltip(TTR("When active, moving Control nodes changes their anchors instead of their offsets.")); + anchor_mode_button->set_tooltip_text(TTR("When active, moving Control nodes changes their anchors instead of their offsets.")); add_child(anchor_mode_button); anchor_mode_button->connect("toggled", callable_mp(this, &ControlEditorToolbar::_anchor_mode_toggled)); // Container tools. containers_button = memnew(ControlEditorPopupButton); - containers_button->set_tooltip(TTR("Sizing settings for children of a Container node.")); + containers_button->set_tooltip_text(TTR("Sizing settings for children of a Container node.")); add_child(containers_button); Label *container_h_label = memnew(Label); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 013a9f10a4..0e84381279 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -87,7 +87,7 @@ void CurveEditor::set_curve(Ref<Curve> curve) { _hover_point = -1; _selected_tangent = TANGENT_NONE; - update(); + queue_redraw(); // Note: if you edit a curve, then set another, and try to undo, // it will normally apply on the previous curve, but you won't see it @@ -311,7 +311,7 @@ void CurveEditor::on_preset_item_selected(int preset_id) { } void CurveEditor::_curve_changed() { - update(); + queue_redraw(); // Point count can change in case of undo if (_selected_point >= _curve_ref->get_point_count()) { set_selected_point(-1); @@ -512,14 +512,14 @@ void CurveEditor::toggle_linear(TangentIndex tangent) { void CurveEditor::set_selected_point(int index) { if (index != _selected_point) { _selected_point = index; - update(); + queue_redraw(); } } void CurveEditor::set_hover_point_index(int index) { if (index != _hover_point) { _hover_point = index; - update(); + queue_redraw(); } } @@ -579,7 +579,7 @@ template <typename T> static void plot_curve_accurate(const Curve &curve, float step, T plot_func) { if (curve.get_point_count() <= 1) { // Not enough points to make a curve, so it's just a straight line - float y = curve.interpolate(0); + float y = curve.sample(0); plot_func(Vector2(0, y), Vector2(1.f, y), true); } else { @@ -603,7 +603,7 @@ static void plot_curve_accurate(const Curve &curve, float step, T plot_func) { for (float x = step; x < len; x += step) { pos.x = a.x + x; - pos.y = curve.interpolate_local_nocheck(i - 1, x); + pos.y = curve.sample_local_nocheck(i - 1, x); plot_func(prev_pos, pos, true); prev_pos = pos; } @@ -817,7 +817,7 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons int prev_y = 0; for (int x = 0; x < im.get_width(); ++x) { float t = static_cast<float>(x) / im.get_width(); - float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y; + float v = (curve.sample_baked(t) - curve.get_min_value()) / range_y; int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height()); // Plot point diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 0196214ceb..369ab0745e 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -255,7 +255,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const Ref<Resource> &p_f Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const { String temp_path = EditorPaths::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text(); - cache_base = temp_path.plus_file("resthumb-" + cache_base); + cache_base = temp_path.path_join("resthumb-" + cache_base); //does not have it, try to load a cached thumbnail @@ -342,6 +342,12 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { RS::get_singleton()->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 0, 3))); RS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + camera_attributes = RS::get_singleton()->camera_attributes_create(); + RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, 1.0, 0.000032552); // Matches default CameraAttributesPhysical to work well with default DirectionalLight3Ds. + RS::get_singleton()->camera_set_camera_attributes(camera, camera_attributes); + } + light = RS::get_singleton()->directional_light_create(); light_instance = RS::get_singleton()->instance_create2(light, scenario); RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); @@ -440,6 +446,7 @@ EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() { RS::get_singleton()->free(light2); RS::get_singleton()->free(light_instance2); RS::get_singleton()->free(camera); + RS::get_singleton()->free(camera_attributes); RS::get_singleton()->free(scenario); } @@ -743,6 +750,12 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() { //RS::get_singleton()->camera_set_perspective(camera,45,0.1,10); RS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + camera_attributes = RS::get_singleton()->camera_attributes_create(); + RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, 1.0, 0.000032552); // Matches default CameraAttributesPhysical to work well with default DirectionalLight3Ds. + RS::get_singleton()->camera_set_camera_attributes(camera, camera_attributes); + } + light = RS::get_singleton()->directional_light_create(); light_instance = RS::get_singleton()->instance_create2(light, scenario); RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); @@ -768,6 +781,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() { RS::get_singleton()->free(light2); RS::get_singleton()->free(light_instance2); RS::get_singleton()->free(camera); + RS::get_singleton()->free(camera_attributes); RS::get_singleton()->free(scenario); } diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index 163cfe79f9..efb2c80cfd 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -91,6 +91,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; + RID camera_attributes; Semaphore preview_done; void _generate_frame_started(); @@ -133,6 +134,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; + RID camera_attributes; Semaphore preview_done; void _generate_frame_started(); diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index c7d3e92802..2df951518e 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -290,7 +290,7 @@ void EditorPropertyFontMetaOverride::update_property() { } else { prop->set_label(TranslationServer::get_singleton()->get_locale_name(name)); } - prop->set_tooltip(name); + prop->set_tooltip_text(name); prop->set_selectable(false); prop->connect("property_changed", callable_mp(this, &EditorPropertyFontMetaOverride::_property_changed)); @@ -487,7 +487,7 @@ void EditorPropertyOTVariation::update_property() { String name = TS->tag_to_name(name_tag); prop->set_label(name.capitalize()); - prop->set_tooltip(name); + prop->set_tooltip_text(name); prop->set_selectable(false); prop->connect("property_changed", callable_mp(this, &EditorPropertyOTVariation::_property_changed)); @@ -766,7 +766,7 @@ void EditorPropertyOTFeatures::update_property() { disp_name = vformat("%s (%s)", disp_name, info["label"].operator String()); } prop->set_label(disp_name); - prop->set_tooltip(name); + prop->set_tooltip_text(name); prop->set_selectable(false); prop->connect("property_changed", callable_mp(this, &EditorPropertyOTFeatures::_property_changed)); @@ -942,7 +942,7 @@ Size2 FontPreview::get_minimum_size() const { void FontPreview::set_data(const Ref<Font> &p_f) { prev_font = p_f; - update(); + queue_redraw(); } FontPreview::FontPreview() { diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h index b5eca46ad3..e1d68d97b5 100644 --- a/editor/plugins/gdextension_export_plugin.h +++ b/editor/plugins/gdextension_export_plugin.h @@ -36,6 +36,7 @@ class GDExtensionExportPlugin : public EditorExportPlugin { protected: virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features); + virtual String _get_name() const { return "GDExtension"; } }; void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) { diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp index b54cb515e4..59d665342f 100644 --- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp @@ -101,7 +101,7 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_notification(int p_what) { return; } - bake->set_tooltip(text); + bake->set_tooltip_text(text); } break; } } diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp new file mode 100644 index 0000000000..c13b162db6 --- /dev/null +++ b/editor/plugins/gradient_editor.cpp @@ -0,0 +1,492 @@ +/*************************************************************************/ +/* gradient_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gradient_editor.h" + +#include "core/os/keyboard.h" +#include "editor/editor_node.h" +#include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" + +void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) { + gradient = p_gradient; + connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed)); + gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed)); + set_points(gradient->get_points()); + set_interpolation_mode(gradient->get_interpolation_mode()); +} + +void GradientEditor::reverse_gradient() { + gradient->reverse(); + set_points(gradient->get_points()); + emit_signal(SNAME("ramp_changed")); + queue_redraw(); +} + +int GradientEditor::_get_point_from_pos(int x) { + int result = -1; + int total_w = get_size().width - get_size().height - draw_spacing; + float min_distance = 1e20; + for (int i = 0; i < points.size(); i++) { + // Check if we clicked at point. + float distance = ABS(x - points[i].offset * total_w); + float min = (draw_point_width / 2 * 1.7); //make it easier to grab + if (distance <= min && distance < min_distance) { + result = i; + min_distance = distance; + } + } + return result; +} + +void GradientEditor::_show_color_picker() { + if (grabbed == -1) { + return; + } + picker->set_pick_color(points[grabbed].color); + Size2 minsize = popup->get_contents_minimum_size(); + bool show_above = false; + if (get_global_position().y + get_size().y + minsize.y > get_viewport_rect().size.y) { + show_above = true; + } + if (show_above) { + popup->set_position(get_screen_position() - Vector2(0, minsize.y)); + } else { + popup->set_position(get_screen_position() + Vector2(0, get_size().y)); + } + popup->popup(); +} + +void GradientEditor::_gradient_changed() { + if (editing) { + return; + } + + editing = true; + Vector<Gradient::Point> points = gradient->get_points(); + set_points(points); + set_interpolation_mode(gradient->get_interpolation_mode()); + queue_redraw(); + editing = false; +} + +void GradientEditor::_ramp_changed() { + editing = true; + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); + undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS); + undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets()); + undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors()); + undo_redo->add_do_method(gradient.ptr(), "set_interpolation_mode", get_interpolation_mode()); + undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets()); + undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors()); + undo_redo->add_undo_method(gradient.ptr(), "set_interpolation_mode", gradient->get_interpolation_mode()); + undo_redo->commit_action(); + editing = false; +} + +void GradientEditor::_color_changed(const Color &p_color) { + if (grabbed == -1) { + return; + } + points.write[grabbed].color = p_color; + queue_redraw(); + emit_signal(SNAME("ramp_changed")); +} + +void GradientEditor::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) { + ERR_FAIL_COND(p_offsets.size() != p_colors.size()); + points.clear(); + for (int i = 0; i < p_offsets.size(); i++) { + Gradient::Point p; + p.offset = p_offsets[i]; + p.color = p_colors[i]; + points.push_back(p); + } + + points.sort(); + queue_redraw(); +} + +Vector<float> GradientEditor::get_offsets() const { + Vector<float> ret; + for (int i = 0; i < points.size(); i++) { + ret.push_back(points[i].offset); + } + return ret; +} + +Vector<Color> GradientEditor::get_colors() const { + Vector<Color> ret; + for (int i = 0; i < points.size(); i++) { + ret.push_back(points[i].color); + } + return ret; +} + +void GradientEditor::set_points(Vector<Gradient::Point> &p_points) { + if (points.size() != p_points.size()) { + grabbed = -1; + } + points.clear(); + points = p_points; + points.sort(); +} + +Vector<Gradient::Point> &GradientEditor::get_points() { + return points; +} + +void GradientEditor::set_interpolation_mode(Gradient::InterpolationMode p_interp_mode) { + interpolation_mode = p_interp_mode; +} + +Gradient::InterpolationMode GradientEditor::get_interpolation_mode() { + return interpolation_mode; +} + +ColorPicker *GradientEditor::get_picker() { + return picker; +} + +PopupPanel *GradientEditor::get_popup() { + return popup; +} + +Size2 GradientEditor::get_minimum_size() const { + return Size2(0, 60) * EDSCALE; +} + +void GradientEditor::gui_input(const Ref<InputEvent> &p_event) { + ERR_FAIL_COND(p_event.is_null()); + + Ref<InputEventKey> k = p_event; + + if (k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && grabbed != -1) { + points.remove_at(grabbed); + grabbed = -1; + grabbing = false; + queue_redraw(); + emit_signal(SNAME("ramp_changed")); + accept_event(); + } + + Ref<InputEventMouseButton> mb = p_event; + // Show color picker on double click. + if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) { + grabbed = _get_point_from_pos(mb->get_position().x); + _show_color_picker(); + accept_event(); + } + + // Delete point on right click. + if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { + grabbed = _get_point_from_pos(mb->get_position().x); + if (grabbed != -1) { + points.remove_at(grabbed); + grabbed = -1; + grabbing = false; + queue_redraw(); + emit_signal(SNAME("ramp_changed")); + accept_event(); + } + } + + // Hold alt key to duplicate selected color. + if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed() && mb->is_alt_pressed()) { + int x = mb->get_position().x; + grabbed = _get_point_from_pos(x); + + if (grabbed != -1) { + int total_w = get_size().width - get_size().height - draw_spacing; + Gradient::Point new_point = points[grabbed]; + new_point.offset = CLAMP(x / float(total_w), 0, 1); + + points.push_back(new_point); + points.sort(); + for (int i = 0; i < points.size(); ++i) { + if (points[i].offset == new_point.offset) { + grabbed = i; + break; + } + } + + emit_signal(SNAME("ramp_changed")); + queue_redraw(); + } + } + + // Select. + if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { + queue_redraw(); + int x = mb->get_position().x; + int total_w = get_size().width - get_size().height - draw_spacing; + + //Check if color selector was clicked. + if (x > total_w + draw_spacing) { + _show_color_picker(); + return; + } + + grabbing = true; + + grabbed = _get_point_from_pos(x); + //grab or select + if (grabbed != -1) { + return; + } + + // Insert point. + Gradient::Point new_point; + new_point.offset = CLAMP(x / float(total_w), 0, 1); + + Gradient::Point prev; + Gradient::Point next; + + int pos = -1; + for (int i = 0; i < points.size(); i++) { + if (points[i].offset < new_point.offset) { + pos = i; + } + } + + if (pos == -1) { + prev.color = Color(0, 0, 0); + prev.offset = 0; + if (points.size()) { + next = points[0]; + } else { + next.color = Color(1, 1, 1); + next.offset = 1.0; + } + } else { + if (pos == points.size() - 1) { + next.color = Color(1, 1, 1); + next.offset = 1.0; + } else { + next = points[pos + 1]; + } + prev = points[pos]; + } + + new_point.color = prev.color.lerp(next.color, (new_point.offset - prev.offset) / (next.offset - prev.offset)); + + points.push_back(new_point); + points.sort(); + for (int i = 0; i < points.size(); i++) { + if (points[i].offset == new_point.offset) { + grabbed = i; + break; + } + } + + emit_signal(SNAME("ramp_changed")); + } + + if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) { + if (grabbing) { + grabbing = false; + emit_signal(SNAME("ramp_changed")); + } + queue_redraw(); + } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid() && grabbing) { + int total_w = get_size().width - get_size().height - draw_spacing; + + int x = mm->get_position().x; + + float newofs = CLAMP(x / float(total_w), 0, 1); + + // Snap to "round" coordinates if holding Ctrl. + // Be more precise if holding Shift as well. + if (mm->is_ctrl_pressed()) { + newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1); + } else if (mm->is_shift_pressed()) { + // Snap to nearest point if holding just Shift + const float snap_threshold = 0.03; + float smallest_ofs = snap_threshold; + bool found = false; + int nearest_point = 0; + for (int i = 0; i < points.size(); ++i) { + if (i != grabbed) { + float temp_ofs = ABS(points[i].offset - newofs); + if (temp_ofs < smallest_ofs) { + smallest_ofs = temp_ofs; + nearest_point = i; + if (found) { + break; + } + found = true; + } + } + } + if (found) { + if (points[nearest_point].offset < newofs) { + newofs = points[nearest_point].offset + 0.00001; + } else { + newofs = points[nearest_point].offset - 0.00001; + } + newofs = CLAMP(newofs, 0, 1); + } + } + + bool valid = true; + for (int i = 0; i < points.size(); i++) { + if (points[i].offset == newofs && i != grabbed) { + valid = false; + break; + } + } + + if (!valid || grabbed == -1) { + return; + } + points.write[grabbed].offset = newofs; + + points.sort(); + for (int i = 0; i < points.size(); i++) { + if (points[i].offset == newofs) { + grabbed = i; + break; + } + } + + emit_signal(SNAME("ramp_changed")); + + queue_redraw(); + } +} + +void GradientEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (!picker->is_connected("color_changed", callable_mp(this, &GradientEditor::_color_changed))) { + picker->connect("color_changed", callable_mp(this, &GradientEditor::_color_changed)); + } + [[fallthrough]]; + } + case NOTIFICATION_THEME_CHANGED: { + draw_spacing = BASE_SPACING * get_theme_default_base_scale(); + draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale(); + } break; + + case NOTIFICATION_DRAW: { + int w = get_size().x; + int h = get_size().y; + + if (w == 0 || h == 0) { + return; // Safety check. We have division by 'h'. And in any case there is nothing to draw with such size. + } + + int total_w = get_size().width - get_size().height - draw_spacing; + + // Draw checker pattern for ramp. + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true); + + // Draw color ramp. + gradient_cache->set_points(points); + gradient_cache->set_interpolation_mode(interpolation_mode); + preview_texture->set_gradient(gradient_cache); + draw_texture_rect(preview_texture, Rect2(0, 0, total_w, h)); + + // Draw point markers. + for (int i = 0; i < points.size(); i++) { + Color col = points[i].color.inverted(); + col.a = 0.9; + + draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col); + Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2); + draw_rect(rect, points[i].color, true); + draw_rect(rect, col, false); + if (grabbed == i) { + rect = rect.grow(-1); + if (has_focus()) { + draw_rect(rect, Color(1, 0, 0, 0.9), false); + } else { + draw_rect(rect, Color(0.6, 0, 0, 0.9), false); + } + + rect = rect.grow(-1); + draw_rect(rect, col, false); + } + } + + // Draw "button" for color selector. + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true); + if (grabbed != -1) { + // Draw with selection color. + draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color); + } else { + // If no color selected draw grey color with 'X' on top. + draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1)); + draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6)); + draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6)); + } + + // Draw borders around color ramp if in focus. + if (has_focus()) { + draw_line(Vector2(-1, -1), Vector2(total_w + 1, -1), Color(1, 1, 1, 0.6)); + draw_line(Vector2(total_w + 1, -1), Vector2(total_w + 1, h + 1), Color(1, 1, 1, 0.6)); + draw_line(Vector2(total_w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); + draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); + } + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible()) { + grabbing = false; + } + } break; + } +} + +void GradientEditor::_bind_methods() { + ADD_SIGNAL(MethodInfo("ramp_changed")); +} + +GradientEditor::GradientEditor() { + set_focus_mode(FOCUS_ALL); + + popup = memnew(PopupPanel); + picker = memnew(ColorPicker); + popup->add_child(picker); + popup->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(GradientEditor::get_picker())); + + gradient_cache.instantiate(); + preview_texture.instantiate(); + + preview_texture->set_width(1024); + add_child(popup, false, INTERNAL_MODE_FRONT); +} + +GradientEditor::~GradientEditor() { +} diff --git a/editor/plugins/gradient_editor.h b/editor/plugins/gradient_editor.h new file mode 100644 index 0000000000..816b539ba2 --- /dev/null +++ b/editor/plugins/gradient_editor.h @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* gradient_editor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GRADIENT_EDITOR_H +#define GRADIENT_EDITOR_H + +#include "scene/gui/color_picker.h" +#include "scene/gui/popup.h" +#include "scene/resources/gradient.h" + +class GradientEditor : public Control { + GDCLASS(GradientEditor, Control); + + PopupPanel *popup = nullptr; + ColorPicker *picker = nullptr; + + bool grabbing = false; + int grabbed = -1; + Vector<Gradient::Point> points; + Gradient::InterpolationMode interpolation_mode = Gradient::GRADIENT_INTERPOLATE_LINEAR; + + bool editing = false; + Ref<Gradient> gradient; + Ref<Gradient> gradient_cache; + Ref<GradientTexture1D> preview_texture; + + // Make sure to use the scaled value below. + const int BASE_SPACING = 3; + const int BASE_POINT_WIDTH = 8; + + int draw_spacing = BASE_SPACING; + int draw_point_width = BASE_POINT_WIDTH; + + void _gradient_changed(); + void _ramp_changed(); + void _color_changed(const Color &p_color); + + int _get_point_from_pos(int x); + void _show_color_picker(); + +protected: + virtual void gui_input(const Ref<InputEvent> &p_event) override; + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_gradient(const Ref<Gradient> &p_gradient); + void reverse_gradient(); + + void set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors); + + Vector<float> get_offsets() const; + Vector<Color> get_colors() const; + void set_points(Vector<Gradient::Point> &p_points); + Vector<Gradient::Point> &get_points(); + + void set_interpolation_mode(Gradient::InterpolationMode p_interp_mode); + Gradient::InterpolationMode get_interpolation_mode(); + + ColorPicker *get_picker(); + PopupPanel *get_popup(); + + virtual Size2 get_minimum_size() const override; + + GradientEditor(); + virtual ~GradientEditor(); +}; + +#endif // GRADIENT_EDITOR_H diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 460178490e..0f412aaefd 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -37,62 +37,6 @@ #include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" -Size2 GradientEditor::get_minimum_size() const { - return Size2(0, 60) * EDSCALE; -} - -void GradientEditor::_gradient_changed() { - if (editing) { - return; - } - - editing = true; - Vector<Gradient::Point> points = gradient->get_points(); - set_points(points); - set_interpolation_mode(gradient->get_interpolation_mode()); - update(); - editing = false; -} - -void GradientEditor::_ramp_changed() { - editing = true; - Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS); - undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets()); - undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors()); - undo_redo->add_do_method(gradient.ptr(), "set_interpolation_mode", get_interpolation_mode()); - undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets()); - undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors()); - undo_redo->add_undo_method(gradient.ptr(), "set_interpolation_mode", gradient->get_interpolation_mode()); - undo_redo->commit_action(); - editing = false; -} - -void GradientEditor::_bind_methods() { -} - -void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) { - gradient = p_gradient; - connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed)); - gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed)); - set_points(gradient->get_points()); - set_interpolation_mode(gradient->get_interpolation_mode()); -} - -void GradientEditor::reverse_gradient() { - gradient->reverse(); - set_points(gradient->get_points()); - emit_signal(SNAME("ramp_changed")); - update(); -} - -GradientEditor::GradientEditor() { - GradientEdit::get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(GradientEdit::get_picker())); - editing = false; -} - -/////////////////////// - void GradientReverseButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { @@ -135,7 +79,7 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) { add_custom_control(gradient_tools_hbox); reverse_btn->connect("pressed", callable_mp(this, &EditorInspectorPluginGradient::_reverse_button_pressed)); - reverse_btn->set_tooltip(TTR("Reverse/mirror gradient.")); + reverse_btn->set_tooltip_text(TTR("Reverse/mirror gradient.")); } void EditorInspectorPluginGradient::_reverse_button_pressed() { diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h index 26bf76fecd..ab191d83e2 100644 --- a/editor/plugins/gradient_editor_plugin.h +++ b/editor/plugins/gradient_editor_plugin.h @@ -32,26 +32,7 @@ #define GRADIENT_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/gui/gradient_edit.h" - -class GradientEditor : public GradientEdit { - GDCLASS(GradientEditor, GradientEdit); - - bool editing; - Ref<Gradient> gradient; - - void _gradient_changed(); - void _ramp_changed(); - -protected: - static void _bind_methods(); - -public: - virtual Size2 get_minimum_size() const override; - void set_gradient(const Ref<Gradient> &p_gradient); - void reverse_gradient(); - GradientEditor(); -}; +#include "gradient_editor.h" class GradientReverseButton : public BaseButton { GDCLASS(GradientReverseButton, BaseButton); diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp index 6c463f71cf..dc01a52bb3 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp +++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp @@ -89,17 +89,17 @@ void GradientTexture2DEditorRect::gui_input(const Ref<InputEvent> &p_event) { void GradientTexture2DEditorRect::set_texture(Ref<GradientTexture2D> &p_texture) { texture = p_texture; - texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); + texture->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); } void GradientTexture2DEditorRect::set_snap_enabled(bool p_snap_enabled) { snap_enabled = p_snap_enabled; - update(); + queue_redraw(); } void GradientTexture2DEditorRect::set_snap_size(float p_snap_size) { snap_size = p_snap_size; - update(); + queue_redraw(); } void GradientTexture2DEditorRect::_notification(int p_what) { @@ -229,14 +229,14 @@ GradientTexture2DEditor::GradientTexture2DEditor() { add_child(toolbar); reverse_button = memnew(Button); - reverse_button->set_tooltip(TTR("Swap Gradient Fill Points")); + reverse_button->set_tooltip_text(TTR("Swap Gradient Fill Points")); toolbar->add_child(reverse_button); reverse_button->connect("pressed", callable_mp(this, &GradientTexture2DEditor::_reverse_button_pressed)); toolbar->add_child(memnew(VSeparator)); snap_button = memnew(Button); - snap_button->set_tooltip(TTR("Toggle Grid Snap")); + snap_button->set_tooltip_text(TTR("Toggle Grid Snap")); snap_button->set_toggle_mode(true); toolbar->add_child(snap_button); snap_button->connect("toggled", callable_mp(this, &GradientTexture2DEditor::_set_snap_enabled)); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 74a6e90a6d..d204873f92 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -30,6 +30,7 @@ #include "material_editor_plugin.h" +#include "core/config/project_settings.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -153,7 +154,7 @@ MaterialEditor::MaterialEditor() { vc->add_child(viewport); viewport->set_disable_input(true); viewport->set_transparent_background(true); - viewport->set_msaa(Viewport::MSAA_4X); + viewport->set_msaa_3d(Viewport::MSAA_4X); camera = memnew(Camera3D); camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 3))); @@ -161,6 +162,10 @@ MaterialEditor::MaterialEditor() { // without much distortion. camera->set_perspective(20, 0.1, 10); camera->make_current(); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + camera_attributes.instantiate(); + camera->set_attributes(camera_attributes); + } viewport->add_child(camera); light1 = memnew(DirectionalLight3D); diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 06ae43e6d7..828dd9f972 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -55,6 +55,7 @@ class MaterialEditor : public Control { DirectionalLight3D *light1 = nullptr; DirectionalLight3D *light2 = nullptr; Camera3D *camera = nullptr; + Ref<CameraAttributesPractical> camera_attributes; Ref<SphereMesh> sphere_mesh; Ref<BoxMesh> box_mesh; diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 980d2974a0..d8977ea6fc 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -30,6 +30,7 @@ #include "mesh_editor_plugin.h" +#include "core/config/project_settings.h" #include "editor/editor_scale.h" void MeshEditor::gui_input(const Ref<InputEvent> &p_event) { @@ -112,13 +113,18 @@ MeshEditor::MeshEditor() { viewport->set_world_3d(world_3d); //use own world add_child(viewport); viewport->set_disable_input(true); - viewport->set_msaa(Viewport::MSAA_4X); + viewport->set_msaa_3d(Viewport::MSAA_4X); set_stretch(true); camera = memnew(Camera3D); camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1))); camera->set_perspective(45, 0.1, 10); viewport->add_child(camera); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + camera_attributes.instantiate(); + camera->set_attributes(camera_attributes); + } + light1 = memnew(DirectionalLight3D); light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); viewport->add_child(light1); diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h index fb61f03485..ab7b5db7c4 100644 --- a/editor/plugins/mesh_editor_plugin.h +++ b/editor/plugins/mesh_editor_plugin.h @@ -36,6 +36,7 @@ #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/gui/subviewport_container.h" +#include "scene/resources/camera_attributes.h" #include "scene/resources/material.h" class MeshEditor : public SubViewportContainer { @@ -50,6 +51,7 @@ class MeshEditor : public SubViewportContainer { DirectionalLight3D *light1 = nullptr; DirectionalLight3D *light2 = nullptr; Camera3D *camera = nullptr; + Ref<CameraAttributesPractical> camera_attributes; Ref<Mesh> mesh; diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 121796e5e8..ec6ea7f39b 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -1366,7 +1366,8 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node()); - Color color = light->get_color(); + Color color = light->get_color().srgb_to_linear() * light->get_correlated_color().srgb_to_linear(); + color = color.linear_to_srgb(); // Make the gizmo color as bright as possible for better visibility color.set_hsv(color.get_h(), color.get_s(), 1); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index a9431537f8..0bb044e679 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -99,7 +99,7 @@ void ViewportRotationControl::_notification(int p_what) { axis_colors.push_back(get_theme_color(SNAME("axis_x_color"), SNAME("Editor"))); axis_colors.push_back(get_theme_color(SNAME("axis_y_color"), SNAME("Editor"))); axis_colors.push_back(get_theme_color(SNAME("axis_z_color"), SNAME("Editor"))); - update(); + queue_redraw(); if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) { connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited)); @@ -247,13 +247,13 @@ void ViewportRotationControl::_update_focus() { } if (focused_axis != original_focus) { - update(); + queue_redraw(); } } void ViewportRotationControl::_on_mouse_exited() { focused_axis = -2; - update(); + queue_redraw(); } void ViewportRotationControl::set_viewport(Node3DEditorViewport *p_viewport) { @@ -350,7 +350,7 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) { } update_transform_gizmo_view(); - rotation_control->update(); + rotation_control->queue_redraw(); spatial_editor->update_grid(); } } @@ -1614,7 +1614,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } - surface->update(); + surface->queue_redraw(); } else { if (_edit.gizmo.is_valid()) { _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, false); @@ -1632,7 +1632,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (cursor.region_select) { _select_region(); cursor.region_select = false; - surface->update(); + surface->queue_redraw(); } } @@ -1657,7 +1657,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { _edit.mode = TRANSFORM_NONE; set_message(""); } - surface->update(); + surface->queue_redraw(); } } break; @@ -1741,7 +1741,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (cursor.region_select) { cursor.region_end = m->get_position(); - surface->update(); + surface->queue_redraw(); return; } @@ -2244,12 +2244,12 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) { void Node3DEditorViewport::scale_fov(real_t p_fov_offset) { cursor.fov_scale = CLAMP(cursor.fov_scale + p_fov_offset, 0.1, 2.5); - surface->update(); + surface->queue_redraw(); } void Node3DEditorViewport::reset_fov() { cursor.fov_scale = 1.0; - surface->update(); + surface->queue_redraw(); } void Node3DEditorViewport::scale_cursor_distance(real_t scale) { @@ -2268,7 +2268,7 @@ void Node3DEditorViewport::scale_cursor_distance(real_t scale) { } zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S; - surface->update(); + surface->queue_redraw(); } void Node3DEditorViewport::scale_freelook_speed(real_t scale) { @@ -2281,7 +2281,7 @@ void Node3DEditorViewport::scale_freelook_speed(real_t scale) { } zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S; - surface->update(); + surface->queue_redraw(); } Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const { @@ -2375,12 +2375,12 @@ void Node3DEditorPlugin::edited_scene_changed() { void Node3DEditorViewport::_project_settings_changed() { //update shadow atlas if changed - int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_size"); - bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_16_bits"); - int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv"); - int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv"); - int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv"); - int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv"); + int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_size"); + bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_16_bits"); + int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv"); + int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv"); + int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv"); + int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv"); viewport->set_positional_shadow_atlas_size(shadowmap_size); viewport->set_positional_shadow_atlas_16_bits(shadowmap_16_bits); @@ -2393,8 +2393,8 @@ void Node3DEditorViewport::_project_settings_changed() { // Update MSAA, screen-space AA and debanding if changed - const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa"); - viewport->set_msaa(Viewport::MSAA(msaa_mode)); + const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa_3d"); + viewport->set_msaa_3d(Viewport::MSAA(msaa_mode)); const int ssaa_mode = GLOBAL_GET("rendering/anti_aliasing/quality/screen_space_aa"); viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); const bool use_taa = GLOBAL_GET("rendering/anti_aliasing/quality/use_taa"); @@ -2454,7 +2454,7 @@ void Node3DEditorViewport::_notification(int p_what) { if (zoom_indicator_delay > 0) { zoom_indicator_delay -= delta; if (zoom_indicator_delay <= 0) { - surface->update(); + surface->queue_redraw(); zoom_limit_label->hide(); } } @@ -2472,7 +2472,7 @@ void Node3DEditorViewport::_notification(int p_what) { previewing = cam; previewing->connect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera()); - surface->update(); + surface->queue_redraw(); } } @@ -2538,13 +2538,13 @@ void Node3DEditorViewport::_notification(int p_what) { if (message_time > 0) { if (message != last_message) { - surface->update(); + surface->queue_redraw(); last_message = message; } message_time -= get_physics_process_delta_time(); if (message_time < 0) { - surface->update(); + surface->queue_redraw(); } } @@ -3356,13 +3356,13 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) { if (!preview) { preview_camera->hide(); } - surface->update(); + surface->queue_redraw(); } else { previewing = preview; previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace - surface->update(); + surface->queue_redraw(); } } @@ -3384,7 +3384,7 @@ void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) { preview_camera->show(); } view_menu->show(); - surface->update(); + surface->queue_redraw(); } } @@ -3619,7 +3619,7 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { previewing = Object::cast_to<Camera3D>(pv); previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace - surface->update(); + surface->queue_redraw(); preview_camera->set_pressed(true); preview_camera->show(); } @@ -4392,7 +4392,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) { } spatial_editor->update_transform_gizmo(); - surface->update(); + surface->queue_redraw(); } break; @@ -4491,7 +4491,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) { } spatial_editor->update_transform_gizmo(); - surface->update(); + surface->queue_redraw(); } break; @@ -4595,7 +4595,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) { } spatial_editor->update_transform_gizmo(); - surface->update(); + surface->queue_redraw(); } break; default: { @@ -4608,7 +4608,7 @@ void Node3DEditorViewport::finish_transform() { spatial_editor->update_transform_gizmo(); _edit.mode = TRANSFORM_NONE; _edit.instant = false; - surface->update(); + surface->queue_redraw(); } // Register a shortcut and also add it as an input action with the same events. @@ -5010,7 +5010,7 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) { hovering_v = mm->get_position().y > (mid_h - v_sep / 2) && mm->get_position().y < (mid_h + v_sep / 2); if (was_hovering_h != hovering_h || was_hovering_v != hovering_v) { - update(); + queue_redraw(); } } @@ -5019,14 +5019,14 @@ void Node3DEditorViewportContainer::gui_input(const Ref<InputEvent> &p_event) { new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width); ratio_h = new_ratio; queue_sort(); - update(); + queue_redraw(); } if (dragging_v) { real_t new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height; new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height); ratio_v = new_ratio; queue_sort(); - update(); + queue_redraw(); } } } @@ -5036,7 +5036,7 @@ void Node3DEditorViewportContainer::_notification(int p_what) { case NOTIFICATION_MOUSE_ENTER: case NOTIFICATION_MOUSE_EXIT: { mouseover = (p_what == NOTIFICATION_MOUSE_ENTER); - update(); + queue_redraw(); } break; case NOTIFICATION_DRAW: { @@ -5818,11 +5818,11 @@ void Node3DEditor::_update_camera_override_button(bool p_game_running) { if (p_game_running) { button->set_disabled(false); - button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera.")); + button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera.")); } else { button->set_disabled(true); button->set_pressed(false); - button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature.")); + button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature.")); } } @@ -7122,6 +7122,9 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) { WorldEnvironment *new_env = memnew(WorldEnvironment); new_env->set_environment(preview_environment->get_environment()->duplicate(true)); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + new_env->set_camera_attributes(preview_environment->get_camera_attributes()->duplicate(true)); + } undo_redo->create_action(TTR("Add Preview Environment to Scene")); undo_redo->add_do_method(base, "add_child", new_env, true); @@ -7582,14 +7585,14 @@ void Node3DEditor::_preview_settings_changed() { Transform3D t; t.basis = Basis(Vector3(sun_rotation.x, sun_rotation.y, 0)); preview_sun->set_transform(t); - sun_direction->update(); + sun_direction->queue_redraw(); preview_sun->set_param(Light3D::PARAM_ENERGY, sun_energy->get_value()); preview_sun->set_param(Light3D::PARAM_SHADOW_MAX_DISTANCE, sun_max_distance->get_value()); preview_sun->set_color(sun_color->get_pick_color()); } { //preview env - sky_material->set_sky_energy(environ_energy->get_value()); + sky_material->set_sky_energy_multiplier(environ_energy->get_value()); Color hz_color = environ_sky_color->get_pick_color().lerp(environ_ground_color->get_pick_color(), 0.5).lerp(Color(1, 1, 1), 0.5); sky_material->set_sky_top_color(environ_sky_color->get_pick_color()); sky_material->set_sky_horizon_color(hz_color); @@ -7616,7 +7619,7 @@ void Node3DEditor::_load_default_preview_settings() { sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x)); sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y)); - sun_direction->update(); + sun_direction->queue_redraw(); environ_sky_color->set_pick_color(Color(0.385, 0.454, 0.55)); environ_ground_color->set_pick_color(Color(0.2, 0.169, 0.133)); environ_energy->set_value(1.0); @@ -7748,7 +7751,7 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SELECT)); tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q)); tool_button[TOOL_MODE_SELECT]->set_shortcut_context(this); - tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); + tool_button[TOOL_MODE_SELECT]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); main_menu_hbox->add_child(memnew(VSeparator)); tool_button[TOOL_MODE_MOVE] = memnew(Button); @@ -7783,13 +7786,13 @@ Node3DEditor::Node3DEditor() { tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true); tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_LIST_SELECT)); - tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show list of selectable nodes at position clicked.")); + tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked.")); tool_button[TOOL_LOCK_SELECTED] = memnew(Button); main_menu_hbox->add_child(tool_button[TOOL_LOCK_SELECTED]); tool_button[TOOL_LOCK_SELECTED]->set_flat(true); tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED)); - tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock selected node, preventing selection and movement.")); + tool_button[TOOL_LOCK_SELECTED]->set_tooltip_text(TTR("Lock selected node, preventing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD | Key::L)); @@ -7797,7 +7800,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]); tool_button[TOOL_UNLOCK_SELECTED]->set_flat(true); tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED)); - tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock selected node, allowing selection and movement.")); + tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L)); @@ -7805,7 +7808,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]); tool_button[TOOL_GROUP_SELECTED]->set_flat(true); tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED)); - tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Make selected node's children not selectable.")); + tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children not selectable.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G)); @@ -7813,7 +7816,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]); tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true); tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED)); - tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Make selected node's children selectable.")); + tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children selectable.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G)); @@ -7847,7 +7850,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(memnew(VSeparator)); sun_button = memnew(Button); - sun_button->set_tooltip(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled.")); + sun_button->set_tooltip_text(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled.")); sun_button->set_toggle_mode(true); sun_button->set_flat(true); sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); @@ -7856,7 +7859,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(sun_button); environ_button = memnew(Button); - environ_button->set_tooltip(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled.")); + environ_button->set_tooltip_text(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled.")); environ_button->set_toggle_mode(true); environ_button->set_flat(true); environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED); @@ -7865,7 +7868,7 @@ Node3DEditor::Node3DEditor() { main_menu_hbox->add_child(environ_button); sun_environ_settings = memnew(Button); - sun_environ_settings->set_tooltip(TTR("Edit Sun and Environment settings.")); + sun_environ_settings->set_tooltip_text(TTR("Edit Sun and Environment settings.")); sun_environ_settings->set_flat(true); sun_environ_settings->connect("pressed", callable_mp(this, &Node3DEditor::_sun_environ_settings_pressed)); @@ -8223,7 +8226,7 @@ void fragment() { sun_add_to_scene = memnew(Button); sun_add_to_scene->set_text(TTR("Add Sun to Scene")); - sun_add_to_scene->set_tooltip(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene.")); + sun_add_to_scene->set_tooltip_text(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene.")); sun_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_sun_to_scene).bind(false)); sun_vb->add_spacer(); sun_vb->add_child(sun_add_to_scene); @@ -8292,7 +8295,7 @@ void fragment() { environ_add_to_scene = memnew(Button); environ_add_to_scene->set_text(TTR("Add Environment to Scene")); - environ_add_to_scene->set_tooltip(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene.")); + environ_add_to_scene->set_tooltip_text(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene.")); environ_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_environment_to_scene).bind(false)); environ_vb->add_spacer(); environ_vb->add_child(environ_add_to_scene); @@ -8309,6 +8312,10 @@ void fragment() { preview_environment = memnew(WorldEnvironment); environment.instantiate(); preview_environment->set_environment(environment); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + camera_attributes.instantiate(); + preview_environment->set_camera_attributes(camera_attributes); + } Ref<Sky> sky; sky.instantiate(); sky_material.instantiate(); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index e0298ebd5f..580cb878ce 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -433,7 +433,7 @@ protected: static void _bind_methods(); public: - void update_surface() { surface->update(); } + void update_surface() { surface->queue_redraw(); } void update_transform_gizmo_view(); void set_can_preview(Camera3D *p_preview); @@ -765,6 +765,7 @@ private: DirectionalLight3D *preview_sun = nullptr; WorldEnvironment *preview_environment = nullptr; Ref<Environment> environment; + Ref<CameraAttributesPhysical> camera_attributes; Ref<ProceduralSkyMaterial> sky_material; bool sun_environ_updating = false; diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp index 8d083d28b2..2f4ae734d1 100644 --- a/editor/plugins/packed_scene_translation_parser_plugin.cpp +++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp @@ -123,7 +123,7 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path, PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlugin() { // Scene Node's properties containing strings that will be fetched for translation. lookup_properties.insert("text"); - lookup_properties.insert("hint_tooltip"); + lookup_properties.insert("tooltip_text"); lookup_properties.insert("placeholder_text"); lookup_properties.insert("items"); lookup_properties.insert("title"); diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 1d8a3f5c81..dc6dfd81c2 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -537,7 +537,7 @@ Path2DEditor::Path2DEditor() { curve_edit->set_flat(true); curve_edit->set_toggle_mode(true); curve_edit->set_focus_mode(Control::FOCUS_NONE); - curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point")); + curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point")); curve_edit->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_EDIT)); base_hb->add_child(curve_edit); @@ -545,7 +545,7 @@ Path2DEditor::Path2DEditor() { curve_edit_curve->set_flat(true); curve_edit_curve->set_toggle_mode(true); curve_edit_curve->set_focus_mode(Control::FOCUS_NONE); - curve_edit_curve->set_tooltip(TTR("Select Control Points (Shift+Drag)")); + curve_edit_curve->set_tooltip_text(TTR("Select Control Points (Shift+Drag)")); curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_EDIT_CURVE)); base_hb->add_child(curve_edit_curve); @@ -553,7 +553,7 @@ Path2DEditor::Path2DEditor() { curve_create->set_flat(true); curve_create->set_toggle_mode(true); curve_create->set_focus_mode(Control::FOCUS_NONE); - curve_create->set_tooltip(TTR("Add Point (in empty space)")); + curve_create->set_tooltip_text(TTR("Add Point (in empty space)")); curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CREATE)); base_hb->add_child(curve_create); @@ -561,14 +561,14 @@ Path2DEditor::Path2DEditor() { curve_del->set_flat(true); curve_del->set_toggle_mode(true); curve_del->set_focus_mode(Control::FOCUS_NONE); - curve_del->set_tooltip(TTR("Delete Point")); + curve_del->set_tooltip_text(TTR("Delete Point")); curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_DELETE)); base_hb->add_child(curve_del); curve_close = memnew(Button); curve_close->set_flat(true); curve_close->set_focus_mode(Control::FOCUS_NONE); - curve_close->set_tooltip(TTR("Close Curve")); + curve_close->set_tooltip_text(TTR("Close Curve")); curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(ACTION_CLOSE)); base_hb->add_child(curve_close); diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 084c0c2bb0..1029b06638 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -597,7 +597,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() { curve_edit->set_toggle_mode(true); curve_edit->hide(); curve_edit->set_focus_mode(Control::FOCUS_NONE); - curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point")); + curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point")); Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit); curve_create = memnew(Button); @@ -605,7 +605,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() { curve_create->set_toggle_mode(true); curve_create->hide(); curve_create->set_focus_mode(Control::FOCUS_NONE); - curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)")); + curve_create->set_tooltip_text(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)")); Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_create); curve_del = memnew(Button); @@ -613,14 +613,14 @@ Path3DEditorPlugin::Path3DEditorPlugin() { curve_del->set_toggle_mode(true); curve_del->hide(); curve_del->set_focus_mode(Control::FOCUS_NONE); - curve_del->set_tooltip(TTR("Delete Point")); + curve_del->set_tooltip_text(TTR("Delete Point")); Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del); curve_close = memnew(Button); curve_close->set_flat(true); curve_close->hide(); curve_close->set_focus_mode(Control::FOCUS_NONE); - curve_close->set_tooltip(TTR("Close Curve")); + curve_close->set_tooltip_text(TTR("Close Curve")); Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_close); PopupMenu *menu; diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 4f46c99a04..a652d1d12f 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -155,8 +155,8 @@ void Polygon2DEditor::_sync_bones() { undo_redo->add_undo_method(node, "_set_bones", prev_bones); undo_redo->add_do_method(this, "_update_bone_list"); undo_redo->add_undo_method(this, "_update_bone_list"); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } @@ -195,11 +195,11 @@ void Polygon2DEditor::_update_bone_list() { cb->connect("pressed", callable_mp(this, &Polygon2DEditor::_bone_paint_selected).bind(i)); } - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_bone_paint_selected(int p_index) { - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_uv_edit_mode_select(int p_mode) { @@ -269,7 +269,7 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) { } uv_edit->set_size(uv_edit->get_size()); // Necessary readjustment of the popup window. - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_uv_edit_popup_hide() { @@ -293,8 +293,8 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->create_action(TTR("Create UV Map")); undo_redo->add_do_method(node, "set_uv", points); undo_redo->add_undo_method(node, "set_uv", uvs); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } @@ -314,8 +314,8 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->create_action(TTR("Create UV Map")); undo_redo->add_do_method(node, "set_uv", points); undo_redo->add_undo_method(node, "set_uv", uvs); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } break; case UVEDIT_UV_TO_POLYGON: { @@ -328,8 +328,8 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->create_action(TTR("Create Polygon")); undo_redo->add_do_method(node, "set_polygon", uvs); undo_redo->add_undo_method(node, "set_polygon", points); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } break; case UVEDIT_UV_CLEAR: { @@ -340,8 +340,8 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->create_action(TTR("Create UV Map")); undo_redo->add_do_method(node, "set_uv", Vector<Vector2>()); undo_redo->add_undo_method(node, "set_uv", uvs); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } break; case UVEDIT_GRID_SETTINGS: { @@ -391,8 +391,8 @@ void Polygon2DEditor::_update_polygon_editing_state() { void Polygon2DEditor::_commit_action() { // Makes that undo/redoing actions made outside of the UV editor still affect its polygon. - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport"); undo_redo->add_undo_method(CanvasItemEditor::get_singleton(), "update_viewport"); undo_redo->commit_action(); @@ -406,31 +406,31 @@ void Polygon2DEditor::_set_use_snap(bool p_use) { void Polygon2DEditor::_set_show_grid(bool p_show) { snap_show_grid = p_show; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "show_grid", p_show); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_set_snap_off_x(real_t p_val) { snap_offset.x = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_set_snap_off_y(real_t p_val) { snap_offset.y = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_offset", snap_offset); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_set_snap_step_x(real_t p_val) { snap_step.x = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_set_snap_step_y(real_t p_val) { snap_step.y = p_val; EditorSettings::get_singleton()->set_project_metadata("polygon_2d_uv_editor", "snap_step", snap_step); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_uv_mode(int p_mode) { @@ -495,7 +495,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { node->set_uv(points_prev); node->set_internal_vertex_count(0); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } else { Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position())); @@ -514,8 +514,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_undo_method(node, "_set_bones", uv_create_bones_prev); undo_redo->add_do_method(this, "_update_polygon_editing_state"); undo_redo->add_undo_method(this, "_update_polygon_editing_state"); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); uv_drag = false; uv_create = false; @@ -566,8 +566,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices); undo_redo->add_do_method(this, "_update_polygon_editing_state"); undo_redo->add_undo_method(this, "_update_polygon_editing_state"); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } @@ -621,8 +621,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices); undo_redo->add_do_method(this, "_update_polygon_editing_state"); undo_redo->add_undo_method(this, "_update_polygon_editing_state"); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } @@ -679,8 +679,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->create_action(TTR("Add Custom Polygon")); undo_redo->add_do_method(node, "set_polygons", polygons); undo_redo->add_undo_method(node, "set_polygons", node->get_polygons()); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } @@ -720,8 +720,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->create_action(TTR("Remove Custom Polygon")); undo_redo->add_do_method(node, "set_polygons", polygons); undo_redo->add_undo_method(node, "set_polygons", node->get_polygons()); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } } @@ -748,15 +748,15 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->create_action(TTR("Transform UV Map")); undo_redo->add_do_method(node, "set_uv", node->get_uv()); undo_redo->add_undo_method(node, "set_uv", points_prev); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } else if (uv_edit_mode[1]->is_pressed() && uv_move_current == UV_MODE_EDIT_POINT) { // Edit polygon. undo_redo->create_action(TTR("Transform Polygon")); undo_redo->add_do_method(node, "set_polygon", node->get_polygon()); undo_redo->add_undo_method(node, "set_polygon", points_prev); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); } @@ -767,8 +767,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->create_action(TTR("Paint Bone Weights")); undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone)); undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->add_do_method(uv_edit_draw, "queue_redraw"); + undo_redo->add_undo_method(uv_edit_draw, "queue_redraw"); undo_redo->commit_action(); bone_painting = false; } @@ -780,7 +780,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { node->set_bone_weights(bone_painting_bone, prev_weights); } - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } } @@ -906,14 +906,14 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { node->set_bone_weights(bone_painting_bone, painted_weights); } - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); CanvasItemEditor::get_singleton()->update_viewport(); } else if (polygon_create.size()) { uv_create_to = mtx.affine_inverse().xform(mm->get_position()); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } else if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) { bone_paint_pos = mm->get_position(); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } } @@ -954,7 +954,7 @@ void Polygon2DEditor::_uv_scroll_changed(real_t) { uv_draw_ofs.x = uv_hscroll->get_value(); uv_draw_ofs.y = uv_vscroll->get_value(); uv_draw_zoom = uv_zoom->get_value(); - uv_edit_draw->update(); + uv_edit_draw->queue_redraw(); } void Polygon2DEditor::_uv_draw() { @@ -1237,7 +1237,7 @@ Polygon2DEditor::Polygon2DEditor() { button_uv = memnew(Button); button_uv->set_flat(true); add_child(button_uv); - button_uv->set_tooltip(TTR("Open Polygon 2D UV editor.")); + button_uv->set_tooltip_text(TTR("Open Polygon 2D UV editor.")); button_uv->connect("pressed", callable_mp(this, &Polygon2DEditor::_menu_option).bind(MODE_EDIT_UV)); uv_mode = UV_MODE_EDIT_POINT; @@ -1293,17 +1293,17 @@ Polygon2DEditor::Polygon2DEditor() { uv_button[i]->set_focus_mode(FOCUS_NONE); } - uv_button[UV_MODE_CREATE]->set_tooltip(TTR("Create Polygon")); - uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip(TTR("Create Internal Vertex")); - uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip(TTR("Remove Internal Vertex")); - uv_button[UV_MODE_EDIT_POINT]->set_tooltip(TTR("Move Points") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale")); - uv_button[UV_MODE_MOVE]->set_tooltip(TTR("Move Polygon")); - uv_button[UV_MODE_ROTATE]->set_tooltip(TTR("Rotate Polygon")); - uv_button[UV_MODE_SCALE]->set_tooltip(TTR("Scale Polygon")); - uv_button[UV_MODE_ADD_POLYGON]->set_tooltip(TTR("Create a custom polygon. Enables custom polygon rendering.")); - uv_button[UV_MODE_REMOVE_POLYGON]->set_tooltip(TTR("Remove a custom polygon. If none remain, custom polygon rendering is disabled.")); - uv_button[UV_MODE_PAINT_WEIGHT]->set_tooltip(TTR("Paint weights with specified intensity.")); - uv_button[UV_MODE_CLEAR_WEIGHT]->set_tooltip(TTR("Unpaint weights with specified intensity.")); + uv_button[UV_MODE_CREATE]->set_tooltip_text(TTR("Create Polygon")); + uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip_text(TTR("Create Internal Vertex")); + uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip_text(TTR("Remove Internal Vertex")); + uv_button[UV_MODE_EDIT_POINT]->set_tooltip_text(TTR("Move Points") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale")); + uv_button[UV_MODE_MOVE]->set_tooltip_text(TTR("Move Polygon")); + uv_button[UV_MODE_ROTATE]->set_tooltip_text(TTR("Rotate Polygon")); + uv_button[UV_MODE_SCALE]->set_tooltip_text(TTR("Scale Polygon")); + uv_button[UV_MODE_ADD_POLYGON]->set_tooltip_text(TTR("Create a custom polygon. Enables custom polygon rendering.")); + uv_button[UV_MODE_REMOVE_POLYGON]->set_tooltip_text(TTR("Remove a custom polygon. If none remain, custom polygon rendering is disabled.")); + uv_button[UV_MODE_PAINT_WEIGHT]->set_tooltip_text(TTR("Paint weights with specified intensity.")); + uv_button[UV_MODE_CLEAR_WEIGHT]->set_tooltip_text(TTR("Unpaint weights with specified intensity.")); uv_button[UV_MODE_CREATE]->hide(); uv_button[UV_MODE_CREATE_INTERNAL]->hide(); @@ -1368,7 +1368,7 @@ Polygon2DEditor::Polygon2DEditor() { b_snap_enable->set_focus_mode(FOCUS_NONE); b_snap_enable->set_toggle_mode(true); b_snap_enable->set_pressed(use_snap); - b_snap_enable->set_tooltip(TTR("Enable Snap")); + b_snap_enable->set_tooltip_text(TTR("Enable Snap")); b_snap_enable->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_use_snap)); b_snap_grid = memnew(Button); @@ -1378,7 +1378,7 @@ Polygon2DEditor::Polygon2DEditor() { b_snap_grid->set_focus_mode(FOCUS_NONE); b_snap_grid->set_toggle_mode(true); b_snap_grid->set_pressed(snap_show_grid); - b_snap_grid->set_tooltip(TTR("Show Grid")); + b_snap_grid->set_tooltip_text(TTR("Show Grid")); b_snap_grid->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_show_grid)); grid_settings = memnew(AcceptDialog); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 201a3af539..21647d1b69 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -196,7 +196,7 @@ void ResourcePreloaderEditor::_update_library() { String type = r->get_class(); ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(type, "Object")); - ti->set_tooltip(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type); + ti->set_tooltip_text(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type); ti->set_text(1, r->get_path()); ti->set_editable(1, false); @@ -356,7 +356,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { vbc->add_child(hbc); load = memnew(Button); - load->set_tooltip(TTR("Load Resource")); + load->set_tooltip_text(TTR("Load Resource")); hbc->add_child(load); paste = memnew(Button); diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 681dd476e3..de30c4100d 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -198,7 +198,7 @@ void EditorPropertyRootMotion::_node_clear() { void EditorPropertyRootMotion::update_property() { NodePath p = get_edited_object()->get(get_edited_property()); - assign->set_tooltip(p); + assign->set_tooltip_text(p); if (p == NodePath()) { assign->set_icon(Ref<Texture2D>()); assign->set_text(TTR("Assign...")); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index a0c9ddb14b..ad114e022f 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -940,50 +940,6 @@ void ScriptEditor::_resave_scripts(const String &p_str) { disk_changed->hide(); } -void ScriptEditor::_reload_scripts() { - for (int i = 0; i < tab_container->get_tab_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); - if (!se) { - continue; - } - - Ref<Resource> edited_res = se->get_edited_resource(); - - if (edited_res->is_built_in()) { - continue; //internal script, who cares - } - - uint64_t last_date = edited_res->get_last_modified_time(); - uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); - - if (last_date == date) { - continue; - } - - Ref<Script> script = edited_res; - if (script != nullptr) { - Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); - ERR_CONTINUE(!rel_script.is_valid()); - script->set_source_code(rel_script->get_source_code()); - script->set_last_modified_time(rel_script->get_last_modified_time()); - script->reload(true); - } - - Ref<TextFile> text_file = edited_res; - if (text_file != nullptr) { - Error err; - Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err); - ERR_CONTINUE(!rel_text_file.is_valid()); - text_file->set_text(rel_text_file->get_text()); - text_file->set_last_modified_time(rel_text_file->get_last_modified_time()); - } - se->reload_text(); - } - - disk_changed->hide(); - _update_script_names(); -} - void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); @@ -1077,7 +1033,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) { if (need_reload) { if (!need_ask) { - script_editor->_reload_scripts(); + script_editor->reload_scripts(); need_reload = false; } else { disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.5); @@ -1540,7 +1496,7 @@ void ScriptEditor::_show_save_theme_as_dialog() { file_dialog_option = THEME_SAVE_AS; file_dialog->clear_filters(); file_dialog->add_filter("*.tet"); - file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); + file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("Save Theme As...")); } @@ -2038,7 +1994,7 @@ void ScriptEditor::_update_script_names() { } break; case DISPLAY_DIR_AND_NAME: { if (!path.get_base_dir().get_file().is_empty()) { - sd.name = path.get_base_dir().get_file().plus_file(name); + sd.name = path.get_base_dir().get_file().path_join(name); } else { sd.name = name; } @@ -2064,7 +2020,7 @@ void ScriptEditor::_update_script_names() { name = name.get_file(); } break; case DISPLAY_DIR_AND_NAME: { - name = name.get_base_dir().get_file().plus_file(name.get_file()); + name = name.get_base_dir().get_file().path_join(name.get_file()); } break; default: break; @@ -2588,6 +2544,50 @@ void ScriptEditor::apply_scripts() const { } } +void ScriptEditor::reload_scripts() { + for (int i = 0; i < tab_container->get_tab_count(); i++) { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); + if (!se) { + continue; + } + + Ref<Resource> edited_res = se->get_edited_resource(); + + if (edited_res->is_built_in()) { + continue; //internal script, who cares + } + + uint64_t last_date = edited_res->get_last_modified_time(); + uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); + + if (last_date == date) { + continue; + } + + Ref<Script> script = edited_res; + if (script != nullptr) { + Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); + ERR_CONTINUE(!rel_script.is_valid()); + script->set_source_code(rel_script->get_source_code()); + script->set_last_modified_time(rel_script->get_last_modified_time()); + script->reload(true); + } + + Ref<TextFile> text_file = edited_res; + if (text_file != nullptr) { + Error err; + Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err); + ERR_CONTINUE(!rel_text_file.is_valid()); + text_file->set_text(rel_text_file->get_text()); + text_file->set_last_modified_time(rel_text_file->get_last_modified_time()); + } + se->reload_text(); + } + + disk_changed->hide(); + _update_script_names(); +} + void ScriptEditor::open_script_create_dialog(const String &p_base_name, const String &p_base_path) { _menu_option(FILE_NEW); script_create_dialog->config(p_base_name, p_base_path); @@ -3267,7 +3267,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset()); // Save the cache. - script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg")); + script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg")); } void ScriptEditor::_help_class_open(const String &p_class) { @@ -3648,7 +3648,7 @@ ScriptEditor::ScriptEditor() { current_theme = ""; script_editor_cache.instantiate(); - script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg")); + script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg")); completion_cache = memnew(EditorScriptCodeCompletionCache); restoring_layout = false; @@ -3712,7 +3712,7 @@ ScriptEditor::ScriptEditor() { members_overview_alphabeta_sort_button = memnew(Button); members_overview_alphabeta_sort_button->set_flat(true); - members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list.")); + members_overview_alphabeta_sort_button->set_tooltip_text(TTR("Toggle alphabetical sorting of the method list.")); members_overview_alphabeta_sort_button->set_toggle_mode(true); members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/script_list/sort_members_outline_alphabetically")); members_overview_alphabeta_sort_button->connect("toggled", callable_mp(this, &ScriptEditor::_toggle_members_overview_alpha_sort)); @@ -3858,14 +3858,14 @@ ScriptEditor::ScriptEditor() { site_search->set_text(TTR("Online Docs")); site_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_WEBSITE)); menu_hb->add_child(site_search); - site_search->set_tooltip(TTR("Open Godot online documentation.")); + site_search->set_tooltip_text(TTR("Open Godot online documentation.")); help_search = memnew(Button); help_search->set_flat(true); help_search->set_text(TTR("Search Help")); help_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_HELP)); menu_hb->add_child(help_search); - help_search->set_tooltip(TTR("Search the reference documentation.")); + help_search->set_tooltip_text(TTR("Search the reference documentation.")); menu_hb->add_child(memnew(VSeparator)); @@ -3874,14 +3874,14 @@ ScriptEditor::ScriptEditor() { script_back->connect("pressed", callable_mp(this, &ScriptEditor::_history_back)); menu_hb->add_child(script_back); script_back->set_disabled(true); - script_back->set_tooltip(TTR("Go to previous edited document.")); + script_back->set_tooltip_text(TTR("Go to previous edited document.")); script_forward = memnew(Button); script_forward->set_flat(true); script_forward->connect("pressed", callable_mp(this, &ScriptEditor::_history_forward)); menu_hb->add_child(script_forward); script_forward->set_disabled(true); - script_forward->set_tooltip(TTR("Go to next edited document.")); + script_forward->set_tooltip_text(TTR("Go to next edited document.")); tab_container->connect("tab_changed", callable_mp(this, &ScriptEditor::_tab_changed)); @@ -3918,7 +3918,7 @@ ScriptEditor::ScriptEditor() { vbc->add_child(disk_changed_list); disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL); - disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::_reload_scripts)); + disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts)); disk_changed->set_ok_button_text(TTR("Reload")); disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index d1898efb69..a8e6cc6868 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -327,7 +327,6 @@ class ScriptEditor : public PanelContainer { String _get_debug_tooltip(const String &p_text, Node *_se); void _resave_scripts(const String &p_str); - void _reload_scripts(); bool _test_script_times_on_disk(Ref<Resource> p_for_script = Ref<Resource>()); @@ -478,6 +477,7 @@ public: bool toggle_scripts_panel(); bool is_scripts_panel_toggled(); void apply_scripts() const; + void reload_scripts(); void open_script_create_dialog(const String &p_base_name, const String &p_base_path); void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = ""); Ref<Resource> open_file(const String &p_file); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 5e7db17edf..fff956a05e 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -942,7 +942,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) { String ScriptTextEditor::_get_absolute_path(const String &rel_path) { String base_path = script->get_path().get_base_dir(); - String path = base_path.plus_file(rel_path); + String path = base_path.path_join(rel_path); return path.replace("///", "//").simplify_path(); } @@ -1124,15 +1124,15 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_TOGGLE_FOLD_LINE: { tx->toggle_foldable_line(tx->get_caret_line()); - tx->update(); + tx->queue_redraw(); } break; case EDIT_FOLD_ALL_LINES: { tx->fold_all_lines(); - tx->update(); + tx->queue_redraw(); } break; case EDIT_UNFOLD_ALL_LINES: { tx->unfold_all_lines(); - tx->update(); + tx->queue_redraw(); } break; case EDIT_TOGGLE_COMMENT: { _edit_option_toggle_inline_comment(); @@ -1590,7 +1590,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } } - String variable_name = String(node->get_name()).camelcase_to_underscore(true).validate_identifier(); + String variable_name = String(node->get_name()).to_snake_case().validate_identifier(); if (use_type) { text_to_drop += vformat("@onready var %s: %s = %s%s\n", variable_name, node->get_class_name(), is_unique ? "%" : "$", path); } else { @@ -1760,7 +1760,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { code_editor->get_text_editor()->begin_complex_operation(); code_editor->get_text_editor()->set_line(color_position.x, line_with_replaced_args); code_editor->get_text_editor()->end_complex_operation(); - code_editor->get_text_editor()->update(); + code_editor->get_text_editor()->queue_redraw(); } void ScriptTextEditor::_prepare_edit_menu() { diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 53bc6fbdf4..6674d15268 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -1398,12 +1398,12 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) { switch (p_index) { case FILE_NEW: { String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir(); - shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 0); + shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 0); shader_create_dialog->popup_centered(); } break; case FILE_NEW_INCLUDE: { String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir(); - shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 2); + shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 2); shader_create_dialog->popup_centered(); } break; case FILE_OPEN: { diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index c25f2bb25c..b85e44e106 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -182,27 +182,27 @@ void BoneTransformEditor::_update_properties() { if (split[2] == "enabled") { enabled_checkbox->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); enabled_checkbox->update_property(); - enabled_checkbox->update(); + enabled_checkbox->queue_redraw(); } if (split[2] == "position") { position_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); position_property->update_property(); - position_property->update(); + position_property->queue_redraw(); } if (split[2] == "rotation") { rotation_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); rotation_property->update_property(); - rotation_property->update(); + rotation_property->queue_redraw(); } if (split[2] == "scale") { scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); scale_property->update_property(); - scale_property->update(); + scale_property->queue_redraw(); } if (split[2] == "rest") { rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); rest_matrix->update_property(); - rest_matrix->update(); + rest_matrix->queue_redraw(); } } } @@ -426,7 +426,9 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi bone_shape->set_name("CollisionShape3D"); Transform3D capsule_transform; - capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0)); + capsule_transform.basis.rows[0] = Vector3(1, 0, 0); + capsule_transform.basis.rows[1] = Vector3(0, 0, 1); + capsule_transform.basis.rows[2] = Vector3(0, -1, 0); bone_shape->set_transform(capsule_transform); /// Get an up vector not collinear with child rest origin @@ -690,8 +692,6 @@ void Skeleton3DEditor::update_editors() { void Skeleton3DEditor::create_editors() { set_h_size_flags(SIZE_EXPAND_FILL); - add_theme_constant_override("separation", 0); - set_focus_mode(FOCUS_ALL); Node3DEditor *ne = Node3DEditor::get_singleton(); @@ -733,7 +733,7 @@ void Skeleton3DEditor::create_editors() { edit_mode_button->set_flat(true); edit_mode_button->set_toggle_mode(true); edit_mode_button->set_focus_mode(FOCUS_NONE); - edit_mode_button->set_tooltip(TTR("Edit Mode\nShow buttons on joints.")); + edit_mode_button->set_tooltip_text(TTR("Edit Mode\nShow buttons on joints.")); edit_mode_button->connect("toggled", callable_mp(this, &Skeleton3DEditor::edit_mode_toggled)); edit_mode = false; @@ -754,7 +754,7 @@ void Skeleton3DEditor::create_editors() { key_loc_button->set_toggle_mode(true); key_loc_button->set_pressed(false); key_loc_button->set_focus_mode(FOCUS_NONE); - key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); + key_loc_button->set_tooltip_text(TTR("Translation mask for inserting keys.")); animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button); @@ -762,7 +762,7 @@ void Skeleton3DEditor::create_editors() { key_rot_button->set_toggle_mode(true); key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); - key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); + key_rot_button->set_tooltip_text(TTR("Rotation mask for inserting keys.")); animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button); @@ -770,14 +770,14 @@ void Skeleton3DEditor::create_editors() { key_scale_button->set_toggle_mode(true); key_scale_button->set_pressed(false); key_scale_button->set_focus_mode(FOCUS_NONE); - key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); + key_scale_button->set_tooltip_text(TTR("Scale mask for inserting keys.")); animation_hb->add_child(key_scale_button); key_insert_button = memnew(Button); key_insert_button->set_flat(true); key_insert_button->set_focus_mode(FOCUS_NONE); key_insert_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys).bind(false)); - key_insert_button->set_tooltip(TTR("Insert key of bone poses already exist track.")); + key_insert_button->set_tooltip_text(TTR("Insert key of bone poses already exist track.")); key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTR("Insert Key (Existing Tracks)"), Key::INSERT)); animation_hb->add_child(key_insert_button); @@ -785,7 +785,7 @@ void Skeleton3DEditor::create_editors() { key_insert_all_button->set_flat(true); key_insert_all_button->set_focus_mode(FOCUS_NONE); key_insert_all_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys).bind(true)); - key_insert_all_button->set_tooltip(TTR("Insert key of all bone poses.")); + key_insert_all_button->set_tooltip_text(TTR("Insert key of all bone poses.")); key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTR("Insert Key (All Bones)"), KeyModifierMask::CMD + Key::INSERT)); animation_hb->add_child(key_insert_all_button); @@ -823,20 +823,11 @@ void Skeleton3DEditor::create_editors() { void Skeleton3DEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), SNAME("EditorIcons"))); - key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons"))); - key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons"))); - key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons"))); - key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons"))); - key_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons"))); - get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONESHOT); - break; - } case NOTIFICATION_ENTER_TREE: { create_editors(); update_joint_tree(); update_editors(); + joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed)); joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select)); #ifdef TOOLS_ENABLED @@ -845,8 +836,23 @@ void Skeleton3DEditor::_notification(int p_what) { skeleton->connect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); skeleton->connect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); #endif - break; - } + + get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONESHOT); + } break; + case NOTIFICATION_READY: { + // Will trigger NOTIFICATION_THEME_CHANGED, but won't cause any loops if called here. + add_theme_constant_override("separation", 0); + } break; + case NOTIFICATION_THEME_CHANGED: { + edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), SNAME("EditorIcons"))); + key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons"))); + key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons"))); + key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons"))); + key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons"))); + key_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons"))); + + update_joint_tree(); + } break; } } diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index e45c907e86..615fd5dba9 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -128,7 +128,7 @@ void Sprite2DEditor::_menu_option(int p_option) { _update_mesh_data(); debug_uv_dialog->popup_centered(); - debug_uv->update(); + debug_uv->queue_redraw(); } break; case MENU_OPTION_CONVERT_TO_POLYGON_2D: { @@ -137,7 +137,7 @@ void Sprite2DEditor::_menu_option(int p_option) { _update_mesh_data(); debug_uv_dialog->popup_centered(); - debug_uv->update(); + debug_uv->queue_redraw(); } break; case MENU_OPTION_CREATE_COLLISION_POLY_2D: { debug_uv_dialog->set_ok_button_text(TTR("Create CollisionPolygon2D")); @@ -145,7 +145,7 @@ void Sprite2DEditor::_menu_option(int p_option) { _update_mesh_data(); debug_uv_dialog->popup_centered(); - debug_uv->update(); + debug_uv->queue_redraw(); } break; case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: { @@ -154,7 +154,7 @@ void Sprite2DEditor::_menu_option(int p_option) { _update_mesh_data(); debug_uv_dialog->popup_centered(); - debug_uv->update(); + debug_uv->queue_redraw(); } break; } @@ -302,7 +302,7 @@ void Sprite2DEditor::_update_mesh_data() { } } - debug_uv->update(); + debug_uv->queue_redraw(); } void Sprite2DEditor::_create_node() { diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 205fed48b4..9508835442 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -182,7 +182,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { if (last_frame_selected != idx || idx != -1) { last_frame_selected = idx; - split_sheet_preview->update(); + split_sheet_preview->queue_redraw(); } } @@ -208,7 +208,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { } last_frame_selected = idx; - split_sheet_preview->update(); + split_sheet_preview->queue_redraw(); } } } @@ -307,7 +307,7 @@ void SpriteFramesEditor::_sheet_select_clear_all_frames() { frames_selected.clear(); } - split_sheet_preview->update(); + split_sheet_preview->queue_redraw(); } void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_param) { @@ -363,7 +363,7 @@ void SpriteFramesEditor::_sheet_spin_changed(double p_value, int p_dominant_para frames_selected.clear(); last_frame_selected = -1; - split_sheet_preview->update(); + split_sheet_preview->queue_redraw(); } void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { @@ -1161,13 +1161,13 @@ SpriteFramesEditor::SpriteFramesEditor() { new_anim = memnew(Button); new_anim->set_flat(true); - new_anim->set_tooltip(TTR("New Animation")); + new_anim->set_tooltip_text(TTR("New Animation")); hbc_animlist->add_child(new_anim); new_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_add)); remove_anim = memnew(Button); remove_anim->set_flat(true); - remove_anim->set_tooltip(TTR("Remove Animation")); + remove_anim->set_tooltip_text(TTR("Remove Animation")); hbc_animlist->add_child(remove_anim); remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove)); @@ -1215,53 +1215,53 @@ SpriteFramesEditor::SpriteFramesEditor() { load = memnew(Button); load->set_flat(true); - load->set_tooltip(TTR("Add a Texture from File")); + load->set_tooltip_text(TTR("Add a Texture from File")); hbc->add_child(load); load_sheet = memnew(Button); load_sheet->set_flat(true); - load_sheet->set_tooltip(TTR("Add Frames from a Sprite Sheet")); + load_sheet->set_tooltip_text(TTR("Add Frames from a Sprite Sheet")); hbc->add_child(load_sheet); hbc->add_child(memnew(VSeparator)); copy = memnew(Button); copy->set_flat(true); - copy->set_tooltip(TTR("Copy")); + copy->set_tooltip_text(TTR("Copy")); hbc->add_child(copy); paste = memnew(Button); paste->set_flat(true); - paste->set_tooltip(TTR("Paste")); + paste->set_tooltip_text(TTR("Paste")); hbc->add_child(paste); hbc->add_child(memnew(VSeparator)); empty = memnew(Button); empty->set_flat(true); - empty->set_tooltip(TTR("Insert Empty (Before)")); + empty->set_tooltip_text(TTR("Insert Empty (Before)")); hbc->add_child(empty); empty2 = memnew(Button); empty2->set_flat(true); - empty2->set_tooltip(TTR("Insert Empty (After)")); + empty2->set_tooltip_text(TTR("Insert Empty (After)")); hbc->add_child(empty2); hbc->add_child(memnew(VSeparator)); move_up = memnew(Button); move_up->set_flat(true); - move_up->set_tooltip(TTR("Move (Before)")); + move_up->set_tooltip_text(TTR("Move (Before)")); hbc->add_child(move_up); move_down = memnew(Button); move_down->set_flat(true); - move_down->set_tooltip(TTR("Move (After)")); + move_down->set_tooltip_text(TTR("Move (After)")); hbc->add_child(move_down); _delete = memnew(Button); _delete->set_flat(true); - _delete->set_tooltip(TTR("Delete")); + _delete->set_tooltip_text(TTR("Delete")); hbc->add_child(_delete); hbc->add_spacer(); @@ -1269,19 +1269,19 @@ SpriteFramesEditor::SpriteFramesEditor() { zoom_out = memnew(Button); zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_out)); zoom_out->set_flat(true); - zoom_out->set_tooltip(TTR("Zoom Out")); + zoom_out->set_tooltip_text(TTR("Zoom Out")); hbc->add_child(zoom_out); zoom_reset = memnew(Button); zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_reset)); zoom_reset->set_flat(true); - zoom_reset->set_tooltip(TTR("Zoom Reset")); + zoom_reset->set_tooltip_text(TTR("Zoom Reset")); hbc->add_child(zoom_reset); zoom_in = memnew(Button); zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_in)); zoom_in->set_flat(true); - zoom_in->set_tooltip(TTR("Zoom In")); + zoom_in->set_tooltip_text(TTR("Zoom In")); hbc->add_child(zoom_in); file = memnew(EditorFileDialog); @@ -1434,21 +1434,21 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_zoom_out = memnew(Button); split_sheet_zoom_out->set_flat(true); split_sheet_zoom_out->set_focus_mode(FOCUS_NONE); - split_sheet_zoom_out->set_tooltip(TTR("Zoom Out")); + split_sheet_zoom_out->set_tooltip_text(TTR("Zoom Out")); split_sheet_zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_out)); split_sheet_zoom_hb->add_child(split_sheet_zoom_out); split_sheet_zoom_reset = memnew(Button); split_sheet_zoom_reset->set_flat(true); split_sheet_zoom_reset->set_focus_mode(FOCUS_NONE); - split_sheet_zoom_reset->set_tooltip(TTR("Zoom Reset")); + split_sheet_zoom_reset->set_tooltip_text(TTR("Zoom Reset")); split_sheet_zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_reset)); split_sheet_zoom_hb->add_child(split_sheet_zoom_reset); split_sheet_zoom_in = memnew(Button); split_sheet_zoom_in->set_flat(true); split_sheet_zoom_in->set_focus_mode(FOCUS_NONE); - split_sheet_zoom_in->set_tooltip(TTR("Zoom In")); + split_sheet_zoom_in->set_tooltip_text(TTR("Zoom In")); split_sheet_zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_in)); split_sheet_zoom_hb->add_child(split_sheet_zoom_in); diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index d4baff34e2..fffcce6d9a 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -36,7 +36,7 @@ bool StyleBoxPreview::grid_preview_enabled = true; void StyleBoxPreview::_grid_preview_toggled(bool p_active) { grid_preview_enabled = p_active; - preview->update(); + preview->queue_redraw(); } bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) { @@ -66,7 +66,7 @@ void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) { } void StyleBoxPreview::_sb_changed() { - preview->update(); + preview->queue_redraw(); } void StyleBoxPreview::_notification(int p_what) { diff --git a/editor/plugins/sub_viewport_preview_editor_plugin.cpp b/editor/plugins/sub_viewport_preview_editor_plugin.cpp index c8bb0cd56f..074a9708b7 100644 --- a/editor/plugins/sub_viewport_preview_editor_plugin.cpp +++ b/editor/plugins/sub_viewport_preview_editor_plugin.cpp @@ -39,7 +39,7 @@ void EditorInspectorPluginSubViewportPreview::parse_begin(Object *p_object) { TexturePreview *sub_viewport_preview = memnew(TexturePreview(sub_viewport->get_texture(), false)); // Otherwise `sub_viewport_preview`'s `texture_display` doesn't update properly when `sub_viewport`'s size changes. - sub_viewport->connect("size_changed", callable_mp((CanvasItem *)sub_viewport_preview->get_texture_display(), &CanvasItem::update)); + sub_viewport->connect("size_changed", callable_mp((CanvasItem *)sub_viewport_preview->get_texture_display(), &CanvasItem::queue_redraw)); add_custom_control(sub_viewport_preview); } diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 0900415b04..76332b2d10 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -339,15 +339,15 @@ void TextEditor::_edit_option(int p_op) { } break; case EDIT_TOGGLE_FOLD_LINE: { tx->toggle_foldable_line(tx->get_caret_line()); - tx->update(); + tx->queue_redraw(); } break; case EDIT_FOLD_ALL_LINES: { tx->fold_all_lines(); - tx->update(); + tx->queue_redraw(); } break; case EDIT_UNFOLD_ALL_LINES: { tx->unfold_all_lines(); - tx->update(); + tx->queue_redraw(); } break; case EDIT_TRIM_TRAILING_WHITESAPCE: { trim_trailing_whitespace(); diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index 64cafa17f3..c2517b4b79 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -53,7 +53,7 @@ void Texture3DEditor::_texture_changed() { if (!is_visible()) { return; } - update(); + queue_redraw(); } void Texture3DEditor::_update_material() { @@ -124,7 +124,7 @@ void Texture3DEditor::edit(Ref<Texture3D> p_texture) { } texture->connect("changed", callable_mp(this, &Texture3DEditor::_texture_changed)); - update(); + queue_redraw(); texture_rect->set_material(material); setting = true; layer->set_max(texture->get_depth() - 1); diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index 2c6f70463d..1118f18605 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -64,7 +64,7 @@ void TextureLayeredEditor::_texture_changed() { if (!is_visible()) { return; } - update(); + queue_redraw(); } void TextureLayeredEditor::_update_material() { @@ -190,7 +190,7 @@ void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) { } texture->connect("changed", callable_mp(this, &TextureLayeredEditor::_texture_changed)); - update(); + queue_redraw(); texture_rect->set_material(materials[texture->get_layered_type()]); setting = true; if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) { diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 772bae6544..f0e3619060 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -381,8 +381,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } undo_redo->add_do_method(this, "_update_rect"); undo_redo->add_undo_method(this, "_update_rect"); - undo_redo->add_do_method(edit_draw, "update"); - undo_redo->add_undo_method(edit_draw, "update"); + undo_redo->add_do_method(edit_draw, "queue_redraw"); + undo_redo->add_undo_method(edit_draw, "queue_redraw"); undo_redo->commit_action(); break; } @@ -455,8 +455,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } undo_redo->add_do_method(this, "_update_rect"); undo_redo->add_undo_method(this, "_update_rect"); - undo_redo->add_do_method(edit_draw, "update"); - undo_redo->add_undo_method(edit_draw, "update"); + undo_redo->add_do_method(edit_draw, "queue_redraw"); + undo_redo->add_undo_method(edit_draw, "queue_redraw"); undo_redo->commit_action(); drag = false; creating = false; @@ -477,7 +477,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else { apply_rect(rect_prev); rect = rect_prev; - edit_draw->update(); + edit_draw->queue_redraw(); drag_index = -1; } } @@ -546,7 +546,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { rect = Rect2(drag_from, Size2()); rect.expand_to(new_pos); apply_rect(rect); - edit_draw->update(); + edit_draw->queue_redraw(); return; } @@ -601,7 +601,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } break; } } - edit_draw->update(); + edit_draw->queue_redraw(); } } @@ -642,7 +642,7 @@ void TextureRegionEditor::_scroll_changed(float) { draw_ofs.x = hscroll->get_value(); draw_ofs.y = vscroll->get_value(); - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_set_snap_mode(int p_mode) { @@ -658,37 +658,37 @@ void TextureRegionEditor::_set_snap_mode(int p_mode) { _update_autoslice(); } - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_set_snap_off_x(float p_val) { snap_offset.x = p_val; - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_set_snap_off_y(float p_val) { snap_offset.y = p_val; - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_set_snap_step_x(float p_val) { snap_step.x = p_val; - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_set_snap_step_y(float p_val) { snap_step.y = p_val; - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_set_snap_sep_x(float p_val) { snap_separation.x = p_val; - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_set_snap_sep_y(float p_val) { snap_separation.y = p_val; - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) { @@ -702,7 +702,7 @@ void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) { ofs = ofs / prev_zoom - ofs / draw_zoom; draw_ofs = (draw_ofs + ofs).round(); - edit_draw->update(); + edit_draw->queue_redraw(); } void TextureRegionEditor::_zoom_in() { @@ -933,7 +933,7 @@ void TextureRegionEditor::edit(Object *p_obj) { obj_styleBox = Ref<StyleBoxTexture>(nullptr); atlas_tex = Ref<AtlasTexture>(nullptr); } - edit_draw->update(); + edit_draw->queue_redraw(); popup_centered_ratio(0.5); request_center = true; } @@ -963,7 +963,7 @@ void TextureRegionEditor::_edit_region() { _zoom_reset(); hscroll->hide(); vscroll->hide(); - edit_draw->update(); + edit_draw->queue_redraw(); return; } @@ -979,7 +979,7 @@ void TextureRegionEditor::_edit_region() { } _update_rect(); - edit_draw->update(); + edit_draw->queue_redraw(); } Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const { @@ -1110,19 +1110,19 @@ TextureRegionEditor::TextureRegionEditor() { zoom_out = memnew(Button); zoom_out->set_flat(true); - zoom_out->set_tooltip(TTR("Zoom Out")); + zoom_out->set_tooltip_text(TTR("Zoom Out")); zoom_out->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_out)); zoom_hb->add_child(zoom_out); zoom_reset = memnew(Button); zoom_reset->set_flat(true); - zoom_reset->set_tooltip(TTR("Zoom Reset")); + zoom_reset->set_tooltip_text(TTR("Zoom Reset")); zoom_reset->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_reset)); zoom_hb->add_child(zoom_reset); zoom_in = memnew(Button); zoom_in->set_flat(true); - zoom_in->set_tooltip(TTR("Zoom In")); + zoom_in->set_tooltip_text(TTR("Zoom In")); zoom_in->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_in)); zoom_hb->add_child(zoom_in); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index af3959d47c..f6acd8ceda 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" #include "scene/gui/color_picker.h" +#include "scene/theme/theme_db.h" void ThemeItemImportTree::_update_items_tree() { import_items_tree->clear(); @@ -1103,15 +1104,15 @@ ThemeItemImportTree::ThemeItemImportTree() { button_set->set_alignment(BoxContainer::ALIGNMENT_END); all_set->add_child(button_set); select_all_items_button->set_flat(true); - select_all_items_button->set_tooltip(select_all_items_tooltip); + select_all_items_button->set_tooltip_text(select_all_items_tooltip); button_set->add_child(select_all_items_button); select_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_data_type_pressed).bind(i)); select_full_items_button->set_flat(true); - select_full_items_button->set_tooltip(select_full_items_tooltip); + select_full_items_button->set_tooltip_text(select_full_items_tooltip); button_set->add_child(select_full_items_button); select_full_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_data_type_pressed).bind(i)); deselect_all_items_button->set_flat(true); - deselect_all_items_button->set_tooltip(deselect_all_items_tooltip); + deselect_all_items_button->set_tooltip_text(deselect_all_items_tooltip); button_set->add_child(deselect_all_items_button); deselect_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed).bind(i)); @@ -1142,12 +1143,12 @@ ThemeItemImportTree::ThemeItemImportTree() { import_collapse_types_button = memnew(Button); import_collapse_types_button->set_flat(true); - import_collapse_types_button->set_tooltip(TTR("Collapse types.")); + import_collapse_types_button->set_tooltip_text(TTR("Collapse types.")); import_buttons->add_child(import_collapse_types_button); import_collapse_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(true)); import_expand_types_button = memnew(Button); import_expand_types_button->set_flat(true); - import_expand_types_button->set_tooltip(TTR("Expand types.")); + import_expand_types_button->set_tooltip_text(TTR("Expand types.")); import_buttons->add_child(import_expand_types_button); import_expand_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(false)); @@ -1156,19 +1157,19 @@ ThemeItemImportTree::ThemeItemImportTree() { import_select_all_button = memnew(Button); import_select_all_button->set_flat(true); import_select_all_button->set_text(TTR("Select All")); - import_select_all_button->set_tooltip(TTR("Select all Theme items.")); + import_select_all_button->set_tooltip_text(TTR("Select all Theme items.")); import_buttons->add_child(import_select_all_button); import_select_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_items_pressed)); import_select_full_button = memnew(Button); import_select_full_button->set_flat(true); import_select_full_button->set_text(TTR("Select With Data")); - import_select_full_button->set_tooltip(TTR("Select all Theme items with item data.")); + import_select_full_button->set_tooltip_text(TTR("Select all Theme items with item data.")); import_buttons->add_child(import_select_full_button); import_select_full_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_items_pressed)); import_deselect_all_button = memnew(Button); import_deselect_all_button->set_flat(true); import_deselect_all_button->set_text(TTR("Deselect All")); - import_deselect_all_button->set_tooltip(TTR("Deselect all Theme items.")); + import_deselect_all_button->set_tooltip_text(TTR("Deselect all Theme items.")); import_buttons->add_child(import_deselect_all_button); import_deselect_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_items_pressed)); @@ -1202,7 +1203,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() { _update_edit_types(); import_default_theme_items->set_edited_theme(edited_theme); - import_default_theme_items->set_base_theme(Theme::get_default()); + import_default_theme_items->set_base_theme(ThemeDB::get_singleton()->get_default_theme()); import_default_theme_items->reset_item_tree(); import_editor_theme_items->set_edited_theme(edited_theme); @@ -1214,7 +1215,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() { } void ThemeItemEditorDialog::_update_edit_types() { - Ref<Theme> base_theme = Theme::get_default(); + Ref<Theme> base_theme = ThemeDB::get_singleton()->get_default_theme(); List<StringName> theme_types; edited_theme->get_type_list(&theme_types); @@ -1630,7 +1631,7 @@ void ThemeItemEditorDialog::_remove_class_items() { Theme::DataType data_type = (Theme::DataType)dt; names.clear(); - Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_theme_item_list(data_type, edited_item_type, &names); for (const StringName &E : names) { if (new_snapshot->has_theme_item_nocheck(data_type, E, edited_item_type)) { new_snapshot->clear_theme_item(data_type, E, edited_item_type); @@ -1668,7 +1669,7 @@ void ThemeItemEditorDialog::_remove_custom_items() { names.clear(); new_snapshot->get_theme_item_list(data_type, edited_item_type, &names); for (const StringName &E : names) { - if (!Theme::get_default()->has_theme_item_nocheck(data_type, E, edited_item_type)) { + if (!ThemeDB::get_singleton()->get_default_theme()->has_theme_item_nocheck(data_type, E, edited_item_type)) { new_snapshot->clear_theme_item(data_type, E, edited_item_type); if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) { @@ -1954,42 +1955,42 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito edit_items_toolbar->add_child(edit_items_toolbar_add_label); edit_items_add_color = memnew(Button); - edit_items_add_color->set_tooltip(TTR("Add Color Item")); + edit_items_add_color->set_tooltip_text(TTR("Add Color Item")); edit_items_add_color->set_flat(true); edit_items_add_color->set_disabled(true); edit_items_toolbar->add_child(edit_items_add_color); edit_items_add_color->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_COLOR)); edit_items_add_constant = memnew(Button); - edit_items_add_constant->set_tooltip(TTR("Add Constant Item")); + edit_items_add_constant->set_tooltip_text(TTR("Add Constant Item")); edit_items_add_constant->set_flat(true); edit_items_add_constant->set_disabled(true); edit_items_toolbar->add_child(edit_items_add_constant); edit_items_add_constant->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_CONSTANT)); edit_items_add_font = memnew(Button); - edit_items_add_font->set_tooltip(TTR("Add Font Item")); + edit_items_add_font->set_tooltip_text(TTR("Add Font Item")); edit_items_add_font->set_flat(true); edit_items_add_font->set_disabled(true); edit_items_toolbar->add_child(edit_items_add_font); edit_items_add_font->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT)); edit_items_add_font_size = memnew(Button); - edit_items_add_font_size->set_tooltip(TTR("Add Font Size Item")); + edit_items_add_font_size->set_tooltip_text(TTR("Add Font Size Item")); edit_items_add_font_size->set_flat(true); edit_items_add_font_size->set_disabled(true); edit_items_toolbar->add_child(edit_items_add_font_size); edit_items_add_font_size->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT_SIZE)); edit_items_add_icon = memnew(Button); - edit_items_add_icon->set_tooltip(TTR("Add Icon Item")); + edit_items_add_icon->set_tooltip_text(TTR("Add Icon Item")); edit_items_add_icon->set_flat(true); edit_items_add_icon->set_disabled(true); edit_items_toolbar->add_child(edit_items_add_icon); edit_items_add_icon->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_ICON)); edit_items_add_stylebox = memnew(Button); - edit_items_add_stylebox->set_tooltip(TTR("Add StyleBox Item")); + edit_items_add_stylebox->set_tooltip_text(TTR("Add StyleBox Item")); edit_items_add_stylebox->set_flat(true); edit_items_add_stylebox->set_disabled(true); edit_items_toolbar->add_child(edit_items_add_stylebox); @@ -2002,21 +2003,21 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito edit_items_toolbar->add_child(edit_items_toolbar_remove_label); edit_items_remove_class = memnew(Button); - edit_items_remove_class->set_tooltip(TTR("Remove Class Items")); + edit_items_remove_class->set_tooltip_text(TTR("Remove Class Items")); edit_items_remove_class->set_flat(true); edit_items_remove_class->set_disabled(true); edit_items_toolbar->add_child(edit_items_remove_class); edit_items_remove_class->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_class_items)); edit_items_remove_custom = memnew(Button); - edit_items_remove_custom->set_tooltip(TTR("Remove Custom Items")); + edit_items_remove_custom->set_tooltip_text(TTR("Remove Custom Items")); edit_items_remove_custom->set_flat(true); edit_items_remove_custom->set_disabled(true); edit_items_toolbar->add_child(edit_items_remove_custom); edit_items_remove_custom->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items)); edit_items_remove_all = memnew(Button); - edit_items_remove_all->set_tooltip(TTR("Remove All Items")); + edit_items_remove_all->set_tooltip_text(TTR("Remove All Items")); edit_items_remove_all->set_flat(true); edit_items_remove_all->set_disabled(true); edit_items_toolbar->add_child(edit_items_remove_all); @@ -2129,7 +2130,7 @@ void ThemeTypeDialog::_update_add_type_options(const String &p_filter) { add_type_options->clear(); List<StringName> names; - Theme::get_default()->get_type_list(&names); + ThemeDB::get_singleton()->get_default_theme()->get_type_list(&names); if (include_own_types) { edited_theme->get_type_list(&names); } @@ -2370,7 +2371,7 @@ HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, v default_type = edited_theme->get_type_variation_base(p_type_name); } - (Theme::get_default().operator->()->*get_list_func)(default_type, &names); + (ThemeDB::get_singleton()->get_default_theme().operator->()->*get_list_func)(default_type, &names); names.sort_custom<StringName::AlphCompare>(); for (const StringName &E : names) { items[E] = false; @@ -2412,7 +2413,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_ item_name->set_h_size_flags(SIZE_EXPAND_FILL); item_name->set_clip_text(true); item_name->set_text(p_item_name); - item_name->set_tooltip(p_item_name); + item_name->set_tooltip_text(p_item_name); item_name_container->add_child(item_name); if (p_editable) { @@ -2425,21 +2426,21 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_ Button *item_rename_button = memnew(Button); item_rename_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons"))); - item_rename_button->set_tooltip(TTR("Rename Item")); + item_rename_button->set_tooltip_text(TTR("Rename Item")); item_rename_button->set_flat(true); item_name_container->add_child(item_rename_button); item_rename_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_cbk).bind(p_data_type, p_item_name, item_name_container)); Button *item_remove_button = memnew(Button); item_remove_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - item_remove_button->set_tooltip(TTR("Remove Item")); + item_remove_button->set_tooltip_text(TTR("Remove Item")); item_remove_button->set_flat(true); item_name_container->add_child(item_remove_button); item_remove_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_remove_cbk).bind(p_data_type, p_item_name)); Button *item_rename_confirm_button = memnew(Button); item_rename_confirm_button->set_icon(get_theme_icon(SNAME("ImportCheck"), SNAME("EditorIcons"))); - item_rename_confirm_button->set_tooltip(TTR("Confirm Item Rename")); + item_rename_confirm_button->set_tooltip_text(TTR("Confirm Item Rename")); item_rename_confirm_button->set_flat(true); item_name_container->add_child(item_rename_confirm_button); item_rename_confirm_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_confirmed).bind(p_data_type, p_item_name, item_name_container)); @@ -2447,7 +2448,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_ Button *item_rename_cancel_button = memnew(Button); item_rename_cancel_button->set_icon(get_theme_icon(SNAME("ImportFail"), SNAME("EditorIcons"))); - item_rename_cancel_button->set_tooltip(TTR("Cancel Item Rename")); + item_rename_cancel_button->set_tooltip_text(TTR("Cancel Item Rename")); item_rename_cancel_button->set_flat(true); item_name_container->add_child(item_rename_cancel_button); item_rename_cancel_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_canceled).bind(p_data_type, p_item_name, item_name_container)); @@ -2457,7 +2458,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_ Button *item_override_button = memnew(Button); item_override_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); - item_override_button->set_tooltip(TTR("Override Item")); + item_override_button->set_tooltip_text(TTR("Override Item")); item_override_button->set_flat(true); item_name_container->add_child(item_override_button); item_override_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_override_cbk).bind(p_data_type, p_item_name)); @@ -2496,7 +2497,7 @@ void ThemeTypeEditor::_update_type_items() { item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed).bind(E.key)); item_editor->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(item_editor->get_picker())); } else { - item_editor->set_pick_color(Theme::get_default()->get_color(E.key, edited_type)); + item_editor->set_pick_color(ThemeDB::get_singleton()->get_default_theme()->get_color(E.key, edited_type)); item_editor->set_disabled(true); } @@ -2529,7 +2530,7 @@ void ThemeTypeEditor::_update_type_items() { item_editor->set_value(edited_theme->get_constant(E.key, edited_type)); item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed).bind(E.key)); } else { - item_editor->set_value(Theme::get_default()->get_constant(E.key, edited_type)); + item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_constant(E.key, edited_type)); item_editor->set_editable(false); } @@ -2563,8 +2564,8 @@ void ThemeTypeEditor::_update_type_items() { item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed).bind(E.key)); } else { - if (Theme::get_default()->has_font(E.key, edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_font(E.key, edited_type)); + if (ThemeDB::get_singleton()->get_default_theme()->has_font(E.key, edited_type)) { + item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_font(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref<Resource>()); } @@ -2600,7 +2601,7 @@ void ThemeTypeEditor::_update_type_items() { item_editor->set_value(edited_theme->get_font_size(E.key, edited_type)); item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed).bind(E.key)); } else { - item_editor->set_value(Theme::get_default()->get_font_size(E.key, edited_type)); + item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_font_size(E.key, edited_type)); item_editor->set_editable(false); } @@ -2634,8 +2635,8 @@ void ThemeTypeEditor::_update_type_items() { item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed).bind(E.key)); } else { - if (Theme::get_default()->has_icon(E.key, edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key, edited_type)); + if (ThemeDB::get_singleton()->get_default_theme()->has_icon(E.key, edited_type)) { + item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_icon(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref<Resource>()); } @@ -2667,7 +2668,7 @@ void ThemeTypeEditor::_update_type_items() { pin_leader_button->set_toggle_mode(true); pin_leader_button->set_pressed(true); pin_leader_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons"))); - pin_leader_button->set_tooltip(TTR("Unpin this StyleBox as a main style.")); + pin_leader_button->set_tooltip_text(TTR("Unpin this StyleBox as a main style.")); item_control->add_child(pin_leader_button); pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_unpin_leader_button_pressed)); @@ -2710,12 +2711,12 @@ void ThemeTypeEditor::_update_type_items() { pin_leader_button->set_flat(true); pin_leader_button->set_toggle_mode(true); pin_leader_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons"))); - pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type.")); + pin_leader_button->set_tooltip_text(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type.")); item_control->add_child(pin_leader_button); pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed).bind(item_editor, E.key)); } else { - if (Theme::get_default()->has_stylebox(E.key, edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key, edited_type)); + if (ThemeDB::get_singleton()->get_default_theme()->has_stylebox(E.key, edited_type)) { + item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref<Resource>()); } @@ -2770,55 +2771,55 @@ void ThemeTypeEditor::_add_default_type_items() { { names.clear(); - Theme::get_default()->get_icon_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_icon_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_icon(E, edited_type)) { - new_snapshot->set_icon(E, edited_type, Theme::get_default()->get_icon(E, edited_type)); + new_snapshot->set_icon(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_icon(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_stylebox_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_stylebox(E, edited_type)) { - new_snapshot->set_stylebox(E, edited_type, Theme::get_default()->get_stylebox(E, edited_type)); + new_snapshot->set_stylebox(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_font_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_font_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_font(E, edited_type)) { - new_snapshot->set_font(E, edited_type, Theme::get_default()->get_font(E, edited_type)); + new_snapshot->set_font(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_font_size_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_font_size(E, edited_type)) { - new_snapshot->set_font_size(E, edited_type, Theme::get_default()->get_font_size(E, edited_type)); + new_snapshot->set_font_size(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_color_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_color_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_color(E, edited_type)) { - new_snapshot->set_color(E, edited_type, Theme::get_default()->get_color(E, edited_type)); + new_snapshot->set_color(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_constant_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_constant_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_constant(E, edited_type)) { - new_snapshot->set_constant(E, edited_type, Theme::get_default()->get_constant(E, edited_type)); + new_snapshot->set_constant(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(E, edited_type)); } } } @@ -2895,11 +2896,11 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { switch (p_data_type) { case Theme::DATA_TYPE_COLOR: { - ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type)); + ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(p_item_name, edited_type)); ur->add_undo_method(*edited_theme, "clear_color", p_item_name, edited_type); } break; case Theme::DATA_TYPE_CONSTANT: { - ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type)); + ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(p_item_name, edited_type)); ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, edited_type); } break; case Theme::DATA_TYPE_FONT: { @@ -2907,7 +2908,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type); } break; case Theme::DATA_TYPE_FONT_SIZE: { - ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type)); + ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(p_item_name, edited_type)); ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, edited_type); } break; case Theme::DATA_TYPE_ICON: { @@ -3387,7 +3388,7 @@ ThemeTypeEditor::ThemeTypeEditor() { theme_type_list->connect("item_selected", callable_mp(this, &ThemeTypeEditor::_list_type_selected)); add_type_button = memnew(Button); - add_type_button->set_tooltip(TTR("Add a type from a list of available types or create a new one.")); + add_type_button->set_tooltip_text(TTR("Add a type from a list of available types or create a new one.")); type_list_hb->add_child(add_type_button); add_type_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_button_cbk)); @@ -3397,7 +3398,7 @@ ThemeTypeEditor::ThemeTypeEditor() { show_default_items_button = memnew(CheckButton); show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL); show_default_items_button->set_text(TTR("Show Default")); - show_default_items_button->set_tooltip(TTR("Show default type items alongside items that have been overridden.")); + show_default_items_button->set_tooltip_text(TTR("Show default type items alongside items that have been overridden.")); show_default_items_button->set_pressed(true); type_controls->add_child(show_default_items_button); show_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_update_type_items)); @@ -3405,7 +3406,7 @@ ThemeTypeEditor::ThemeTypeEditor() { Button *add_default_items_button = memnew(Button); add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL); add_default_items_button->set_text(TTR("Override All")); - add_default_items_button->set_tooltip(TTR("Override all default type items.")); + add_default_items_button->set_tooltip_text(TTR("Override all default type items.")); type_controls->add_child(add_default_items_button); add_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_default_type_items)); @@ -3452,7 +3453,7 @@ ThemeTypeEditor::ThemeTypeEditor() { type_variation_edit->connect("focus_exited", callable_mp(this, &ThemeTypeEditor::_update_type_items)); type_variation_button = memnew(Button); type_variation_hb->add_child(type_variation_button); - type_variation_button->set_tooltip(TTR("Select the variation base type from a list of available types.")); + type_variation_button->set_tooltip_text(TTR("Select the variation base type from a list of available types.")); type_variation_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_variation_cbk)); type_variation_locked = memnew(Label); @@ -3633,7 +3634,7 @@ ThemeEditor::ThemeEditor() { Button *theme_edit_button = memnew(Button); theme_edit_button->set_text(TTR("Manage Items...")); - theme_edit_button->set_tooltip(TTR("Add, remove, organize and import Theme items.")); + theme_edit_button->set_tooltip_text(TTR("Add, remove, organize and import Theme items.")); theme_edit_button->set_flat(true); theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk)); top_menu->add_child(theme_edit_button); diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index b5c6c6d651..8cc96201e7 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -40,6 +40,7 @@ #include "scene/gui/color_picker.h" #include "scene/gui/progress_bar.h" #include "scene/resources/packed_scene.h" +#include "scene/theme/theme_db.h" constexpr double REFRESH_TIMER = 1.5; @@ -55,7 +56,7 @@ void ThemeEditorPreview::add_preview_overlay(Control *p_overlay) { void ThemeEditorPreview::_propagate_redraw(Control *p_at) { p_at->notification(NOTIFICATION_THEME_CHANGED); p_at->update_minimum_size(); - p_at->update(); + p_at->queue_redraw(); for (int i = 0; i < p_at->get_child_count(); i++) { Control *a = Object::cast_to<Control>(p_at->get_child(i)); if (a) { @@ -173,7 +174,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even if (mm.is_valid()) { Vector2 mp = preview_content->get_local_mouse_position(); hovered_control = _find_hovered_control(preview_content, mp); - picker_overlay->update(); + picker_overlay->queue_redraw(); } // Forward input to the scroll container underneath to allow scrolling. @@ -182,7 +183,7 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even void ThemeEditorPreview::_reset_picker_overlay() { hovered_control = nullptr; - picker_overlay->update(); + picker_overlay->queue_redraw(); } void ThemeEditorPreview::_notification(int p_what) { @@ -227,7 +228,7 @@ ThemeEditorPreview::ThemeEditorPreview() { preview_toolbar->add_child(picker_button); picker_button->set_flat(true); picker_button->set_toggle_mode(true); - picker_button->set_tooltip(TTR("Toggle the control picker, allowing to visually select control types for edit.")); + picker_button->set_tooltip_text(TTR("Toggle the control picker, allowing to visually select control types for edit.")); picker_button->connect("pressed", callable_mp(this, &ThemeEditorPreview::_picker_button_cbk)); MarginContainer *preview_body = memnew(MarginContainer); @@ -240,7 +241,7 @@ ThemeEditorPreview::ThemeEditorPreview() { MarginContainer *preview_root = memnew(MarginContainer); preview_container->add_child(preview_root); - preview_root->set_theme(Theme::get_default()); + preview_root->set_theme(ThemeDB::get_singleton()->get_default_theme()); preview_root->set_clip_contents(true); preview_root->set_custom_minimum_size(Size2(450, 0) * EDSCALE); preview_root->set_v_size_flags(SIZE_EXPAND_FILL); @@ -517,7 +518,7 @@ SceneThemeEditorPreview::SceneThemeEditorPreview() { reload_scene_button = memnew(Button); reload_scene_button->set_flat(true); - reload_scene_button->set_tooltip(TTR("Reload the scene to reflect its most actual state.")); + reload_scene_button->set_tooltip_text(TTR("Reload the scene to reflect its most actual state.")); preview_toolbar->add_child(reload_scene_button); reload_scene_button->connect("pressed", callable_mp(this, &SceneThemeEditorPreview::_reload_scene)); } diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 54ba28833c..5f0576a675 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -160,7 +160,7 @@ void TileAtlasView::_center_view() { } void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) { - base_tiles_root_control->set_tooltip(""); + base_tiles_root_control->set_tooltip_text(""); Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { @@ -169,7 +169,7 @@ void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_ if (coords != TileSetSource::INVALID_ATLAS_COORDS) { coords = tile_set_atlas_source->get_tile_at_coords(coords); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { - base_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords)); + base_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords)); } } } @@ -319,7 +319,7 @@ void TileAtlasView::_draw_base_tiles_shape_grid() { } void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) { - alternative_tiles_root_control->set_tooltip(""); + alternative_tiles_root_control->set_tooltip_text(""); Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { @@ -328,7 +328,7 @@ void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEve Vector2i coords = Vector2i(coords3.x, coords3.y); int alternative_id = coords3.z; if (coords != TileSetSource::INVALID_ATLAS_COORDS && alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) { - alternative_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id)); + alternative_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id)); } } } @@ -404,12 +404,12 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_ _update_zoom_and_panning(); // Update. - base_tiles_draw->update(); - base_tiles_texture_grid->update(); - base_tiles_shape_grid->update(); - alternatives_draw->update(); - background_left->update(); - background_right->update(); + base_tiles_draw->queue_redraw(); + base_tiles_texture_grid->queue_redraw(); + base_tiles_shape_grid->queue_redraw(); + alternatives_draw->queue_redraw(); + background_left->queue_redraw(); + background_right->queue_redraw(); } float TileAtlasView::get_zoom() const { @@ -493,13 +493,13 @@ Rect2i TileAtlasView::get_alternative_tile_rect(const Vector2i p_coords, int p_a return alternative_tiles_rect_cache[p_coords][p_alternative_tile]; } -void TileAtlasView::update() { - base_tiles_draw->update(); - base_tiles_texture_grid->update(); - base_tiles_shape_grid->update(); - alternatives_draw->update(); - background_left->update(); - background_right->update(); +void TileAtlasView::queue_redraw() { + base_tiles_draw->queue_redraw(); + base_tiles_texture_grid->queue_redraw(); + base_tiles_shape_grid->queue_redraw(); + alternatives_draw->queue_redraw(); + background_left->queue_redraw(); + background_right->queue_redraw(); } void TileAtlasView::_notification(int p_what) { @@ -542,7 +542,7 @@ TileAtlasView::TileAtlasView() { button_center_view->connect("pressed", callable_mp(this, &TileAtlasView::_center_view)); button_center_view->set_flat(true); button_center_view->set_disabled(true); - button_center_view->set_tooltip(TTR("Center View")); + button_center_view->set_tooltip_text(TTR("Center View")); add_child(button_center_view); panner.instantiate(); diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h index 1c0b622bb1..c710eac107 100644 --- a/editor/plugins/tiles/tile_atlas_view.h +++ b/editor/plugins/tiles/tile_atlas_view.h @@ -154,8 +154,8 @@ public: p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS); }; - // Update everything. - void update(); + // Redraw everything. + void queue_redraw(); TileAtlasView(); }; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index b44b6fcc53..1bfbd342c2 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -240,12 +240,12 @@ void GenericTilePolygonEditor::_base_control_draw() { void GenericTilePolygonEditor::_center_view() { panning = Vector2(); - base_control->update(); + base_control->queue_redraw(); button_center_view->set_disabled(true); } void GenericTilePolygonEditor::_zoom_changed() { - base_control->update(); + base_control->queue_redraw(); } void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { @@ -266,26 +266,26 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { polygon.write[i] = polygon[i] * tile_set->get_tile_size(); } undo_redo->add_do_method(this, "add_polygon", polygon); - undo_redo->add_do_method(base_control, "update"); + undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); undo_redo->add_undo_method(this, "clear_polygons"); for (unsigned int i = 0; i < polygons.size(); i++) { undo_redo->add_undo_method(this, "add_polygon", polygons[i]); } - undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); undo_redo->commit_action(true); } break; case CLEAR_TILE: { undo_redo->create_action(TTR("Clear Polygons")); undo_redo->add_do_method(this, "clear_polygons"); - undo_redo->add_do_method(base_control, "update"); + undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); undo_redo->add_undo_method(this, "clear_polygons"); for (unsigned int i = 0; i < polygons.size(); i++) { undo_redo->add_undo_method(this, "add_polygon", polygons[i]); } - undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); undo_redo->commit_action(true); } break; @@ -318,12 +318,12 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { } undo_redo->add_do_method(this, "set_polygon", i, new_polygon); } - undo_redo->add_do_method(base_control, "update"); + undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); for (unsigned int i = 0; i < polygons.size(); i++) { undo_redo->add_undo_method(this, "set_polygon", polygons[i]); } - undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); undo_redo->commit_action(true); } break; @@ -491,9 +491,9 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) undo_redo->add_do_method(this, "clear_polygons"); } undo_redo->add_do_method(this, "add_polygon", in_creation_polygon); - undo_redo->add_do_method(base_control, "update"); + undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "remove_polygon", added); - undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->commit_action(false); emit_signal(SNAME("polygons_changed")); } else { @@ -539,8 +539,8 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]); undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon); } - undo_redo->add_do_method(base_control, "update"); - undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_do_method(base_control, "queue_redraw"); + undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->commit_action(false); emit_signal(SNAME("polygons_changed")); } @@ -549,9 +549,9 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) if (drag_type == DRAG_TYPE_DRAG_POINT) { undo_redo->create_action(TTR("Edit Polygons")); undo_redo->add_do_method(this, "set_polygon", drag_polygon_index, polygons[drag_polygon_index]); - undo_redo->add_do_method(base_control, "update"); + undo_redo->add_do_method(base_control, "queue_redraw"); undo_redo->add_undo_method(this, "set_polygon", drag_polygon_index, drag_old_polygon); - undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->commit_action(false); emit_signal(SNAME("polygons_changed")); } else if (drag_type == DRAG_TYPE_CREATE_POINT) { @@ -586,8 +586,8 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]); undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon); } - undo_redo->add_do_method(base_control, "update"); - undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_do_method(base_control, "queue_redraw"); + undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->commit_action(false); emit_signal(SNAME("polygons_changed")); } else { @@ -611,7 +611,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) } } - base_control->update(); + base_control->queue_redraw(); } void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) { @@ -659,7 +659,7 @@ void GenericTilePolygonEditor::set_background(Ref<Texture2D> p_texture, Rect2 p_ background_v_flip = p_flip_v; background_transpose = p_transpose; background_modulate = p_modulate; - base_control->update(); + base_control->queue_redraw(); } int GenericTilePolygonEditor::get_polygon_count() { @@ -672,13 +672,13 @@ int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index) if (p_index < 0) { polygons.push_back(p_polygon); - base_control->update(); + base_control->queue_redraw(); button_edit->set_pressed(true); return polygons.size() - 1; } else { polygons.insert(p_index, p_polygon); button_edit->set_pressed(true); - base_control->update(); + base_control->queue_redraw(); return p_index; } } @@ -690,12 +690,12 @@ void GenericTilePolygonEditor::remove_polygon(int p_index) { if (polygons.size() == 0) { button_create->set_pressed(true); } - base_control->update(); + base_control->queue_redraw(); } void GenericTilePolygonEditor::clear_polygons() { polygons.clear(); - base_control->update(); + base_control->queue_redraw(); } void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p_polygon) { @@ -703,7 +703,7 @@ void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p ERR_FAIL_COND(p_polygon.size() < 3); polygons[p_polygon_index] = p_polygon; button_edit->set_pressed(true); - base_control->update(); + base_control->queue_redraw(); } Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) { @@ -713,7 +713,7 @@ Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) { void GenericTilePolygonEditor::set_polygons_color(Color p_color) { polygon_color = p_color; - base_control->update(); + base_control->queue_redraw(); } void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon_mode) { @@ -764,21 +764,21 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { button_create->set_toggle_mode(true); button_create->set_button_group(tools_button_group); button_create->set_pressed(true); - button_create->set_tooltip(TTR("Add polygon tool")); + button_create->set_tooltip_text(TTR("Add polygon tool")); toolbar->add_child(button_create); button_edit = memnew(Button); button_edit->set_flat(true); button_edit->set_toggle_mode(true); button_edit->set_button_group(tools_button_group); - button_edit->set_tooltip(TTR("Edit points tool")); + button_edit->set_tooltip_text(TTR("Edit points tool")); toolbar->add_child(button_edit); button_delete = memnew(Button); button_delete->set_flat(true); button_delete->set_toggle_mode(true); button_delete->set_button_group(tools_button_group); - button_delete->set_tooltip(TTR("Delete points tool")); + button_delete->set_tooltip_text(TTR("Delete points tool")); toolbar->add_child(button_delete); button_advanced_menu = memnew(MenuButton); @@ -801,7 +801,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { button_pixel_snap->set_flat(true); button_pixel_snap->set_toggle_mode(true); button_pixel_snap->set_pressed(true); - button_pixel_snap->set_tooltip(TTR("Snap to half-pixel")); + button_pixel_snap->set_tooltip_text(TTR("Snap to half-pixel")); toolbar->add_child(button_pixel_snap); Control *root = memnew(Control); @@ -1161,7 +1161,7 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p property_editor->set_label(p_label); } property_editor->connect("property_changed", callable_mp(this, &TileDataDefaultEditor::_property_value_changed).unbind(1)); - property_editor->set_tooltip(p_property); + property_editor->set_tooltip_text(p_property); property_editor->update_property(); add_child(property_editor); } @@ -1371,7 +1371,7 @@ void TileDataCollisionEditor::_polygons_changed() { one_way_property_editor->set_label(one_way_property); one_way_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1)); one_way_property_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected)); - one_way_property_editor->set_tooltip(one_way_property_editor->get_edited_property()); + one_way_property_editor->set_tooltip_text(one_way_property_editor->get_edited_property()); one_way_property_editor->update_property(); add_child(one_way_property_editor); property_editors[one_way_property] = one_way_property_editor; @@ -1383,7 +1383,7 @@ void TileDataCollisionEditor::_polygons_changed() { one_way_margin_property_editor->set_label(one_way_margin_property); one_way_margin_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1)); one_way_margin_property_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected)); - one_way_margin_property_editor->set_tooltip(one_way_margin_property_editor->get_edited_property()); + one_way_margin_property_editor->set_tooltip_text(one_way_margin_property_editor->get_edited_property()); one_way_margin_property_editor->update_property(); add_child(one_way_margin_property_editor); property_editors[one_way_margin_property] = one_way_margin_property_editor; @@ -1544,7 +1544,7 @@ TileDataCollisionEditor::TileDataCollisionEditor() { linear_velocity_editor->set_label("linear_velocity"); linear_velocity_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1)); linear_velocity_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected)); - linear_velocity_editor->set_tooltip(linear_velocity_editor->get_edited_property()); + linear_velocity_editor->set_tooltip_text(linear_velocity_editor->get_edited_property()); linear_velocity_editor->update_property(); add_child(linear_velocity_editor); property_editors["linear_velocity"] = linear_velocity_editor; @@ -1554,7 +1554,7 @@ TileDataCollisionEditor::TileDataCollisionEditor() { angular_velocity_editor->set_label("angular_velocity"); angular_velocity_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1)); angular_velocity_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected)); - angular_velocity_editor->set_tooltip(angular_velocity_editor->get_edited_property()); + angular_velocity_editor->set_tooltip_text(angular_velocity_editor->get_edited_property()); angular_velocity_editor->update_property(); add_child(angular_velocity_editor); property_editors["angular_velocity"] = angular_velocity_editor; @@ -2602,7 +2602,7 @@ TileDataTerrainsEditor::TileDataTerrainsEditor() { terrain_set_property_editor->set_object_and_property(dummy_object, "terrain_set"); terrain_set_property_editor->set_label("Terrain Set"); terrain_set_property_editor->connect("property_changed", callable_mp(this, &TileDataTerrainsEditor::_property_value_changed).unbind(1)); - terrain_set_property_editor->set_tooltip(terrain_set_property_editor->get_edited_property()); + terrain_set_property_editor->set_tooltip_text(terrain_set_property_editor->get_edited_property()); add_child(terrain_set_property_editor); terrain_property_editor = memnew(EditorPropertyEnum); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 3f355a1ed2..ec406ef9ba 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -351,7 +351,7 @@ void TileMapEditorTilesPlugin::_update_atlas_view() { tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id); TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view); - tile_atlas_control->update(); + tile_atlas_control->queue_redraw(); } void TileMapEditorTilesPlugin::_update_scenes_collection_view() { @@ -1651,8 +1651,8 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern( } } _update_source_display(); - tile_atlas_control->update(); - alternative_tiles_control->update(); + tile_atlas_control->queue_redraw(); + alternative_tiles_control->queue_redraw(); } void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { @@ -1736,7 +1736,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_mouse_exited() { hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS); hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; tile_set_dragging_selection = false; - tile_atlas_control->update(); + tile_atlas_control->queue_redraw(); } void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) { @@ -1780,8 +1780,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - tile_atlas_control->update(); - alternative_tiles_control->update(); + tile_atlas_control->queue_redraw(); + alternative_tiles_control->queue_redraw(); } Ref<InputEventMouseButton> mb = p_event; @@ -1841,7 +1841,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven } tile_set_dragging_selection = false; } - tile_atlas_control->update(); + tile_atlas_control->queue_redraw(); } } @@ -1895,7 +1895,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_mouse_exited() { hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS); hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; tile_set_dragging_selection = false; - alternative_tiles_control->update(); + alternative_tiles_control->queue_redraw(); } void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) { @@ -1938,8 +1938,8 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - tile_atlas_control->update(); - alternative_tiles_control->update(); + tile_atlas_control->queue_redraw(); + alternative_tiles_control->queue_redraw(); } Ref<InputEventMouseButton> mb = p_event; @@ -1959,8 +1959,8 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_gui_input(const Ref<In } _update_selection_pattern_from_tileset_tiles_selection(); } - tile_atlas_control->update(); - alternative_tiles_control->update(); + tile_atlas_control->queue_redraw(); + alternative_tiles_control->queue_redraw(); } } @@ -2050,7 +2050,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { paint_tool_button->set_toggle_mode(true); paint_tool_button->set_button_group(tool_buttons_group); paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", Key::D)); - paint_tool_button->set_tooltip(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle.")); + paint_tool_button->set_tooltip_text(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle.")); paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(paint_tool_button); @@ -2091,7 +2091,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { picker_button->set_flat(true); picker_button->set_toggle_mode(true); picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P)); - picker_button->set_tooltip(TTR("Alternatively hold Ctrl with other tools to pick tile.")); + picker_button->set_tooltip_text(TTR("Alternatively hold Ctrl with other tools to pick tile.")); picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport)); tools_settings->add_child(picker_button); @@ -2100,7 +2100,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { erase_button->set_flat(true); erase_button->set_toggle_mode(true); erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E)); - erase_button->set_tooltip(TTR("Alternatively use RMB to erase tiles.")); + erase_button->set_tooltip_text(TTR("Alternatively use RMB to erase tiles.")); erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport)); tools_settings->add_child(erase_button); @@ -2119,13 +2119,13 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { random_tile_toggle = memnew(Button); random_tile_toggle->set_flat(true); random_tile_toggle->set_toggle_mode(true); - random_tile_toggle->set_tooltip(TTR("Place Random Tile")); + random_tile_toggle->set_tooltip_text(TTR("Place Random Tile")); random_tile_toggle->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled)); tools_settings->add_child(random_tile_toggle); // Random tile scattering. scatter_label = memnew(Label); - scatter_label->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile.")); + scatter_label->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile.")); scatter_label->set_text(TTR("Scattering:")); tools_settings->add_child(scatter_label); @@ -2133,7 +2133,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { scatter_spinbox->set_min(0.0); scatter_spinbox->set_max(1000); scatter_spinbox->set_step(0.001); - scatter_spinbox->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile.")); + scatter_spinbox->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile.")); scatter_spinbox->get_line_edit()->add_theme_constant_override("minimum_character_width", 4); scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapEditorTilesPlugin::_on_scattering_spinbox_changed)); tools_settings->add_child(scatter_spinbox); @@ -2178,7 +2178,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { source_sort_button = memnew(MenuButton); source_sort_button->set_flat(true); - source_sort_button->set_tooltip(TTR("Sort sources")); + source_sort_button->set_tooltip_text(TTR("Sort sources")); PopupMenu *p = source_sort_button->get_popup(); p->connect("id_pressed", callable_mp(this, &TileMapEditorTilesPlugin::_set_source_sort)); @@ -3618,7 +3618,7 @@ void TileMapEditor::_tab_changed(int p_tab_id) { } // Graphical update. - tabs_data[tabs_bar->get_current_tab()].panel->update(); + tabs_data[tabs_bar->get_current_tab()].panel->queue_redraw(); CanvasItemEditor::get_singleton()->update_viewport(); } @@ -4003,7 +4003,7 @@ TileMapEditor::TileMapEditor() { layers_selection_button = memnew(OptionButton); layers_selection_button->set_custom_minimum_size(Size2(200, 0)); layers_selection_button->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); - layers_selection_button->set_tooltip(TTR("TileMap Layers")); + layers_selection_button->set_tooltip_text(TTR("TileMap Layers")); layers_selection_button->connect("item_selected", callable_mp(this, &TileMapEditor::_layers_selection_item_selected)); tile_map_toolbar->add_child(layers_selection_button); @@ -4012,7 +4012,7 @@ TileMapEditor::TileMapEditor() { toggle_highlight_selected_layer_button->set_toggle_mode(true); toggle_highlight_selected_layer_button->set_pressed(true); toggle_highlight_selected_layer_button->connect("pressed", callable_mp(this, &TileMapEditor::_update_layers_selection)); - toggle_highlight_selected_layer_button->set_tooltip(TTR("Highlight Selected TileMap Layer")); + toggle_highlight_selected_layer_button->set_tooltip_text(TTR("Highlight Selected TileMap Layer")); tile_map_toolbar->add_child(toggle_highlight_selected_layer_button); tile_map_toolbar->add_child(memnew(VSeparator)); @@ -4021,7 +4021,7 @@ TileMapEditor::TileMapEditor() { toggle_grid_button = memnew(Button); toggle_grid_button->set_flat(true); toggle_grid_button->set_toggle_mode(true); - toggle_grid_button->set_tooltip(TTR("Toggle grid visibility.")); + toggle_grid_button->set_tooltip_text(TTR("Toggle grid visibility.")); toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditor::_on_grid_toggled)); tile_map_toolbar->add_child(toggle_grid_button); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 6bdf279537..2aea020902 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -527,7 +527,7 @@ void TileSetAtlasSourceEditor::_update_tile_id_label() { if (selection.size() == 1) { TileSelection selected = selection.front()->get(); tool_tile_id_label->set_text(vformat("%d, %s, %d", tile_set_atlas_source_id, selected.tile, selected.alternative)); - tool_tile_id_label->set_tooltip(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative)); + tool_tile_id_label->set_tooltip_text(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative)); tool_tile_id_label->show(); } else { tool_tile_id_label->hide(); @@ -624,8 +624,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor); tile_data_texture_offset_editor->hide(); tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset"); - tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors["texture_offset"] = tile_data_texture_offset_editor; } @@ -634,8 +634,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataDefaultEditor *tile_data_modulate_editor = memnew(TileDataDefaultEditor()); tile_data_modulate_editor->hide(); tile_data_modulate_editor->setup_property_editor(Variant::COLOR, "modulate", "", Color(1.0, 1.0, 1.0, 1.0)); - tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors["modulate"] = tile_data_modulate_editor; } @@ -644,8 +644,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataDefaultEditor *tile_data_z_index_editor = memnew(TileDataDefaultEditor()); tile_data_z_index_editor->hide(); tile_data_z_index_editor->setup_property_editor(Variant::INT, "z_index"); - tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors["z_index"] = tile_data_z_index_editor; } @@ -654,8 +654,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor); tile_data_y_sort_editor->hide(); tile_data_y_sort_editor->setup_property_editor(Variant::INT, "y_sort_origin"); - tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors["y_sort_origin"] = tile_data_y_sort_editor; } @@ -665,8 +665,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor()); tile_data_occlusion_shape_editor->hide(); tile_data_occlusion_shape_editor->set_occlusion_layer(i); - tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors[vformat("occlusion_layer_%d", i)] = tile_data_occlusion_shape_editor; } } @@ -680,8 +680,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { if (!tile_data_editors.has("terrain_set")) { TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor); tile_data_terrains_editor->hide(); - tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors["terrain_set"] = tile_data_terrains_editor; } @@ -691,8 +691,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataDefaultEditor *tile_data_probability_editor = memnew(TileDataDefaultEditor()); tile_data_probability_editor->hide(); tile_data_probability_editor->setup_property_editor(Variant::FLOAT, "probability", "", 1.0); - tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors["probability"] = tile_data_probability_editor; } @@ -704,8 +704,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataCollisionEditor *tile_data_collision_editor = memnew(TileDataCollisionEditor()); tile_data_collision_editor->hide(); tile_data_collision_editor->set_physics_layer(i); - tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors[vformat("physics_layer_%d", i)] = tile_data_collision_editor; } } @@ -722,8 +722,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataNavigationEditor *tile_data_navigation_editor = memnew(TileDataNavigationEditor()); tile_data_navigation_editor->hide(); tile_data_navigation_editor->set_navigation_layer(i); - tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors[vformat("navigation_layer_%d", i)] = tile_data_navigation_editor; } } @@ -744,8 +744,8 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { TileDataDefaultEditor *tile_data_custom_data_editor = memnew(TileDataDefaultEditor()); tile_data_custom_data_editor->hide(); tile_data_custom_data_editor->setup_property_editor(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), tile_set->get_custom_data_layer_name(i)); - tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); - tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw)); + tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw)); tile_data_editors[vformat("custom_data_%d", i)] = tile_data_custom_data_editor; } } @@ -872,10 +872,10 @@ void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() { void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() { tile_data_editors_popup->call_deferred(SNAME("hide")); _update_current_tile_data_editor(); - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); } void TileSetAtlasSourceEditor::_update_atlas_view() { @@ -923,11 +923,11 @@ void TileSetAtlasSourceEditor::_update_atlas_view() { tile_atlas_view->set_padding(Side::SIDE_RIGHT, texture_region_base_size_min); // Redraw everything. - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); + tile_atlas_view->queue_redraw(); // Synchronize atlas view. TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view); @@ -961,14 +961,14 @@ void TileSetAtlasSourceEditor::_update_toolbar() { void TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited() { hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS; - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - tile_atlas_view->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + tile_atlas_view->queue_redraw(); } void TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed() { - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); } void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) { @@ -983,11 +983,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven // Update only what's needed. tile_set_changed_needs_update = false; - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); + tile_atlas_view->queue_redraw(); return; } else { // Handle the event. @@ -1132,11 +1132,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven } // Redraw for the hovered tile. - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); + tile_atlas_view->queue_redraw(); return; } @@ -1283,11 +1283,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven // Left click released. _end_dragging(); } - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); + tile_atlas_view->queue_redraw(); return; } else if (mb->get_button_index() == MouseButton::RIGHT) { // Right click pressed. @@ -1298,11 +1298,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven // Right click released. _end_dragging(); } - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); + tile_atlas_view->queue_redraw(); return; } } @@ -1872,20 +1872,20 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In if (current_tile_data_editor) { current_tile_data_editor->forward_painting_alternatives_gui_input(tile_atlas_view, tile_set_atlas_source, p_event); } - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); + tile_atlas_view->queue_redraw(); return; } Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) { if (Vector2(drag_start_mouse_pos).distance_to(alternative_tiles_control->get_local_mouse_position()) > 5.0 * EDSCALE) { @@ -1942,19 +1942,19 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In drag_type = DRAG_TYPE_NONE; } } - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); } } void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() { hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE); - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); + tile_atlas_control->queue_redraw(); + tile_atlas_control_unscaled->queue_redraw(); + alternative_tiles_control->queue_redraw(); + alternative_tiles_control_unscaled->queue_redraw(); } void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() { @@ -2446,7 +2446,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tool_setup_atlas_source_button->set_toggle_mode(true); tool_setup_atlas_source_button->set_pressed(true); tool_setup_atlas_source_button->set_button_group(tools_button_group); - tool_setup_atlas_source_button->set_tooltip(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing).")); + tool_setup_atlas_source_button->set_tooltip_text(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing).")); toolbox->add_child(tool_setup_atlas_source_button); tool_select_button = memnew(Button); @@ -2454,14 +2454,14 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tool_select_button->set_toggle_mode(true); tool_select_button->set_pressed(false); tool_select_button->set_button_group(tools_button_group); - tool_select_button->set_tooltip(TTR("Select tiles.")); + tool_select_button->set_tooltip_text(TTR("Select tiles.")); toolbox->add_child(tool_select_button); tool_paint_button = memnew(Button); tool_paint_button->set_flat(true); tool_paint_button->set_toggle_mode(true); tool_paint_button->set_button_group(tools_button_group); - tool_paint_button->set_tooltip(TTR("Paint properties.")); + tool_paint_button->set_tooltip_text(TTR("Paint properties.")); toolbox->add_child(tool_paint_button); // Tool settings. diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 8d04dd3121..dca17475e0 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -695,7 +695,7 @@ TileSetEditor::TileSetEditor() { source_sort_button = memnew(MenuButton); source_sort_button->set_flat(true); - source_sort_button->set_tooltip(TTR("Sort sources")); + source_sort_button->set_tooltip_text(TTR("Sort sources")); PopupMenu *p = source_sort_button->get_popup(); p->connect("id_pressed", callable_mp(this, &TileSetEditor::_set_source_sort)); diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 6db499f2c7..fba760d57f 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -30,25 +30,59 @@ #include "version_control_editor_plugin.h" -#include "core/object/script_language.h" +#include "core/config/project_settings.h" #include "core/os/keyboard.h" +#include "core/os/time.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/filesystem_dock.h" #include "scene/gui/separator.h" +#define CHECK_PLUGIN_INITIALIZED() \ + ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton(), "No VCS plugin is initialized. Select a Version Control Plugin from Project menu."); + VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr; void VersionControlEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog); + ClassDB::bind_method(D_METHOD("_initialize_vcs"), &VersionControlEditorPlugin::_initialize_vcs); + ClassDB::bind_method(D_METHOD("_set_credentials"), &VersionControlEditorPlugin::_set_credentials); + ClassDB::bind_method(D_METHOD("_update_set_up_warning"), &VersionControlEditorPlugin::_update_set_up_warning); + ClassDB::bind_method(D_METHOD("_commit"), &VersionControlEditorPlugin::_commit); + ClassDB::bind_method(D_METHOD("_refresh_stage_area"), &VersionControlEditorPlugin::_refresh_stage_area); + ClassDB::bind_method(D_METHOD("_move_all"), &VersionControlEditorPlugin::_move_all); + ClassDB::bind_method(D_METHOD("_load_diff"), &VersionControlEditorPlugin::_load_diff); + ClassDB::bind_method(D_METHOD("_display_diff"), &VersionControlEditorPlugin::_display_diff); + ClassDB::bind_method(D_METHOD("_item_activated"), &VersionControlEditorPlugin::_item_activated); + ClassDB::bind_method(D_METHOD("_update_branch_create_button"), &VersionControlEditorPlugin::_update_branch_create_button); + ClassDB::bind_method(D_METHOD("_update_remote_create_button"), &VersionControlEditorPlugin::_update_remote_create_button); + ClassDB::bind_method(D_METHOD("_update_commit_button"), &VersionControlEditorPlugin::_update_commit_button); + ClassDB::bind_method(D_METHOD("_refresh_branch_list"), &VersionControlEditorPlugin::_refresh_branch_list); + ClassDB::bind_method(D_METHOD("_set_commit_list_size"), &VersionControlEditorPlugin::_set_commit_list_size); + ClassDB::bind_method(D_METHOD("_refresh_commit_list"), &VersionControlEditorPlugin::_refresh_commit_list); + ClassDB::bind_method(D_METHOD("_refresh_remote_list"), &VersionControlEditorPlugin::_refresh_remote_list); + ClassDB::bind_method(D_METHOD("_ssh_public_key_selected"), &VersionControlEditorPlugin::_ssh_public_key_selected); + ClassDB::bind_method(D_METHOD("_ssh_private_key_selected"), &VersionControlEditorPlugin::_ssh_private_key_selected); + ClassDB::bind_method(D_METHOD("_commit_message_gui_input"), &VersionControlEditorPlugin::_commit_message_gui_input); + ClassDB::bind_method(D_METHOD("_cell_button_pressed"), &VersionControlEditorPlugin::_cell_button_pressed); + ClassDB::bind_method(D_METHOD("_discard_all"), &VersionControlEditorPlugin::_discard_all); + ClassDB::bind_method(D_METHOD("_create_branch"), &VersionControlEditorPlugin::_create_branch); + ClassDB::bind_method(D_METHOD("_create_remote"), &VersionControlEditorPlugin::_create_remote); + ClassDB::bind_method(D_METHOD("_remove_branch"), &VersionControlEditorPlugin::_remove_branch); + ClassDB::bind_method(D_METHOD("_remove_remote"), &VersionControlEditorPlugin::_remove_remote); + ClassDB::bind_method(D_METHOD("_branch_item_selected"), &VersionControlEditorPlugin::_branch_item_selected); + ClassDB::bind_method(D_METHOD("_remote_selected"), &VersionControlEditorPlugin::_remote_selected); + ClassDB::bind_method(D_METHOD("_fetch"), &VersionControlEditorPlugin::_fetch); + ClassDB::bind_method(D_METHOD("_pull"), &VersionControlEditorPlugin::_pull); + ClassDB::bind_method(D_METHOD("_push"), &VersionControlEditorPlugin::_push); + ClassDB::bind_method(D_METHOD("_extra_option_selected"), &VersionControlEditorPlugin::_extra_option_selected); + ClassDB::bind_method(D_METHOD("_update_extra_options"), &VersionControlEditorPlugin::_update_extra_options); + ClassDB::bind_method(D_METHOD("_popup_branch_remove_confirm"), &VersionControlEditorPlugin::_popup_branch_remove_confirm); + ClassDB::bind_method(D_METHOD("_popup_remote_remove_confirm"), &VersionControlEditorPlugin::_popup_remote_remove_confirm); + ClassDB::bind_method(D_METHOD("_popup_file_dialog"), &VersionControlEditorPlugin::_popup_file_dialog); - // Used to track the status of files in the staging area - BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW); - BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED); - BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED); - BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED); - BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE); + ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog); } void VersionControlEditorPlugin::_create_vcs_metadata_files() { @@ -56,21 +90,25 @@ void VersionControlEditorPlugin::_create_vcs_metadata_files() { EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(metadata_selection->get_selected()), dir); } -void VersionControlEditorPlugin::_selected_a_vcs(int p_id) { - List<StringName> available_addons = get_available_vcs_names(); - const StringName selected_vcs = set_up_choice->get_item_text(p_id); -} +void VersionControlEditorPlugin::_notification(int p_what) { + if (p_what == NOTIFICATION_READY) { + String installed_plugin = GLOBAL_DEF("editor/version_control/plugin_name", ""); + String project_path = GLOBAL_DEF("editor/version_control/project_path", OS::get_singleton()->get_resource_dir()); + project_path_input->set_text(project_path); + bool has_autoload_enable = GLOBAL_DEF("editor/version_control/autoload_on_startup", false); -void VersionControlEditorPlugin::_populate_available_vcs_names() { - static bool called = false; - - if (!called) { - List<StringName> available_addons = get_available_vcs_names(); - for (int i = 0; i < available_addons.size(); i++) { - set_up_choice->add_item(available_addons[i]); + if (installed_plugin != "" && has_autoload_enable) { + if (_load_plugin(installed_plugin, project_path)) { + _set_credentials(); + } } + } +} - called = true; +void VersionControlEditorPlugin::_populate_available_vcs_names() { + set_up_choice->clear(); + for (int i = 0; i < available_plugins.size(); i++) { + set_up_choice->add_item(available_plugins[i]); } } @@ -83,9 +121,8 @@ void VersionControlEditorPlugin::popup_vcs_metadata_dialog() { } void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) { - fetch_available_vcs_addon_names(); - List<StringName> available_addons = get_available_vcs_names(); - if (available_addons.size() >= 1) { + fetch_available_vcs_plugin_names(); + if (!available_plugins.is_empty()) { Size2 popup_size = Size2(400, 100); Size2 window_size = p_gui_base->get_viewport_rect().size; popup_size.x = MIN(window_size.x * 0.5, popup_size.x); @@ -95,213 +132,782 @@ void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_ba set_up_dialog->popup_centered_clamped(popup_size * EDSCALE); } else { - EditorNode::get_singleton()->show_warning(TTR("No VCS addons are available."), TTR("Error")); + // TODO: Give info to user on how to fix this error. + EditorNode::get_singleton()->show_warning(TTR("No VCS plugins are available in the project. Install a VCS plugin to use VCS integration features."), TTR("Error")); } } void VersionControlEditorPlugin::_initialize_vcs() { - register_editor(); - - ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active"); + ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active."); const int id = set_up_choice->get_selected_id(); - String selected_addon = set_up_choice->get_item_text(id); + String selected_plugin = set_up_choice->get_item_text(id); - String path = ScriptServer::get_global_class_path(selected_addon); - Ref<Script> script = ResourceLoader::load(path); + if (_load_plugin(selected_plugin, project_path_input->get_text())) { + ProjectSettings::get_singleton()->set("editor/version_control/autoload_on_startup", true); + ProjectSettings::get_singleton()->set("editor/version_control/plugin_name", selected_plugin); + ProjectSettings::get_singleton()->set("editor/version_control/project_path", project_path_input->get_text()); + ProjectSettings::get_singleton()->save(); + } +} - ERR_FAIL_COND_MSG(!script.is_valid(), "VCS Addon path is invalid"); +void VersionControlEditorPlugin::_set_vcs_ui_state(bool p_enabled) { + select_project_path_button->set_disabled(p_enabled); + set_up_dialog->get_ok_button()->set_disabled(!p_enabled); + project_path_input->set_editable(!p_enabled); + set_up_choice->set_disabled(p_enabled); + toggle_vcs_choice->set_pressed_no_signal(p_enabled); +} - EditorVCSInterface *vcs_interface = memnew(EditorVCSInterface); - ScriptInstance *addon_script_instance = script->instance_create(vcs_interface); +void VersionControlEditorPlugin::_set_credentials() { + CHECK_PLUGIN_INITIALIZED(); + + String username = set_up_username->get_text(); + String password = set_up_password->get_text(); + String ssh_public_key = set_up_ssh_public_key_path->get_text(); + String ssh_private_key = set_up_ssh_private_key_path->get_text(); + String ssh_passphrase = set_up_ssh_passphrase->get_text(); + + EditorVCSInterface::get_singleton()->set_credentials( + username, + password, + ssh_public_key, + ssh_private_key, + ssh_passphrase); + + EditorSettings::get_singleton()->set_setting("version_control/username", username); + EditorSettings::get_singleton()->set_setting("version_control/ssh_public_key_path", ssh_public_key); + EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key); +} - ERR_FAIL_COND_MSG(!addon_script_instance, "Failed to create addon script instance."); +bool VersionControlEditorPlugin::_load_plugin(String p_name, String p_project_path) { + Object *extension_instance = ClassDB::instantiate(p_name); + ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction."); - // The addon is attached as a script to the VCS interface as a proxy end-point - vcs_interface->set_script_and_instance(script, addon_script_instance); + EditorVCSInterface *vcs_plugin = Object::cast_to<EditorVCSInterface>(extension_instance); + ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat("Could not cast VCS extension instance to %s.", EditorVCSInterface::get_class_static())); - EditorVCSInterface::set_singleton(vcs_interface); - EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); + String res_dir = project_path_input->get_text(); - String res_dir = OS::get_singleton()->get_resource_dir(); + ERR_FAIL_COND_V_MSG(!vcs_plugin->initialize(res_dir), false, "Could not initialize " + p_name); - ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton()->initialize(res_dir), "VCS was not initialized"); + EditorVCSInterface::set_singleton(vcs_plugin); + + register_editor(); + EditorFileSystem::get_singleton()->connect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); _refresh_stage_area(); + _refresh_commit_list(); + _refresh_branch_list(); + _refresh_remote_list(); + + return true; } -void VersionControlEditorPlugin::_send_commit_msg() { - if (EditorVCSInterface::get_singleton()) { - if (staged_files_count == 0) { - commit_status->set_text(TTR("No files added to stage")); - return; +void VersionControlEditorPlugin::_update_set_up_warning(String p_new_text) { + bool empty_settings = set_up_username->get_text().strip_edges().is_empty() && + set_up_password->get_text().is_empty() && + set_up_ssh_public_key_path->get_text().strip_edges().is_empty() && + set_up_ssh_private_key_path->get_text().strip_edges().is_empty() && + set_up_ssh_passphrase->get_text().is_empty(); + + if (empty_settings) { + set_up_warning_text->add_theme_color_override(SNAME("font_color"), EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor"))); + set_up_warning_text->set_text(TTR("Remote settings are empty. VCS features that use the network may not work.")); + } else { + set_up_warning_text->set_text(""); + } +} + +void VersionControlEditorPlugin::_refresh_branch_list() { + CHECK_PLUGIN_INITIALIZED(); + + List<String> branch_list = EditorVCSInterface::get_singleton()->get_branch_list(); + branch_select->clear(); + + branch_select->set_disabled(branch_list.is_empty()); + + String current_branch = EditorVCSInterface::get_singleton()->get_current_branch_name(); + + for (int i = 0; i < branch_list.size(); i++) { + branch_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("VcsBranches"), SNAME("EditorIcons")), branch_list[i], i); + + if (branch_list[i] == current_branch) { + branch_select->select(i); } + } +} - EditorVCSInterface::get_singleton()->commit(commit_message->get_text()); +String VersionControlEditorPlugin::_get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const { + return vformat( + "%s %s", + Time::get_singleton()->get_datetime_string_from_unix_time(p_unix_timestamp + p_offset_minutes * 60, true), + Time::get_singleton()->get_offset_string_from_offset_minutes(p_offset_minutes)); +} - commit_message->set_text(""); - version_control_dock_button->set_pressed(false); - } else { - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu"); +void VersionControlEditorPlugin::_set_commit_list_size(int p_index) { + _refresh_commit_list(); +} + +void VersionControlEditorPlugin::_refresh_commit_list() { + CHECK_PLUGIN_INITIALIZED(); + + commit_list->get_root()->clear_children(); + + List<EditorVCSInterface::Commit> commit_info_list = EditorVCSInterface::get_singleton()->get_previous_commits(commit_list_size_button->get_selected_metadata()); + + for (List<EditorVCSInterface::Commit>::Element *e = commit_info_list.front(); e; e = e->next()) { + EditorVCSInterface::Commit commit = e->get(); + TreeItem *item = commit_list->create_item(); + + // Only display the first line of a commit message + int line_ending = commit.msg.find_char('\n'); + String commit_display_msg = commit.msg.substr(0, line_ending); + String commit_date_string = _get_date_string_from(commit.unix_timestamp, commit.offset_minutes); + + Dictionary meta_data; + meta_data[SNAME("commit_id")] = commit.id; + meta_data[SNAME("commit_title")] = commit_display_msg; + meta_data[SNAME("commit_subtitle")] = commit.msg.substr(line_ending).strip_edges(); + meta_data[SNAME("commit_unix_timestamp")] = commit.unix_timestamp; + meta_data[SNAME("commit_author")] = commit.author; + meta_data[SNAME("commit_date_string")] = commit_date_string; + + item->set_text(0, commit_display_msg); + item->set_text(1, commit.author.strip_edges()); + item->set_metadata(0, meta_data); + } +} + +void VersionControlEditorPlugin::_refresh_remote_list() { + CHECK_PLUGIN_INITIALIZED(); + + List<String> remotes = EditorVCSInterface::get_singleton()->get_remotes(); + + String current_remote = remote_select->get_selected_metadata(); + remote_select->clear(); + + remote_select->set_disabled(remotes.is_empty()); + + for (int i = 0; i < remotes.size(); i++) { + remote_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")), remotes[i], i); + remote_select->set_item_metadata(i, remotes[i]); + + if (remotes[i] == current_remote) { + remote_select->select(i); + } } +} + +void VersionControlEditorPlugin::_commit() { + CHECK_PLUGIN_INITIALIZED(); + + String msg = commit_message->get_text().strip_edges(); + + ERR_FAIL_COND_MSG(msg.is_empty(), "No commit message was provided."); + + EditorVCSInterface::get_singleton()->commit(msg); + + version_control_dock_button->set_pressed(false); + + commit_message->release_focus(); + commit_button->release_focus(); + commit_message->set_text(""); + + _refresh_stage_area(); + _refresh_commit_list(); + _refresh_branch_list(); + _clear_diff(); +} + +void VersionControlEditorPlugin::_branch_item_selected(int p_index) { + CHECK_PLUGIN_INITIALIZED(); + + String branch_name = branch_select->get_item_text(p_index); + EditorVCSInterface::get_singleton()->checkout_branch(branch_name); + + EditorFileSystem::get_singleton()->scan_changes(); + ScriptEditor::get_singleton()->reload_scripts(); - _update_commit_status(); + _refresh_branch_list(); + _refresh_commit_list(); _refresh_stage_area(); - _clear_file_diff(); + _clear_diff(); + + _update_opened_tabs(); +} + +void VersionControlEditorPlugin::_remote_selected(int p_index) { + _refresh_remote_list(); +} + +void VersionControlEditorPlugin::_ssh_public_key_selected(String p_path) { + set_up_ssh_public_key_path->set_text(p_path); +} + +void VersionControlEditorPlugin::_ssh_private_key_selected(String p_path) { + set_up_ssh_private_key_path->set_text(p_path); +} + +void VersionControlEditorPlugin::_popup_file_dialog(Variant p_file_dialog_variant) { + FileDialog *file_dialog = Object::cast_to<FileDialog>(p_file_dialog_variant); + ERR_FAIL_NULL(file_dialog); + + file_dialog->popup_centered_ratio(); +} + +void VersionControlEditorPlugin::_create_branch() { + CHECK_PLUGIN_INITIALIZED(); + + String new_branch_name = branch_create_name_input->get_text().strip_edges(); + + EditorVCSInterface::get_singleton()->create_branch(new_branch_name); + EditorVCSInterface::get_singleton()->checkout_branch(new_branch_name); + + branch_create_name_input->clear(); + _refresh_branch_list(); +} + +void VersionControlEditorPlugin::_create_remote() { + CHECK_PLUGIN_INITIALIZED(); + + String new_remote_name = remote_create_name_input->get_text().strip_edges(); + String new_remote_url = remote_create_url_input->get_text().strip_edges(); + + EditorVCSInterface::get_singleton()->create_remote(new_remote_name, new_remote_url); + + remote_create_name_input->clear(); + remote_create_url_input->clear(); + _refresh_remote_list(); +} + +void VersionControlEditorPlugin::_update_branch_create_button(String p_new_text) { + branch_create_ok->set_disabled(p_new_text.strip_edges().is_empty()); +} + +void VersionControlEditorPlugin::_update_remote_create_button(String p_new_text) { + remote_create_ok->set_disabled(p_new_text.strip_edges().is_empty()); +} + +int VersionControlEditorPlugin::_get_item_count(Tree *p_tree) { + if (!p_tree->get_root()) { + return 0; + } + return p_tree->get_root()->get_children().size(); } void VersionControlEditorPlugin::_refresh_stage_area() { - if (EditorVCSInterface::get_singleton()) { - staged_files_count = 0; - clear_stage_area(); - - Dictionary modified_file_paths = EditorVCSInterface::get_singleton()->get_modified_files_data(); - String file_path; - for (int i = 0; i < modified_file_paths.size(); i++) { - file_path = modified_file_paths.get_key_at_index(i); - TreeItem *found = stage_files->search_item_text(file_path, nullptr, true); - if (!found) { - ChangeType change_index = (ChangeType)(int)modified_file_paths.get_value_at_index(i); - String change_text = file_path + " (" + change_type_to_strings[change_index] + ")"; - Color &change_color = change_type_to_color[change_index]; - TreeItem *new_item = stage_files->create_item(stage_files->get_root()); - new_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - new_item->set_text(0, change_text); - new_item->set_metadata(0, file_path); - new_item->set_custom_color(0, change_color); - new_item->set_checked(0, true); - new_item->set_editable(0, true); - } else { - if (found->get_metadata(0) == diff_file_name->get_text()) { - _refresh_file_diff(); - } - } - commit_status->set_text(TTR("New changes detected")); + CHECK_PLUGIN_INITIALIZED(); + + staged_files->get_root()->clear_children(); + unstaged_files->get_root()->clear_children(); + + List<EditorVCSInterface::StatusFile> status_files = EditorVCSInterface::get_singleton()->get_modified_files_data(); + for (List<EditorVCSInterface::StatusFile>::Element *E = status_files.front(); E; E = E->next()) { + EditorVCSInterface::StatusFile sf = E->get(); + if (sf.area == EditorVCSInterface::TREE_AREA_STAGED) { + _add_new_item(staged_files, sf.file_path, sf.change_type); + } else if (sf.area == EditorVCSInterface::TREE_AREA_UNSTAGED) { + _add_new_item(unstaged_files, sf.file_path, sf.change_type); } + } + + staged_files->queue_redraw(); + unstaged_files->queue_redraw(); + + int total_changes = status_files.size(); + String commit_tab_title = TTR("Commit") + (total_changes > 0 ? " (" + itos(total_changes) + ")" : ""); + version_commit_dock->set_name(commit_tab_title); +} + +void VersionControlEditorPlugin::_discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change) { + CHECK_PLUGIN_INITIALIZED(); + + if (p_change == EditorVCSInterface::CHANGE_TYPE_NEW) { + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES); + dir->remove(p_file_path); } else { - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu."); + CHECK_PLUGIN_INITIALIZED(); + EditorVCSInterface::get_singleton()->discard_file(p_file_path); } + // FIXIT: The project.godot file shows weird behaviour + EditorFileSystem::get_singleton()->update_file(p_file_path); } -void VersionControlEditorPlugin::_stage_selected() { - if (!EditorVCSInterface::get_singleton()) { - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu"); - return; +void VersionControlEditorPlugin::_discard_all() { + TreeItem *file_entry = unstaged_files->get_root()->get_first_child(); + while (file_entry) { + String file_path = file_entry->get_meta(SNAME("file_path")); + EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)file_entry->get_meta(SNAME("change_type")); + _discard_file(file_path, change); + + file_entry = file_entry->get_next(); } + _refresh_stage_area(); +} - staged_files_count = 0; - TreeItem *root = stage_files->get_root(); - if (root) { - TreeItem *file_entry = root->get_first_child(); - while (file_entry) { - if (file_entry->is_checked(0)) { - EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0)); - file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"))); - staged_files_count++; - } else { - EditorVCSInterface::get_singleton()->unstage_file(file_entry->get_metadata(0)); - file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"))); - } +void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change) { + String change_text = p_file_path + " (" + change_type_to_strings[p_change] + ")"; - file_entry = file_entry->get_next(); - } + TreeItem *new_item = p_tree->create_item(); + new_item->set_text(0, change_text); + new_item->set_icon(0, change_type_to_icon[p_change]); + new_item->set_meta(SNAME("file_path"), p_file_path); + new_item->set_meta(SNAME("change_type"), p_change); + new_item->set_custom_color(0, change_type_to_color[p_change]); + + new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("File"), SNAME("EditorIcons")), BUTTON_TYPE_OPEN, false, TTR("Open in editor")); + if (p_tree == unstaged_files) { + new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")), BUTTON_TYPE_DISCARD, false, TTR("Discard changes")); } +} - _update_stage_status(); +void VersionControlEditorPlugin::_fetch() { + CHECK_PLUGIN_INITIALIZED(); + + EditorVCSInterface::get_singleton()->fetch(remote_select->get_selected_metadata()); + _refresh_branch_list(); } -void VersionControlEditorPlugin::_stage_all() { - if (!EditorVCSInterface::get_singleton()) { - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu"); - return; - } +void VersionControlEditorPlugin::_pull() { + CHECK_PLUGIN_INITIALIZED(); - staged_files_count = 0; - TreeItem *root = stage_files->get_root(); - if (root) { - TreeItem *file_entry = root->get_first_child(); - while (file_entry) { - EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0)); - file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"))); - file_entry->set_checked(0, true); - staged_files_count++; + EditorVCSInterface::get_singleton()->pull(remote_select->get_selected_metadata()); + _refresh_stage_area(); + _refresh_branch_list(); + _refresh_commit_list(); + _clear_diff(); + _update_opened_tabs(); +} + +void VersionControlEditorPlugin::_push() { + CHECK_PLUGIN_INITIALIZED(); + + EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), false); +} + +void VersionControlEditorPlugin::_force_push() { + CHECK_PLUGIN_INITIALIZED(); + + EditorVCSInterface::get_singleton()->push(remote_select->get_selected_metadata(), true); +} - file_entry = file_entry->get_next(); +void VersionControlEditorPlugin::_update_opened_tabs() { + Vector<EditorData::EditedScene> open_scenes = EditorNode::get_singleton()->get_editor_data().get_edited_scenes(); + for (int i = 0; i < open_scenes.size(); i++) { + if (open_scenes[i].root == NULL) { + continue; } + EditorNode::get_singleton()->reload_scene(open_scenes[i].path); } +} + +void VersionControlEditorPlugin::_move_all(Object *p_tree) { + Tree *tree = Object::cast_to<Tree>(p_tree); - _update_stage_status(); + TreeItem *file_entry = tree->get_root()->get_first_child(); + while (file_entry) { + _move_item(tree, file_entry); + + file_entry = file_entry->get_next(); + } + _refresh_stage_area(); } -void VersionControlEditorPlugin::_view_file_diff() { +void VersionControlEditorPlugin::_load_diff(Object *p_tree) { + CHECK_PLUGIN_INITIALIZED(); + version_control_dock_button->set_pressed(true); - String file_path = stage_files->get_selected()->get_metadata(0); + Tree *tree = Object::cast_to<Tree>(p_tree); + if (tree == staged_files) { + show_commit_diff_header = false; + String file_path = tree->get_selected()->get_meta(SNAME("file_path")); + diff_title->set_text(TTR("Staged Changes")); + diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_STAGED); + } else if (tree == unstaged_files) { + show_commit_diff_header = false; + String file_path = tree->get_selected()->get_meta(SNAME("file_path")); + diff_title->set_text(TTR("Unstaged Changes")); + diff_content = EditorVCSInterface::get_singleton()->get_diff(file_path, EditorVCSInterface::TREE_AREA_UNSTAGED); + } else if (tree == commit_list) { + show_commit_diff_header = true; + Dictionary meta_data = tree->get_selected()->get_metadata(0); + String commit_id = meta_data[SNAME("commit_id")]; + String commit_title = meta_data[SNAME("commit_title")]; + diff_title->set_text(commit_title); + diff_content = EditorVCSInterface::get_singleton()->get_diff(commit_id, EditorVCSInterface::TREE_AREA_COMMIT); + } + _display_diff(0); +} + +void VersionControlEditorPlugin::_clear_diff() { + diff->clear(); + diff_content.clear(); + diff_title->set_text(""); +} - _display_file_diff(file_path); +void VersionControlEditorPlugin::_item_activated(Object *p_tree) { + Tree *tree = Object::cast_to<Tree>(p_tree); + + _move_item(tree, tree->get_selected()); + _refresh_stage_area(); } -void VersionControlEditorPlugin::_display_file_diff(String p_file_path) { - TypedArray<Dictionary> diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path); +void VersionControlEditorPlugin::_move_item(Tree *p_tree, TreeItem *p_item) { + CHECK_PLUGIN_INITIALIZED(); + + if (p_tree == staged_files) { + EditorVCSInterface::get_singleton()->unstage_file(p_item->get_meta(SNAME("file_path"))); + } else { + EditorVCSInterface::get_singleton()->stage_file(p_item->get_meta(SNAME("file_path"))); + } +} - diff_file_name->set_text(p_file_path); +void VersionControlEditorPlugin::_cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index) { + TreeItem *item = Object::cast_to<TreeItem>(p_item); + String file_path = item->get_meta(SNAME("file_path")); + EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)item->get_meta(SNAME("change_type")); + + if (p_id == BUTTON_TYPE_OPEN && change != EditorVCSInterface::CHANGE_TYPE_DELETED) { + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (!dir->file_exists(file_path)) { + return; + } + + file_path = "res://" + file_path; + if (ResourceLoader::get_resource_type(file_path) == "PackedScene") { + EditorNode::get_singleton()->open_request(file_path); + } else if (file_path.ends_with(".gd")) { + EditorNode::get_singleton()->load_resource(file_path); + ScriptEditor::get_singleton()->reload_scripts(); + } else { + FileSystemDock::get_singleton()->navigate_to_path(file_path); + } + + } else if (p_id == BUTTON_TYPE_DISCARD) { + _discard_file(file_path, change); + _refresh_stage_area(); + } +} + +void VersionControlEditorPlugin::_display_diff(int p_idx) { + DiffViewType diff_view = (DiffViewType)diff_view_type_select->get_selected(); diff->clear(); - diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("source"), SNAME("EditorFonts"))); + + if (show_commit_diff_header) { + Dictionary meta_data = commit_list->get_selected()->get_metadata(0); + String commit_id = meta_data[SNAME("commit_id")]; + String commit_subtitle = meta_data[SNAME("commit_subtitle")]; + String commit_date = meta_data[SNAME("commit_date")]; + String commit_author = meta_data[SNAME("commit_author")]; + String commit_date_string = meta_data[SNAME("commit_date_string")]; + + diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"))); + diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor"))); + diff->add_text(TTR("Commit:") + " " + commit_id); + diff->add_newline(); + diff->add_text(TTR("Author:") + " " + commit_author); + diff->add_newline(); + diff->add_text(TTR("Date:") + " " + commit_date_string); + diff->add_newline(); + if (!commit_subtitle.is_empty()) { + diff->add_text(TTR("Subtitle:") + " " + commit_subtitle); + diff->add_newline(); + } + diff->add_newline(); + diff->pop(); + diff->pop(); + } + for (int i = 0; i < diff_content.size(); i++) { - Dictionary line_result = diff_content[i]; + EditorVCSInterface::DiffFile diff_file = diff_content[i]; + + diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"))); + diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor"))); + diff->add_text(TTR("File:") + " " + diff_file.new_file); + diff->pop(); + diff->pop(); + + diff->add_newline(); + diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts"))); + for (int j = 0; j < diff_file.diff_hunks.size(); j++) { + EditorVCSInterface::DiffHunk hunk = diff_file.diff_hunks[j]; + + String old_start = String::num_int64(hunk.old_start); + String new_start = String::num_int64(hunk.new_start); + String old_lines = String::num_int64(hunk.old_lines); + String new_lines = String::num_int64(hunk.new_lines); + + diff->append_text("[center]@@ " + old_start + "," + old_lines + " " + new_start + "," + new_lines + " @@[/center]"); + diff->add_newline(); + + switch (diff_view) { + case DIFF_VIEW_TYPE_SPLIT: + _display_diff_split_view(hunk.diff_lines); + break; + case DIFF_VIEW_TYPE_UNIFIED: + _display_diff_unified_view(hunk.diff_lines); + break; + } + diff->add_newline(); + diff->add_newline(); + } + diff->pop(); + + diff->add_newline(); + } +} + +void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content) { + List<EditorVCSInterface::DiffLine> parsed_diff; + + for (int i = 0; i < p_diff_content.size(); i++) { + EditorVCSInterface::DiffLine diff_line = p_diff_content[i]; + String line = diff_line.content.strip_edges(false, true); + + if (diff_line.new_line_no >= 0 && diff_line.old_line_no >= 0) { + diff_line.new_text = line; + diff_line.old_text = line; + parsed_diff.push_back(diff_line); + } else if (diff_line.new_line_no == -1) { + diff_line.new_text = ""; + diff_line.old_text = line; + parsed_diff.push_back(diff_line); + } else if (diff_line.old_line_no == -1) { + int j = parsed_diff.size() - 1; + while (j >= 0 && parsed_diff[j].new_line_no == -1) { + j--; + } + + if (j == parsed_diff.size() - 1) { + // no lines are modified + diff_line.new_text = line; + diff_line.old_text = ""; + parsed_diff.push_back(diff_line); + } else { + // lines are modified + EditorVCSInterface::DiffLine modified_line = parsed_diff[j + 1]; + modified_line.new_text = line; + modified_line.new_line_no = diff_line.new_line_no; + parsed_diff[j + 1] = modified_line; + } + } + } + + diff->push_table(6); + /* + [cell]Old Line No[/cell] + [cell]prefix[/cell] + [cell]Old Code[/cell] + + [cell]New Line No[/cell] + [cell]prefix[/cell] + [cell]New Line[/cell] + */ + + diff->set_table_column_expand(2, true); + diff->set_table_column_expand(5, true); + + for (int i = 0; i < parsed_diff.size(); i++) { + EditorVCSInterface::DiffLine diff_line = parsed_diff[i]; + + bool has_change = diff_line.status != " "; + static const Color red = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")); + static const Color green = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")); + static const Color white = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label")) * Color(1, 1, 1, 0.6); + + if (diff_line.old_line_no >= 0) { + diff->push_cell(); + diff->push_indent(1); + diff->push_color(has_change ? red : white); + diff->add_text(String::num_int64(diff_line.old_line_no)); + diff->pop(); + diff->pop(); + diff->pop(); + + diff->push_cell(); + diff->push_color(has_change ? red : white); + diff->add_text(has_change ? "-|" : " |"); + diff->pop(); + diff->pop(); + + diff->push_cell(); + diff->push_color(has_change ? red : white); + diff->add_text(diff_line.old_text); + diff->pop(); + diff->pop(); - if (line_result["status"] == "+") { - diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor"))); - } else if (line_result["status"] == "-") { - diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor"))); } else { - diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label"))); + diff->push_cell(); + diff->pop(); + + diff->push_cell(); + diff->pop(); + + diff->push_cell(); + diff->pop(); } - diff->add_text((String)line_result["content"]); + if (diff_line.new_line_no >= 0) { + diff->push_cell(); + diff->push_indent(1); + diff->push_color(has_change ? green : white); + diff->add_text(String::num_int64(diff_line.new_line_no)); + diff->pop(); + diff->pop(); + diff->pop(); + + diff->push_cell(); + diff->push_color(has_change ? green : white); + diff->add_text(has_change ? "+|" : " |"); + diff->pop(); + diff->pop(); + + diff->push_cell(); + diff->push_color(has_change ? green : white); + diff->add_text(diff_line.new_text); + diff->pop(); + diff->pop(); + } else { + diff->push_cell(); + diff->pop(); - diff->pop(); + diff->push_cell(); + diff->pop(); + + diff->push_cell(); + diff->pop(); + } } diff->pop(); } -void VersionControlEditorPlugin::_refresh_file_diff() { - String open_file = diff_file_name->get_text(); - if (!open_file.is_empty()) { - _display_file_diff(diff_file_name->get_text()); +void VersionControlEditorPlugin::_display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content) { + diff->push_table(4); + diff->set_table_column_expand(3, true); + + /* + [cell]Old Line No[/cell] + [cell]New Line No[/cell] + [cell]status[/cell] + [cell]code[/cell] + */ + for (int i = 0; i < p_diff_content.size(); i++) { + EditorVCSInterface::DiffLine diff_line = p_diff_content[i]; + String line = diff_line.content.strip_edges(false, true); + + Color color; + if (diff_line.status == "+") { + color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")); + } else if (diff_line.status == "-") { + color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")); + } else { + color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label")); + color *= Color(1, 1, 1, 0.6); + } + + diff->push_cell(); + diff->push_color(color); + diff->push_indent(1); + diff->add_text(diff_line.old_line_no >= 0 ? String::num_int64(diff_line.old_line_no) : ""); + diff->pop(); + diff->pop(); + diff->pop(); + + diff->push_cell(); + diff->push_color(color); + diff->push_indent(1); + diff->add_text(diff_line.new_line_no >= 0 ? String::num_int64(diff_line.new_line_no) : ""); + diff->pop(); + diff->pop(); + diff->pop(); + + diff->push_cell(); + diff->push_color(color); + diff->add_text(diff_line.status != "" ? diff_line.status + "|" : " |"); + diff->pop(); + diff->pop(); + + diff->push_cell(); + diff->push_color(color); + diff->add_text(line); + diff->pop(); + diff->pop(); } + + diff->pop(); } -void VersionControlEditorPlugin::_clear_file_diff() { - diff->clear(); - diff_file_name->set_text(""); - version_control_dock_button->set_pressed(false); +void VersionControlEditorPlugin::_update_commit_button() { + commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty()); } -void VersionControlEditorPlugin::_update_stage_status() { - String status; - if (staged_files_count == 1) { - status = TTR("Stage contains 1 file"); - } else { - status = vformat(TTR("Stage contains %d files"), staged_files_count); +void VersionControlEditorPlugin::_remove_branch() { + CHECK_PLUGIN_INITIALIZED(); + + EditorVCSInterface::get_singleton()->remove_branch(branch_to_remove); + branch_to_remove.clear(); + + _refresh_branch_list(); +} + +void VersionControlEditorPlugin::_remove_remote() { + CHECK_PLUGIN_INITIALIZED(); + + EditorVCSInterface::get_singleton()->remove_remote(remote_to_remove); + remote_to_remove.clear(); + + _refresh_remote_list(); +} + +void VersionControlEditorPlugin::_extra_option_selected(int p_index) { + CHECK_PLUGIN_INITIALIZED(); + + switch ((ExtraOption)p_index) { + case EXTRA_OPTION_FORCE_PUSH: + _force_push(); + break; + case EXTRA_OPTION_CREATE_BRANCH: + branch_create_confirm->popup_centered(); + break; + case EXTRA_OPTION_CREATE_REMOTE: + remote_create_confirm->popup_centered(); + break; } - commit_status->set_text(status); } -void VersionControlEditorPlugin::_update_commit_status() { - String status; - if (staged_files_count == 1) { - status = TTR("Committed 1 file"); - } else { - status = vformat(TTR("Committed %d files"), staged_files_count); +void VersionControlEditorPlugin::_popup_branch_remove_confirm(int p_index) { + branch_to_remove = extra_options_remove_branch_list->get_item_text(p_index); + + branch_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s branch?"), branch_to_remove)); + branch_remove_confirm->popup_centered(); +} + +void VersionControlEditorPlugin::_popup_remote_remove_confirm(int p_index) { + remote_to_remove = extra_options_remove_remote_list->get_item_text(p_index); + + remote_remove_confirm->set_text(vformat(TTR("Do you want to remove the %s remote?"), branch_to_remove)); + remote_remove_confirm->popup_centered(); +} + +void VersionControlEditorPlugin::_update_extra_options() { + extra_options_remove_branch_list->clear(); + for (int i = 0; i < branch_select->get_item_count(); i++) { + extra_options_remove_branch_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("VcsBranches"), SNAME("EditorIcons")), branch_select->get_item_text(branch_select->get_item_id(i))); + } + extra_options_remove_branch_list->update_canvas_items(); + + extra_options_remove_remote_list->clear(); + for (int i = 0; i < remote_select->get_item_count(); i++) { + extra_options_remove_remote_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ArrowUp"), SNAME("EditorIcons")), remote_select->get_item_text(remote_select->get_item_id(i))); } - commit_status->set_text(status); - staged_files_count = 0; + extra_options_remove_remote_list->update_canvas_items(); } -void VersionControlEditorPlugin::_update_commit_button() { - commit_button->set_disabled(commit_message->get_text().strip_edges().is_empty()); +bool VersionControlEditorPlugin::_is_staging_area_empty() { + return staged_files->get_root()->get_child_count() == 0; } void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) { @@ -316,266 +922,660 @@ void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> if (k.is_valid() && k->is_pressed()) { if (ED_IS_SHORTCUT("version_control/commit", p_event)) { - if (staged_files_count == 0) { + if (_is_staging_area_empty()) { // Stage all files only when no files were previously staged. - _stage_all(); + _move_all(unstaged_files); } - _send_commit_msg(); + + _commit(); + commit_message->accept_event(); - return; } } } -void VersionControlEditorPlugin::register_editor() { - if (!EditorVCSInterface::get_singleton()) { - EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock); - TabContainer *dock_vbc = (TabContainer *)version_commit_dock->get_parent_control(); - dock_vbc->set_tab_title(dock_vbc->get_tab_idx_from_control(version_commit_dock), TTR("Commit")); - - Button *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock); - set_version_control_tool_button(vc); +void VersionControlEditorPlugin::_toggle_vcs_integration(bool p_toggled) { + if (p_toggled) { + _initialize_vcs(); + } else { + shut_down(); } } -void VersionControlEditorPlugin::fetch_available_vcs_addon_names() { - List<StringName> global_classes; - ScriptServer::get_global_class_list(&global_classes); - - for (int i = 0; i != global_classes.size(); i++) { - String path = ScriptServer::get_global_class_path(global_classes[i]); - Ref<Script> script = ResourceLoader::load(path); - ERR_FAIL_COND(script.is_null()); +void VersionControlEditorPlugin::_project_path_selected(String p_project_path) { + project_path_input->set_text(p_project_path); +} - if (script->get_instance_base_type() == "EditorVCSInterface") { - available_addons.push_back(global_classes[i]); - } - } +void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() { + available_plugins.clear(); + ClassDB::get_direct_inheriters_from_class(EditorVCSInterface::get_class_static(), &available_plugins); } -void VersionControlEditorPlugin::clear_stage_area() { - stage_files->get_root()->clear_children(); +void VersionControlEditorPlugin::register_editor() { + EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock); + + version_control_dock_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock); + + _set_vcs_ui_state(true); } void VersionControlEditorPlugin::shut_down() { - if (EditorVCSInterface::get_singleton()) { - if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) { - EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); - } - EditorVCSInterface::get_singleton()->shut_down(); - memdelete(EditorVCSInterface::get_singleton()); - EditorVCSInterface::set_singleton(nullptr); + if (!EditorVCSInterface::get_singleton()) { + return; + } - EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock); - EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock); + if (EditorFileSystem::get_singleton()->is_connected(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) { + EditorFileSystem::get_singleton()->disconnect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); } -} -bool VersionControlEditorPlugin::is_vcs_initialized() const { - return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->is_vcs_initialized() : false; -} + EditorVCSInterface::get_singleton()->shut_down(); + memdelete(EditorVCSInterface::get_singleton()); + EditorVCSInterface::set_singleton(nullptr); + + EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock); + EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock); -const String VersionControlEditorPlugin::get_vcs_name() const { - return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->get_vcs_name() : ""; + _set_vcs_ui_state(false); } VersionControlEditorPlugin::VersionControlEditorPlugin() { singleton = this; - staged_files_count = 0; version_control_actions = memnew(PopupMenu); metadata_dialog = memnew(ConfirmationDialog); metadata_dialog->set_title(TTR("Create Version Control Metadata")); metadata_dialog->set_min_size(Size2(200, 40)); + metadata_dialog->get_ok_button()->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files)); version_control_actions->add_child(metadata_dialog); VBoxContainer *metadata_vb = memnew(VBoxContainer); + metadata_dialog->add_child(metadata_vb); + HBoxContainer *metadata_hb = memnew(HBoxContainer); metadata_hb->set_custom_minimum_size(Size2(200, 20)); + metadata_vb->add_child(metadata_hb); + Label *l = memnew(Label); l->set_text(TTR("Create VCS metadata files for:")); metadata_hb->add_child(l); + metadata_selection = memnew(OptionButton); metadata_selection->set_custom_minimum_size(Size2(100, 20)); metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE); metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT); metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT); - metadata_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files)); metadata_hb->add_child(metadata_selection); - metadata_vb->add_child(metadata_hb); + l = memnew(Label); l->set_text(TTR("Existing VCS metadata files will be overwritten.")); metadata_vb->add_child(l); - metadata_dialog->add_child(metadata_vb); set_up_dialog = memnew(AcceptDialog); - set_up_dialog->set_title(TTR("Set Up Version Control")); - set_up_dialog->set_min_size(Size2(400, 100)); + set_up_dialog->set_title(TTR("Local Settings")); + set_up_dialog->set_min_size(Size2(600, 100)); + set_up_dialog->add_cancel_button("Cancel"); + set_up_dialog->set_hide_on_ok(true); version_control_actions->add_child(set_up_dialog); - set_up_ok_button = set_up_dialog->get_ok_button(); - set_up_ok_button->set_text(TTR("Close")); + Button *set_up_apply_button = set_up_dialog->get_ok_button(); + set_up_apply_button->set_text(TTR("Apply")); + set_up_apply_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_set_credentials)); set_up_vbc = memnew(VBoxContainer); set_up_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER); set_up_dialog->add_child(set_up_vbc); - set_up_hbc = memnew(HBoxContainer); - set_up_hbc->set_h_size_flags(BoxContainer::SIZE_EXPAND_FILL); + HBoxContainer *set_up_hbc = memnew(HBoxContainer); + set_up_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); set_up_vbc->add_child(set_up_hbc); - set_up_vcs_status = memnew(RichTextLabel); - set_up_vcs_status->set_text(TTR("VCS Addon is not initialized")); - set_up_vbc->add_child(set_up_vcs_status); - - set_up_vcs_label = memnew(Label); - set_up_vcs_label->set_text(TTR("Version Control System")); + Label *set_up_vcs_label = memnew(Label); + set_up_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_vcs_label->set_text(TTR("VCS Provider")); set_up_hbc->add_child(set_up_vcs_label); set_up_choice = memnew(OptionButton); - set_up_choice->set_h_size_flags(HBoxContainer::SIZE_EXPAND_FILL); - set_up_choice->connect("item_selected", callable_mp(this, &VersionControlEditorPlugin::_selected_a_vcs)); + set_up_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL); set_up_hbc->add_child(set_up_choice); - set_up_init_settings = nullptr; - - set_up_init_button = memnew(Button); - set_up_init_button->set_text(TTR("Initialize")); - set_up_init_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_initialize_vcs)); - set_up_vbc->add_child(set_up_init_button); + HBoxContainer *project_path_hbc = memnew(HBoxContainer); + project_path_hbc->set_h_size_flags(Control::SIZE_FILL); + set_up_vbc->add_child(project_path_hbc); + + Label *project_path_label = memnew(Label); + project_path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + project_path_label->set_text(TTR("VCS Project Path")); + project_path_hbc->add_child(project_path_label); + + project_path_input = memnew(LineEdit); + project_path_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + project_path_input->set_text(OS::get_singleton()->get_resource_dir()); + project_path_hbc->add_child(project_path_input); + + FileDialog *select_project_path_file_dialog = memnew(FileDialog); + select_project_path_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM); + select_project_path_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR); + select_project_path_file_dialog->set_show_hidden_files(true); + select_project_path_file_dialog->set_current_dir(OS::get_singleton()->get_resource_dir()); + select_project_path_file_dialog->connect(SNAME("dir_selected"), callable_mp(this, &VersionControlEditorPlugin::_project_path_selected)); + project_path_hbc->add_child(select_project_path_file_dialog); + + select_project_path_button = memnew(Button); + select_project_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons")); + select_project_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(select_project_path_file_dialog)); + select_project_path_button->set_tooltip_text(TTR("Select VCS project path")); + project_path_hbc->add_child(select_project_path_button); + + HBoxContainer *toggle_vcs_hbc = memnew(HBoxContainer); + toggle_vcs_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_vbc->add_child(toggle_vcs_hbc); + + Label *toggle_vcs_label = memnew(Label); + toggle_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + toggle_vcs_label->set_text(TTR("Connect to VCS")); + toggle_vcs_hbc->add_child(toggle_vcs_label); + + toggle_vcs_choice = memnew(CheckButton); + toggle_vcs_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL); + toggle_vcs_choice->set_pressed_no_signal(false); + toggle_vcs_choice->connect(SNAME("toggled"), callable_mp(this, &VersionControlEditorPlugin::_toggle_vcs_integration)); + toggle_vcs_hbc->add_child(toggle_vcs_choice); + + set_up_vbc->add_child(memnew(HSeparator)); + + set_up_settings_vbc = memnew(VBoxContainer); + set_up_settings_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER); + set_up_vbc->add_child(set_up_settings_vbc); + + Label *remote_login = memnew(Label); + remote_login->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_login->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + remote_login->set_text(TTR("Remote Login")); + set_up_settings_vbc->add_child(remote_login); + + HBoxContainer *set_up_username_input = memnew(HBoxContainer); + set_up_username_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_settings_vbc->add_child(set_up_username_input); + + Label *set_up_username_label = memnew(Label); + set_up_username_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_username_label->set_text(TTR("Username")); + set_up_username_input->add_child(set_up_username_label); + + set_up_username = memnew(LineEdit); + set_up_username->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_username->set_text(EDITOR_DEF("version_control/username", "")); + set_up_username->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning)); + set_up_username_input->add_child(set_up_username); + + HBoxContainer *set_up_password_input = memnew(HBoxContainer); + set_up_password_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_settings_vbc->add_child(set_up_password_input); + + Label *set_up_password_label = memnew(Label); + set_up_password_label->set_text(TTR("Password")); + set_up_password_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_password_input->add_child(set_up_password_label); + + set_up_password = memnew(LineEdit); + set_up_password->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_password->set_secret(true); + set_up_password->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning)); + set_up_password_input->add_child(set_up_password); + + HBoxContainer *set_up_ssh_public_key_input = memnew(HBoxContainer); + set_up_ssh_public_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_settings_vbc->add_child(set_up_ssh_public_key_input); + + Label *set_up_ssh_public_key_label = memnew(Label); + set_up_ssh_public_key_label->set_text(TTR("SSH Public Key Path")); + set_up_ssh_public_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_label); + + HBoxContainer *set_up_ssh_public_key_input_hbc = memnew(HBoxContainer); + set_up_ssh_public_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_public_key_input->add_child(set_up_ssh_public_key_input_hbc); + + set_up_ssh_public_key_path = memnew(LineEdit); + set_up_ssh_public_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_public_key_path->set_text(EDITOR_DEF("version_control/ssh_public_key_path", "")); + set_up_ssh_public_key_path->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning)); + set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_path); + + set_up_ssh_public_key_file_dialog = memnew(FileDialog); + set_up_ssh_public_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM); + set_up_ssh_public_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE); + set_up_ssh_public_key_file_dialog->set_show_hidden_files(true); + // TODO: Make this start at the user's home folder + Ref<DirAccess> d = DirAccess::open(OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS)); + d->change_dir("../"); + set_up_ssh_public_key_file_dialog->set_current_dir(d->get_current_dir()); + set_up_ssh_public_key_file_dialog->connect(SNAME("file_selected"), callable_mp(this, &VersionControlEditorPlugin::_ssh_public_key_selected)); + set_up_ssh_public_key_input_hbc->add_child(set_up_ssh_public_key_file_dialog); + + Button *select_public_path_button = memnew(Button); + select_public_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons")); + select_public_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_public_key_file_dialog)); + select_public_path_button->set_tooltip_text(TTR("Select SSH public key path")); + set_up_ssh_public_key_input_hbc->add_child(select_public_path_button); + + HBoxContainer *set_up_ssh_private_key_input = memnew(HBoxContainer); + set_up_ssh_private_key_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_settings_vbc->add_child(set_up_ssh_private_key_input); + + Label *set_up_ssh_private_key_label = memnew(Label); + set_up_ssh_private_key_label->set_text(TTR("SSH Private Key Path")); + set_up_ssh_private_key_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_label); + + HBoxContainer *set_up_ssh_private_key_input_hbc = memnew(HBoxContainer); + set_up_ssh_private_key_input_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_private_key_input->add_child(set_up_ssh_private_key_input_hbc); + + set_up_ssh_private_key_path = memnew(LineEdit); + set_up_ssh_private_key_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_private_key_path->set_text(EDITOR_DEF("version_control/ssh_private_key_path", "")); + set_up_ssh_private_key_path->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning)); + set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_path); + + set_up_ssh_private_key_file_dialog = memnew(FileDialog); + set_up_ssh_private_key_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM); + set_up_ssh_private_key_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE); + set_up_ssh_private_key_file_dialog->set_show_hidden_files(true); + // TODO: Make this start at the user's home folder + set_up_ssh_private_key_file_dialog->set_current_dir(d->get_current_dir()); + set_up_ssh_private_key_file_dialog->connect("file_selected", callable_mp(this, &VersionControlEditorPlugin::_ssh_private_key_selected)); + set_up_ssh_private_key_input_hbc->add_child(set_up_ssh_private_key_file_dialog); + + Button *select_private_path_button = memnew(Button); + select_private_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons")); + select_private_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_private_key_file_dialog)); + select_private_path_button->set_tooltip_text(TTR("Select SSH private key path")); + set_up_ssh_private_key_input_hbc->add_child(select_private_path_button); + + HBoxContainer *set_up_ssh_passphrase_input = memnew(HBoxContainer); + set_up_ssh_passphrase_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_settings_vbc->add_child(set_up_ssh_passphrase_input); + + Label *set_up_ssh_passphrase_label = memnew(Label); + set_up_ssh_passphrase_label->set_text(TTR("SSH Passphrase")); + set_up_ssh_passphrase_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase_label); + + set_up_ssh_passphrase = memnew(LineEdit); + set_up_ssh_passphrase->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_ssh_passphrase->set_secret(true); + set_up_ssh_passphrase->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_set_up_warning)); + set_up_ssh_passphrase_input->add_child(set_up_ssh_passphrase); + + set_up_warning_text = memnew(Label); + set_up_warning_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + set_up_warning_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); + set_up_settings_vbc->add_child(set_up_warning_text); version_commit_dock = memnew(VBoxContainer); version_commit_dock->set_visible(false); + version_commit_dock->set_name(TTR("Commit")); - commit_box_vbc = memnew(VBoxContainer); - commit_box_vbc->set_alignment(VBoxContainer::ALIGNMENT_BEGIN); - commit_box_vbc->set_h_size_flags(VBoxContainer::SIZE_EXPAND_FILL); - commit_box_vbc->set_v_size_flags(VBoxContainer::SIZE_EXPAND_FILL); - version_commit_dock->add_child(commit_box_vbc); + VBoxContainer *unstage_area = memnew(VBoxContainer); + unstage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL); + unstage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL); + version_commit_dock->add_child(unstage_area); - stage_tools = memnew(HSplitContainer); - stage_tools->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED); - commit_box_vbc->add_child(stage_tools); + HBoxContainer *unstage_title = memnew(HBoxContainer); + unstage_area->add_child(unstage_title); - staging_area_label = memnew(Label); - staging_area_label->set_h_size_flags(Label::SIZE_EXPAND_FILL); - staging_area_label->set_text(TTR("Staging area")); - stage_tools->add_child(staging_area_label); + Label *unstage_label = memnew(Label); + unstage_label->set_text(TTR("Unstaged Changes")); + unstage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + unstage_title->add_child(unstage_label); refresh_button = memnew(Button); - refresh_button->set_tooltip(TTR("Detect new changes")); - refresh_button->set_text(TTR("Refresh")); + refresh_button->set_tooltip_text(TTR("Detect new changes")); + refresh_button->set_flat(true); refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); - refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); - stage_tools->add_child(refresh_button); - - stage_files = memnew(Tree); - stage_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL); - stage_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL); - stage_files->set_columns(1); - stage_files->set_column_title(0, TTR("Changes")); - stage_files->set_column_titles_visible(true); - stage_files->set_allow_reselect(true); - stage_files->set_allow_rmb_select(true); - stage_files->set_select_mode(Tree::SelectMode::SELECT_MULTI); - stage_files->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); - stage_files->connect("cell_selected", callable_mp(this, &VersionControlEditorPlugin::_view_file_diff)); - stage_files->create_item(); - stage_files->set_hide_root(true); - commit_box_vbc->add_child(stage_files); - - change_type_to_strings[CHANGE_TYPE_NEW] = TTR("New"); - change_type_to_strings[CHANGE_TYPE_MODIFIED] = TTR("Modified"); - change_type_to_strings[CHANGE_TYPE_RENAMED] = TTR("Renamed"); - change_type_to_strings[CHANGE_TYPE_DELETED] = TTR("Deleted"); - change_type_to_strings[CHANGE_TYPE_TYPECHANGE] = TTR("Typechange"); - - change_type_to_color[CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")); - change_type_to_color[CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")); - change_type_to_color[CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")); - change_type_to_color[CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")); - change_type_to_color[CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Editor")); - - stage_buttons = memnew(HSplitContainer); - stage_buttons->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED); - commit_box_vbc->add_child(stage_buttons); - - stage_selected_button = memnew(Button); - stage_selected_button->set_h_size_flags(Button::SIZE_EXPAND_FILL); - stage_selected_button->set_text(TTR("Stage Selected")); - stage_selected_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_selected)); - stage_buttons->add_child(stage_selected_button); + refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); + refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_commit_list)); + refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list)); + refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list)); + unstage_title->add_child(refresh_button); + + discard_all_button = memnew(Button); + discard_all_button->set_tooltip_text(TTR("Discard all changes")); + discard_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); + discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all)); + discard_all_button->set_flat(true); + unstage_title->add_child(discard_all_button); stage_all_button = memnew(Button); - stage_all_button->set_text(TTR("Stage All")); - stage_all_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_all)); - stage_buttons->add_child(stage_all_button); - - commit_box_vbc->add_child(memnew(HSeparator)); + stage_all_button->set_flat(true); + stage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons"))); + stage_all_button->set_tooltip_text(TTR("Stage all changes")); + unstage_title->add_child(stage_all_button); + + unstaged_files = memnew(Tree); + unstaged_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL); + unstaged_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL); + unstaged_files->set_select_mode(Tree::SELECT_ROW); + unstaged_files->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(unstaged_files)); + unstaged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(unstaged_files)); + unstaged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed)); + unstaged_files->create_item(); + unstaged_files->set_hide_root(true); + unstage_area->add_child(unstaged_files); + + VBoxContainer *stage_area = memnew(VBoxContainer); + stage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL); + stage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL); + version_commit_dock->add_child(stage_area); + + HBoxContainer *stage_title = memnew(HBoxContainer); + stage_area->add_child(stage_title); + + Label *stage_label = memnew(Label); + stage_label->set_text(TTR("Staged Changes")); + stage_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + stage_title->add_child(stage_label); + + unstage_all_button = memnew(Button); + unstage_all_button->set_flat(true); + unstage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons"))); + unstage_all_button->set_tooltip_text(TTR("Unstage all changes")); + stage_title->add_child(unstage_all_button); + + staged_files = memnew(Tree); + staged_files->set_h_size_flags(Tree::SIZE_EXPAND_FILL); + staged_files->set_v_size_flags(Tree::SIZE_EXPAND_FILL); + staged_files->set_select_mode(Tree::SELECT_ROW); + staged_files->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(staged_files)); + staged_files->connect(SNAME("button_clicked"), callable_mp(this, &VersionControlEditorPlugin::_cell_button_pressed)); + staged_files->connect(SNAME("item_activated"), callable_mp(this, &VersionControlEditorPlugin::_item_activated).bind(staged_files)); + staged_files->create_item(); + staged_files->set_hide_root(true); + stage_area->add_child(staged_files); + + // Editor crashes if bind is null + unstage_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(staged_files)); + stage_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(unstaged_files)); + + version_commit_dock->add_child(memnew(HSeparator)); + + VBoxContainer *commit_area = memnew(VBoxContainer); + version_commit_dock->add_child(commit_area); + + Label *commit_label = memnew(Label); + commit_label->set_text(TTR("Commit Message")); + commit_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + commit_area->add_child(commit_label); commit_message = memnew(TextEdit); commit_message->set_h_size_flags(Control::SIZE_EXPAND_FILL); commit_message->set_h_grow_direction(Control::GrowDirection::GROW_DIRECTION_BEGIN); commit_message->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END); commit_message->set_custom_minimum_size(Size2(200, 100)); - commit_message->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY); - commit_message->connect("text_changed", callable_mp(this, &VersionControlEditorPlugin::_update_commit_button)); - commit_message->connect("gui_input", callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input)); - commit_box_vbc->add_child(commit_message); + commit_message->set_line_wrapping_mode(TextEdit::LINE_WRAPPING_BOUNDARY); + commit_message->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_commit_button)); + commit_message->connect(SNAME("gui_input"), callable_mp(this, &VersionControlEditorPlugin::_commit_message_gui_input)); + commit_area->add_child(commit_message); + ED_SHORTCUT("version_control/commit", TTR("Commit"), KeyModifierMask::CMD | Key::ENTER); commit_button = memnew(Button); commit_button->set_text(TTR("Commit Changes")); commit_button->set_disabled(true); - commit_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_send_commit_msg)); - commit_box_vbc->add_child(commit_button); - - commit_status = memnew(Label); - commit_status->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - commit_box_vbc->add_child(commit_status); - - version_control_dock = memnew(PanelContainer); + commit_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_commit)); + commit_area->add_child(commit_button); + + version_commit_dock->add_child(memnew(HSeparator)); + + HBoxContainer *commit_list_hbc = memnew(HBoxContainer); + version_commit_dock->add_child(commit_list_hbc); + + Label *commit_list_label = memnew(Label); + commit_list_label->set_text(TTR("Commit List")); + commit_list_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + commit_list_hbc->add_child(commit_list_label); + + commit_list_size_button = memnew(OptionButton); + commit_list_size_button->set_tooltip_text(TTR("Commit list size")); + commit_list_size_button->add_item("10"); + commit_list_size_button->set_item_metadata(0, 10); + commit_list_size_button->add_item("20"); + commit_list_size_button->set_item_metadata(1, 20); + commit_list_size_button->add_item("30"); + commit_list_size_button->set_item_metadata(2, 30); + commit_list_size_button->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_set_commit_list_size)); + commit_list_hbc->add_child(commit_list_size_button); + + commit_list = memnew(Tree); + commit_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); + commit_list->set_v_grow_direction(Control::GrowDirection::GROW_DIRECTION_END); + commit_list->set_custom_minimum_size(Size2(200, 160)); + commit_list->create_item(); + commit_list->set_hide_root(true); + commit_list->set_select_mode(Tree::SELECT_ROW); + commit_list->set_columns(2); // Commit msg, author + commit_list->set_column_custom_minimum_width(0, 40); + commit_list->set_column_custom_minimum_width(1, 20); + commit_list->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(commit_list)); + version_commit_dock->add_child(commit_list); + + version_commit_dock->add_child(memnew(HSeparator)); + + HBoxContainer *menu_bar = memnew(HBoxContainer); + menu_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); + menu_bar->set_v_size_flags(Control::SIZE_FILL); + version_commit_dock->add_child(menu_bar); + + branch_select = memnew(OptionButton); + branch_select->set_tooltip_text(TTR("Branches")); + branch_select->set_h_size_flags(Control::SIZE_EXPAND_FILL); + branch_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_branch_item_selected)); + branch_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list)); + menu_bar->add_child(branch_select); + + branch_create_confirm = memnew(AcceptDialog); + branch_create_confirm->set_title(TTR("Create New Branch")); + branch_create_confirm->set_min_size(Size2(400, 100)); + branch_create_confirm->set_hide_on_ok(true); + version_commit_dock->add_child(branch_create_confirm); + + branch_create_ok = branch_create_confirm->get_ok_button(); + branch_create_ok->set_text(TTR("Create")); + branch_create_ok->set_disabled(true); + branch_create_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_branch)); + + branch_remove_confirm = memnew(AcceptDialog); + branch_remove_confirm->set_title(TTR("Remove Branch")); + branch_remove_confirm->add_cancel_button(); + version_commit_dock->add_child(branch_remove_confirm); + + Button *branch_remove_ok = branch_remove_confirm->get_ok_button(); + branch_remove_ok->set_text(TTR("Remove")); + branch_remove_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_remove_branch)); + + VBoxContainer *branch_create_vbc = memnew(VBoxContainer); + branch_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER); + branch_create_confirm->add_child(branch_create_vbc); + + HBoxContainer *branch_create_hbc = memnew(HBoxContainer); + branch_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + branch_create_vbc->add_child(branch_create_hbc); + + Label *branch_create_name_label = memnew(Label); + branch_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + branch_create_name_label->set_text(TTR("Branch Name")); + branch_create_hbc->add_child(branch_create_name_label); + + branch_create_name_input = memnew(LineEdit); + branch_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + branch_create_name_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_branch_create_button)); + branch_create_hbc->add_child(branch_create_name_input); + + remote_select = memnew(OptionButton); + remote_select->set_tooltip_text(TTR("Remotes")); + remote_select->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_remote_selected)); + remote_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list)); + menu_bar->add_child(remote_select); + + remote_create_confirm = memnew(AcceptDialog); + remote_create_confirm->set_title(TTR("Create New Remote")); + remote_create_confirm->set_min_size(Size2(400, 100)); + remote_create_confirm->set_hide_on_ok(true); + version_commit_dock->add_child(remote_create_confirm); + + remote_create_ok = remote_create_confirm->get_ok_button(); + remote_create_ok->set_text(TTR("Create")); + remote_create_ok->set_disabled(true); + remote_create_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_remote)); + + remote_remove_confirm = memnew(AcceptDialog); + remote_remove_confirm->set_title(TTR("Remove Remote")); + remote_remove_confirm->add_cancel_button(); + version_commit_dock->add_child(remote_remove_confirm); + + Button *remote_remove_ok = remote_remove_confirm->get_ok_button(); + remote_remove_ok->set_text(TTR("Remove")); + remote_remove_ok->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_remove_remote)); + + VBoxContainer *remote_create_vbc = memnew(VBoxContainer); + remote_create_vbc->set_alignment(BoxContainer::ALIGNMENT_CENTER); + remote_create_confirm->add_child(remote_create_vbc); + + HBoxContainer *remote_create_name_hbc = memnew(HBoxContainer); + remote_create_name_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_create_vbc->add_child(remote_create_name_hbc); + + Label *remote_create_name_label = memnew(Label); + remote_create_name_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_create_name_label->set_text(TTR("Remote Name")); + remote_create_name_hbc->add_child(remote_create_name_label); + + remote_create_name_input = memnew(LineEdit); + remote_create_name_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_create_name_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button)); + remote_create_name_hbc->add_child(remote_create_name_input); + + HBoxContainer *remote_create_hbc = memnew(HBoxContainer); + remote_create_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_create_vbc->add_child(remote_create_hbc); + + Label *remote_create_url_label = memnew(Label); + remote_create_url_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_create_url_label->set_text(TTR("Remote URL")); + remote_create_hbc->add_child(remote_create_url_label); + + remote_create_url_input = memnew(LineEdit); + remote_create_url_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); + remote_create_url_input->connect(SNAME("text_changed"), callable_mp(this, &VersionControlEditorPlugin::_update_remote_create_button)); + remote_create_hbc->add_child(remote_create_url_input); + + fetch_button = memnew(Button); + fetch_button->set_flat(true); + fetch_button->set_tooltip_text(TTR("Fetch")); + fetch_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); + fetch_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_fetch)); + menu_bar->add_child(fetch_button); + + pull_button = memnew(Button); + pull_button->set_flat(true); + pull_button->set_tooltip_text(TTR("Pull")); + pull_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons"))); + pull_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_pull)); + menu_bar->add_child(pull_button); + + push_button = memnew(Button); + push_button->set_flat(true); + push_button->set_tooltip_text(TTR("Push")); + push_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons"))); + push_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_push)); + menu_bar->add_child(push_button); + + extra_options = memnew(MenuButton); + extra_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); + extra_options->get_popup()->connect(SNAME("about_to_popup"), callable_mp(this, &VersionControlEditorPlugin::_update_extra_options)); + extra_options->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected)); + menu_bar->add_child(extra_options); + + extra_options->get_popup()->add_item(TTR("Force Push"), EXTRA_OPTION_FORCE_PUSH); + extra_options->get_popup()->add_separator(); + extra_options->get_popup()->add_item(TTR("Create New Branch"), EXTRA_OPTION_CREATE_BRANCH); + + extra_options_remove_branch_list = memnew(PopupMenu); + extra_options_remove_branch_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_branch_remove_confirm)); + extra_options_remove_branch_list->set_name("Remove Branch"); + extra_options->get_popup()->add_child(extra_options_remove_branch_list); + extra_options->get_popup()->add_submenu_item(TTR("Remove Branch"), "Remove Branch"); + + extra_options->get_popup()->add_separator(); + extra_options->get_popup()->add_item(TTR("Create New Remote"), EXTRA_OPTION_CREATE_REMOTE); + + extra_options_remove_remote_list = memnew(PopupMenu); + extra_options_remove_remote_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_remote_remove_confirm)); + extra_options_remove_remote_list->set_name("Remove Remote"); + extra_options->get_popup()->add_child(extra_options_remove_remote_list); + extra_options->get_popup()->add_submenu_item(TTR("Remove Remote"), "Remove Remote"); + + change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_NEW] = TTR("New"); + change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = TTR("Modified"); + change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_RENAMED] = TTR("Renamed"); + change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_DELETED] = TTR("Deleted"); + change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = TTR("Typechange"); + change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = TTR("Unmerged"); + + change_type_to_color[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), SNAME("Editor")); + change_type_to_color[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")); + change_type_to_color[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")); + change_type_to_color[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), SNAME("Editor")); + change_type_to_color[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Editor")); + change_type_to_color[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")); + + change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusSuccess"), SNAME("EditorIcons")); + change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")); + change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")); + change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")); + change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")); + change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")); + + version_control_dock = memnew(VBoxContainer); version_control_dock->set_v_size_flags(Control::SIZE_EXPAND_FILL); version_control_dock->set_custom_minimum_size(Size2(0, 300) * EDSCALE); version_control_dock->hide(); - diff_vbc = memnew(VBoxContainer); - diff_vbc->set_h_size_flags(HBoxContainer::SIZE_FILL); - diff_vbc->set_v_size_flags(HBoxContainer::SIZE_FILL); - version_control_dock->add_child(diff_vbc); + HBoxContainer *diff_heading = memnew(HBoxContainer); + diff_heading->set_h_size_flags(Control::SIZE_EXPAND_FILL); + diff_heading->set_tooltip_text(TTR("View file diffs before committing them to the latest version")); + version_control_dock->add_child(diff_heading); - diff_hbc = memnew(HBoxContainer); - diff_hbc->set_h_size_flags(HBoxContainer::SIZE_FILL); - diff_vbc->add_child(diff_hbc); + diff_title = memnew(Label); + diff_title->set_h_size_flags(Control::SIZE_EXPAND_FILL); + diff_heading->add_child(diff_title); - diff_heading = memnew(Label); - diff_heading->set_text(TTR("Status")); - diff_heading->set_tooltip(TTR("View file diffs before committing them to the latest version")); - diff_hbc->add_child(diff_heading); + Label *view = memnew(Label); + view->set_text(TTR("View:")); + diff_heading->add_child(view); - diff_file_name = memnew(Label); - diff_file_name->set_text(TTR("No file diff is active")); - diff_file_name->set_h_size_flags(Label::SIZE_EXPAND_FILL); - diff_file_name->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); - diff_hbc->add_child(diff_file_name); - - diff_refresh_button = memnew(Button); - diff_refresh_button->set_tooltip(TTR("Detect changes in file diff")); - diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); - diff_refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_file_diff)); - diff_hbc->add_child(diff_refresh_button); + diff_view_type_select = memnew(OptionButton); + diff_view_type_select->add_item(TTR("Split"), DIFF_VIEW_TYPE_SPLIT); + diff_view_type_select->add_item(TTR("Unified"), DIFF_VIEW_TYPE_UNIFIED); + diff_view_type_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_display_diff)); + diff_heading->add_child(diff_view_type_select); diff = memnew(RichTextLabel); diff->set_h_size_flags(TextEdit::SIZE_EXPAND_FILL); diff->set_v_size_flags(TextEdit::SIZE_EXPAND_FILL); + diff->set_use_bbcode(true); diff->set_selection_enabled(true); - diff_vbc->add_child(diff); + version_control_dock->add_child(diff); + + _update_set_up_warning(""); } VersionControlEditorPlugin::~VersionControlEditorPlugin() { shut_down(); - memdelete(version_control_dock); memdelete(version_commit_dock); + memdelete(version_control_dock); memdelete(version_control_actions); } diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h index fa721268ba..3340384a92 100644 --- a/editor/plugins/version_control_editor_plugin.h +++ b/editor/plugins/version_control_editor_plugin.h @@ -33,9 +33,12 @@ #include "editor/editor_plugin.h" #include "editor/editor_vcs_interface.h" -#include "scene/gui/box_container.h" +#include "scene/gui/check_button.h" +#include "scene/gui/container.h" +#include "scene/gui/file_dialog.h" +#include "scene/gui/menu_button.h" #include "scene/gui/rich_text_label.h" -#include "scene/gui/split_container.h" +#include "scene/gui/tab_container.h" #include "scene/gui/text_edit.h" #include "scene/gui/tree.h" @@ -43,79 +46,154 @@ class VersionControlEditorPlugin : public EditorPlugin { GDCLASS(VersionControlEditorPlugin, EditorPlugin) public: - enum ChangeType { - CHANGE_TYPE_NEW = 0, - CHANGE_TYPE_MODIFIED = 1, - CHANGE_TYPE_RENAMED = 2, - CHANGE_TYPE_DELETED = 3, - CHANGE_TYPE_TYPECHANGE = 4 + enum ButtonType { + BUTTON_TYPE_OPEN = 0, + BUTTON_TYPE_DISCARD = 1, + }; + + enum DiffViewType { + DIFF_VIEW_TYPE_SPLIT = 0, + DIFF_VIEW_TYPE_UNIFIED = 1, + }; + + enum ExtraOption { + EXTRA_OPTION_FORCE_PUSH, + EXTRA_OPTION_CREATE_BRANCH, + EXTRA_OPTION_CREATE_REMOTE, }; private: static VersionControlEditorPlugin *singleton; - int staged_files_count; - List<StringName> available_addons; + List<StringName> available_plugins; PopupMenu *version_control_actions = nullptr; ConfirmationDialog *metadata_dialog = nullptr; OptionButton *metadata_selection = nullptr; AcceptDialog *set_up_dialog = nullptr; - VBoxContainer *set_up_vbc = nullptr; - HBoxContainer *set_up_hbc = nullptr; - Label *set_up_vcs_label = nullptr; + CheckButton *toggle_vcs_choice = nullptr; OptionButton *set_up_choice = nullptr; - PanelContainer *set_up_init_settings = nullptr; - Button *set_up_init_button = nullptr; - RichTextLabel *set_up_vcs_status = nullptr; - Button *set_up_ok_button = nullptr; - - HashMap<ChangeType, String> change_type_to_strings; - HashMap<ChangeType, Color> change_type_to_color; + LineEdit *project_path_input = nullptr; + Button *select_project_path_button = nullptr; + VBoxContainer *set_up_vbc = nullptr; + VBoxContainer *set_up_settings_vbc = nullptr; + LineEdit *set_up_username = nullptr; + LineEdit *set_up_password = nullptr; + LineEdit *set_up_ssh_public_key_path = nullptr; + LineEdit *set_up_ssh_private_key_path = nullptr; + LineEdit *set_up_ssh_passphrase = nullptr; + FileDialog *set_up_ssh_public_key_file_dialog = nullptr; + FileDialog *set_up_ssh_private_key_file_dialog = nullptr; + Label *set_up_warning_text = nullptr; + + OptionButton *commit_list_size_button = nullptr; + + AcceptDialog *branch_create_confirm = nullptr; + LineEdit *branch_create_name_input = nullptr; + Button *branch_create_ok = nullptr; + + AcceptDialog *remote_create_confirm = nullptr; + LineEdit *remote_create_name_input = nullptr; + LineEdit *remote_create_url_input = nullptr; + Button *remote_create_ok = nullptr; + + HashMap<EditorVCSInterface::ChangeType, String> change_type_to_strings; + HashMap<EditorVCSInterface::ChangeType, Color> change_type_to_color; + HashMap<EditorVCSInterface::ChangeType, Ref<Texture>> change_type_to_icon; VBoxContainer *version_commit_dock = nullptr; - VBoxContainer *commit_box_vbc = nullptr; - HSplitContainer *stage_tools = nullptr; - Tree *stage_files = nullptr; - TreeItem *new_files = nullptr; - TreeItem *modified_files = nullptr; - TreeItem *renamed_files = nullptr; - TreeItem *deleted_files = nullptr; - TreeItem *typechange_files = nullptr; - Label *staging_area_label = nullptr; - HSplitContainer *stage_buttons = nullptr; + Tree *staged_files = nullptr; + Tree *unstaged_files = nullptr; + Tree *commit_list = nullptr; + + OptionButton *branch_select = nullptr; + Button *branch_remove_button = nullptr; + AcceptDialog *branch_remove_confirm = nullptr; + + Button *fetch_button = nullptr; + Button *pull_button = nullptr; + Button *push_button = nullptr; + OptionButton *remote_select = nullptr; + Button *remote_remove_button = nullptr; + AcceptDialog *remote_remove_confirm = nullptr; + MenuButton *extra_options = nullptr; + PopupMenu *extra_options_remove_branch_list = nullptr; + PopupMenu *extra_options_remove_remote_list = nullptr; + + String branch_to_remove; + String remote_to_remove; + Button *stage_all_button = nullptr; - Button *stage_selected_button = nullptr; + Button *unstage_all_button = nullptr; + Button *discard_all_button = nullptr; Button *refresh_button = nullptr; TextEdit *commit_message = nullptr; Button *commit_button = nullptr; - Label *commit_status = nullptr; - PanelContainer *version_control_dock = nullptr; + VBoxContainer *version_control_dock = nullptr; Button *version_control_dock_button = nullptr; - VBoxContainer *diff_vbc = nullptr; - HBoxContainer *diff_hbc = nullptr; - Button *diff_refresh_button = nullptr; - Label *diff_file_name = nullptr; - Label *diff_heading = nullptr; + Label *diff_title = nullptr; RichTextLabel *diff = nullptr; + OptionButton *diff_view_type_select = nullptr; + bool show_commit_diff_header = false; + List<EditorVCSInterface::DiffFile> diff_content; - void _populate_available_vcs_names(); - void _create_vcs_metadata_files(); - void _selected_a_vcs(int p_id); + void _notification(int p_what); void _initialize_vcs(); - void _send_commit_msg(); + void _set_vcs_ui_state(bool p_enabled); + void _set_credentials(); + void _ssh_public_key_selected(String p_path); + void _ssh_private_key_selected(String p_path); + void _populate_available_vcs_names(); + void _update_remotes_list(); + void _update_set_up_warning(String p_new_text); + void _update_opened_tabs(); + void _update_extra_options(); + + bool _load_plugin(String p_name, String p_project_path); + + void _pull(); + void _push(); + void _force_push(); + void _fetch(); + void _commit(); + void _discard_all(); void _refresh_stage_area(); - void _stage_selected(); - void _stage_all(); - void _view_file_diff(); - void _display_file_diff(String p_file_path); - void _refresh_file_diff(); - void _clear_file_diff(); - void _update_stage_status(); - void _update_commit_status(); + void _refresh_branch_list(); + void _set_commit_list_size(int p_index); + void _refresh_commit_list(); + void _refresh_remote_list(); + void _display_diff(int p_idx); + void _move_all(Object *p_tree); + void _load_diff(Object *p_tree); + void _clear_diff(); + int _get_item_count(Tree *p_tree); + void _item_activated(Object *p_tree); + void _create_branch(); + void _create_remote(); + void _update_branch_create_button(String p_new_text); + void _update_remote_create_button(String p_new_text); + void _branch_item_selected(int p_index); + void _remote_selected(int p_index); + void _remove_branch(); + void _remove_remote(); + void _popup_branch_remove_confirm(int p_index); + void _popup_remote_remove_confirm(int p_index); + void _move_item(Tree *p_tree, TreeItem *p_itme); + void _display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content); + void _display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content); + void _discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change); + void _cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index); + void _add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change); void _update_commit_button(); void _commit_message_gui_input(const Ref<InputEvent> &p_event); + void _extra_option_selected(int p_index); + bool _is_staging_area_empty(); + String _get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const; + void _create_vcs_metadata_files(); + void _popup_file_dialog(Variant p_file_dialog_variant); + void _toggle_vcs_integration(bool p_toggled); + void _project_path_selected(String p_project_path); friend class EditorVCSInterface; @@ -127,25 +205,15 @@ public: void popup_vcs_metadata_dialog(); void popup_vcs_set_up_dialog(const Control *p_gui_base); - void set_version_control_tool_button(Button *p_button) { version_control_dock_button = p_button; } PopupMenu *get_version_control_actions_panel() const { return version_control_actions; } - VBoxContainer *get_version_commit_dock() const { return version_commit_dock; } - PanelContainer *get_version_control_dock() const { return version_control_dock; } - - List<StringName> get_available_vcs_names() const { return available_addons; } - bool is_vcs_initialized() const; - const String get_vcs_name() const; void register_editor(); - void fetch_available_vcs_addon_names(); - void clear_stage_area(); + void fetch_available_vcs_plugin_names(); void shut_down(); VersionControlEditorPlugin(); ~VersionControlEditorPlugin(); }; -VARIANT_ENUM_CAST(VersionControlEditorPlugin::ChangeType); - #endif // VERSION_CONTROL_EDITOR_PLUGIN_H diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index e048ee2698..2fb8bbe86b 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -754,7 +754,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { Button *remove_btn = memnew(Button); remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - remove_btn->set_tooltip(TTR("Remove") + " " + name_left); + remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left); remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, i), CONNECT_DEFERRED); hb->add_child(remove_btn); } else { @@ -781,7 +781,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (is_group) { Button *remove_btn = memnew(Button); remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); - remove_btn->set_tooltip(TTR("Remove") + " " + name_left); + remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left); remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED); hb->add_child(remove_btn); @@ -4826,7 +4826,7 @@ VisualShaderEditor::VisualShaderEditor() { preview_shader = memnew(Button); preview_shader->set_flat(true); preview_shader->set_toggle_mode(true); - preview_shader->set_tooltip(TTR("Show generated shader code.")); + preview_shader->set_tooltip_text(TTR("Show generated shader code.")); graph->get_zoom_hbox()->add_child(preview_shader); preview_shader->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_preview_text)); @@ -4896,7 +4896,7 @@ VisualShaderEditor::VisualShaderEditor() { tools = memnew(MenuButton); filter_hb->add_child(tools); - tools->set_tooltip(TTR("Options")); + tools->set_tooltip_text(TTR("Options")); tools->get_popup()->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_tools_menu_option)); tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL); tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL); @@ -4928,7 +4928,7 @@ VisualShaderEditor::VisualShaderEditor() { highend_label->set_visible(false); highend_label->set_text("Vulkan"); highend_label->set_mouse_filter(Control::MOUSE_FILTER_STOP); - highend_label->set_tooltip(TTR("High-end node")); + highend_label->set_tooltip_text(TTR("High-end node")); node_desc = memnew(RichTextLabel); members_vb->add_child(node_desc); @@ -5411,6 +5411,7 @@ VisualShaderEditor::VisualShaderEditor() { // TEXTURES add_options.push_back(AddOption("UVFunc", "Textures", "Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D)); + add_options.push_back(AddOption("UVPolarCoord", "Textures", "Common", "VisualShaderNodeUVPolarCoord", TTR("Polar coordinates conversion applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D)); cubemap_node_option_idx = add_options.size(); add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D)); @@ -5418,6 +5419,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR)); curve_xyz_node_option_idx = add_options.size(); add_options.push_back(AddOption("CurveXYZTexture", "Textures", "Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D)); + add_options.push_back(AddOption("LinearSceneDepth", "Textures", "Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value of the DEPTH_TEXTURE node in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); texture2d_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D)); texture2d_array_node_option_idx = add_options.size(); @@ -5457,6 +5459,13 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("TransformConstant", "Transform", "Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM)); add_options.push_back(AddOption("TransformUniform", "Transform", "Variables", "VisualShaderNodeTransformUniform", TTR("Transform uniform."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM)); + // UTILITY + + add_options.push_back(AddOption("DistanceFade", "Utility", "", "VisualShaderNodeDistanceFade", TTR("The distance fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ProximityFade", "Utility", "", "VisualShaderNodeProximityFade", TTR("The proximity fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("RandomRange", "Utility", "", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Remap", "Utility", "", "VisualShaderNodeRemap", TTR("Remaps a given input from the input range to the output range."), {}, VisualShaderNode::PORT_TYPE_SCALAR)); + // VECTOR add_options.push_back(AddOption("VectorFunc", "Vector", "Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D)); @@ -6254,7 +6263,7 @@ void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Visua type = p_type; port = p_port; node = p_node; - update(); + queue_redraw(); _shader_changed(); } diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp index e3b2be33df..713c90c075 100644 --- a/editor/plugins/voxel_gi_editor_plugin.cpp +++ b/editor/plugins/voxel_gi_editor_plugin.cpp @@ -100,7 +100,7 @@ void VoxelGIEditorPlugin::_notification(int p_what) { return; } - bake->set_tooltip(text); + bake->set_tooltip_text(text); } break; } } diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 04c73e16ab..dbd2a7555d 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -41,9 +41,7 @@ const int ERROR_CODE = 77; #include "core/os/time.h" #include "core/templates/hash_map.h" #include "core/templates/list.h" - -const uint64_t CONVERSION_MAX_FILE_SIZE_MB = 4; -const uint64_t CONVERSION_MAX_FILE_SIZE = 1024 * 1024 * CONVERSION_MAX_FILE_SIZE_MB; +#include "core/templates/local_vector.h" static const char *enum_renames[][2] = { //// constants @@ -206,6 +204,7 @@ static const char *gdscript_function_renames[][2] = { // { "set_offset", "set_progress" }, // PathFollow2D, PathFollow3D - Too common // { "set_process_mode", "set_process_callback" }, // AnimationTree broke Node, Tween, Sky // { "set_refuse_new_network_connections", "set_refuse_new_connections"}, // MultiplayerAPI broke SceneTree + // { "set_tooltip", "set_tooltip_text" }, // Control, breaks TreeItem, at least for now. // { "set_uv", "surface_set_uv" }, // ImmediateMesh broke Polygon2D // { "set_v_offset", "set_drag_vertical_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // {"get_points","get_points_id"},// Astar, broke Line2D, Convexpolygonshape @@ -229,7 +228,6 @@ static const char *gdscript_function_renames[][2] = { { "add_stylebox_override", "add_theme_stylebox_override" }, // Control { "add_torque", "apply_torque" }, //RigidBody2D { "apply_changes", "_apply_changes" }, // EditorPlugin - { "bind_child_node_to_bone", "set_bone_children" }, // Skeleton3D { "body_add_force", "body_apply_force" }, // PhysicsServer2D { "body_add_torque", "body_apply_torque" }, // PhysicsServer2D { "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image @@ -297,11 +295,11 @@ static const char *gdscript_function_renames[][2] = { { "get_d", "get_distance" }, // LineShape2D { "get_drag_data", "_get_drag_data" }, // Control { "get_drag_data_fw", "_get_drag_data_fw" }, // ScriptEditor - { "get_editor_description", "_get_editor_description" }, // Node { "get_editor_viewport", "get_viewport" }, // EditorPlugin { "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton { "get_endian_swap", "is_big_endian" }, // File { "get_error_string", "get_error_message" }, // JSON + { "get_filename", "get_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places { "get_focus_neighbour", "get_focus_neighbor" }, // Control { "get_font_types", "get_font_type_list" }, // Theme { "get_frame_color", "get_color" }, // ColorRect @@ -397,9 +395,9 @@ static const char *gdscript_function_renames[][2] = { { "has_stylebox_override", "has_theme_stylebox_override" }, // Control { "http_escape", "uri_encode" }, // String { "http_unescape", "uri_decode" }, // String - { "import_animation_from_other_importer", "_import_animation" }, //EditorSceneFormatImporter { "import_scene_from_other_importer", "_import_scene" }, //EditorSceneFormatImporter { "instance_set_surface_material", "instance_set_surface_override_material" }, // RenderingServer + { "interpolate", "sample" }, // Curve, Curve2D, Curve3D, Gradient { "intersect_polygons_2d", "intersect_polygons" }, // Geometry2D { "intersect_polyline_with_polygon_2d", "intersect_polyline_with_polygon" }, // Geometry2D { "is_a_parent_of", "is_ancestor_of" }, // Node @@ -529,7 +527,6 @@ static const char *gdscript_function_renames[][2] = { { "set_tangent", "surface_set_tangent" }, // ImmediateGeometry broke SurfaceTool { "set_text_align", "set_text_alignment" }, // Button { "set_timer_process_mode", "set_timer_process_callback" }, // Timer - { "set_tonemap_auto_exposure", "set_tonemap_auto_exposure_enabled" }, // Environment { "set_translation", "set_position" }, // Node3D - this broke GLTFNode which is used rarely { "set_unit_offset", "set_progress_ratio" }, // PathFollow2D, PathFollow3D { "set_uv2", "surface_set_uv2" }, // ImmediateMesh broke Surffacetool @@ -545,7 +542,6 @@ static const char *gdscript_function_renames[][2] = { { "targeting_property", "tween_property" }, // Tween { "track_remove_key_at_position", "track_remove_key_at_time" }, // Animation { "triangulate_delaunay_2d", "triangulate_delaunay" }, // Geometry2D - { "unbind_child_node_from_bone", "remove_bone_child" }, // Skeleton3D { "unselect", "deselect" }, // ItemList { "unselect_all", "deselect_all" }, // ItemList { "update_configuration_warning", "update_configuration_warnings" }, // Node @@ -554,6 +550,7 @@ static const char *gdscript_function_renames[][2] = { { "warp_mouse_position", "warp_mouse" }, // Input // Builtin types + // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed // { "empty", "is_empty" }, // Array - Used as custom rule // Be careful, this will be used everywhere { "clamped", "clamp" }, // Vector2 // Be careful, this will be used everywhere { "get_rotation_quat", "get_rotation_quaternion" }, // Basis @@ -567,6 +564,7 @@ static const char *gdscript_function_renames[][2] = { { "to_wchar", "to_utf32_buffer" }, // String // TODO - utf32 or utf16? // @GlobalScope + // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed { "bytes2var", "bytes_to_var" }, { "bytes2var_with_objects", "bytes_to_var_with_objects" }, { "db2linear", "db_to_linear" }, @@ -581,6 +579,7 @@ static const char *gdscript_function_renames[][2] = { { "var2bytes_with_objects", "var_to_bytes_with_objects" }, // @GDScript + // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed { "dict2inst", "dict_to_inst" }, { "inst2dict", "inst_to_dict" }, @@ -629,6 +628,7 @@ static const char *csharp_function_renames[][2] = { // { "SetOffset", "SetProgress" }, // PathFollow2D, PathFollow3D - Too common // { "SetProcessMode", "SetProcessCallback" }, // AnimationTree broke Node, Tween, Sky // { "SetRefuseNewNetworkConnections", "SetRefuseNewConnections"}, // MultiplayerAPI broke SceneTree + // { "SetTooltip", "SetTooltipText" }, // Control, breaks TreeItem, at least for now. // { "SetUv", "SurfaceSetUv" }, // ImmediateMesh broke Polygon2D // { "SetVOffset", "SetDragVerticalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D // {"GetPoints","GetPointsId"},// Astar, broke Line2D, Convexpolygonshape @@ -1039,6 +1039,7 @@ static const char *gdscript_properties_renames[][2] = { { "global_rate_scale", "playback_speed_scale" }, // AudioServer { "gravity_distance_scale", "gravity_point_distance_scale" }, // Area2D { "gravity_vec", "gravity_direction" }, // Area2D + { "hint_tooltip", "tooltip_text" }, // Control { "hseparation", "h_separation" }, // Theme { "iterations_per_second", "physics_ticks_per_second" }, // Engine { "invert_enable", "invert_enabled" }, // Polygon2D @@ -1054,6 +1055,14 @@ static const char *gdscript_properties_renames[][2] = { { "pause_mode", "process_mode" }, // Node { "physical_scancode", "physical_keycode" }, // InputEventKey { "popup_exclusive", "exclusive" }, // Window + { "rect_position", "position" }, // Control + { "rect_global_position", "global_position" }, // Control + { "rect_size", "size" }, // Control + { "rect_min_size", "minimum_size" }, // Control + { "rect_rotation", "rotation" }, // Control + { "rect_scale", "scale" }, // Control + { "rect_pivot_offset", "pivot_offset" }, // Control + { "rect_clip_content", "clip_contents" }, // Control { "refuse_new_network_connections", "refuse_new_connections" }, // MultiplayerAPI { "region_filter_clip", "region_filter_clip_enabled" }, // Sprite2D { "selectedframe", "selected_frame" }, // Theme @@ -1123,6 +1132,7 @@ static const char *csharp_properties_renames[][2] = { { "GlobalRateScale", "PlaybackSpeedScale" }, // AudioServer { "GravityDistanceScale", "GravityPointDistanceScale" }, // Area2D { "GravityVec", "GravityDirection" }, // Area2D + { "HintTooltip", "TooltipText" }, // Control { "Hseparation", "HSeparation" }, // Theme { "IterationsPerSecond", "PhysicsTicksPerSecond" }, // Engine { "InvertEnable", "InvertEnabled" }, // Polygon2D @@ -1236,12 +1246,12 @@ static const char *project_settings_renames[][2] = { { "rendering/quality/shading/force_lambert_over_burley.mobile", "rendering/shading/overrides/force_lambert_over_burley.mobile" }, { "rendering/quality/shading/force_vertex_shading", "rendering/shading/overrides/force_vertex_shading" }, { "rendering/quality/shading/force_vertex_shading.mobile", "rendering/shading/overrides/force_vertex_shading.mobile" }, - { "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/shadows/shadow_atlas/quadrant_0_subdiv" }, - { "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/shadows/shadow_atlas/quadrant_1_subdiv" }, - { "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/shadows/shadow_atlas/quadrant_2_subdiv" }, - { "rendering/quality/shadow_atlas/quadrant_3_subdiv", "rendering/shadows/shadow_atlas/quadrant_3_subdiv" }, - { "rendering/quality/shadow_atlas/size", "rendering/shadows/shadow_atlas/size" }, - { "rendering/quality/shadow_atlas/size.mobile", "rendering/shadows/shadow_atlas/size.mobile" }, + { "rendering/quality/shadow_atlas/quadrant_0_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_0_subdiv" }, + { "rendering/quality/shadow_atlas/quadrant_1_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_1_subdiv" }, + { "rendering/quality/shadow_atlas/quadrant_2_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_2_subdiv" }, + { "rendering/quality/shadow_atlas/quadrant_3_subdiv", "rendering/lights_and_shadows/shadow_atlas/quadrant_3_subdiv" }, + { "rendering/quality/shadow_atlas/size", "rendering/lights_and_shadows/shadow_atlas/size" }, + { "rendering/quality/shadow_atlas/size.mobile", "rendering/lights_and_shadows/shadow_atlas/size.mobile" }, { "rendering/vram_compression/import_bptc", "rendering/textures/vram_compression/import_bptc" }, { "rendering/vram_compression/import_etc", "rendering/textures/vram_compression/import_etc" }, { "rendering/vram_compression/import_etc2", "rendering/textures/vram_compression/import_etc2" }, @@ -1267,9 +1277,19 @@ static const char *builtin_types_renames[][2] = { static const char *shaders_renames[][2] = { { "ALPHA_SCISSOR", "ALPHA_SCISSOR_THRESHOLD" }, + { "CAMERA_MATRIX", "INV_VIEW_MATRIX" }, + { "INV_CAMERA_MATRIX", "VIEW_MATRIX" }, { "NORMALMAP", "NORMAL_MAP" }, { "NORMALMAP_DEPTH", "NORMAL_MAP_DEPTH" }, - { "TRANSMISSION", "SSS_TRANSMITTANCE_COLOR" }, + { "TRANSMISSION", "BACKLIGHT" }, + { "WORLD_MATRIX", "MODEL_MATRIX" }, + { "depth_draw_alpha_prepass", "depth_draw_opaque" }, + { "hint_albedo", "source_color" }, + { "hint_aniso", "hint_anisotropy" }, + { "hint_black", "hint_default_black" }, + { "hint_black_albedo", "hint_default_black" }, + { "hint_color", "source_color" }, + { "hint_white", "hint_default_white" }, { nullptr, nullptr }, }; @@ -1490,7 +1510,7 @@ static const char *class_renames[][2] = { }; // TODO - this colors needs to be validated(not all are valid) -static const char *colors_renames[][2] = { +static const char *color_renames[][2] = { { "aliceblue", "ALICE_BLUE" }, { "antiquewhite", "ANTIQUE_WHITE" }, { "aqua", "AQUA" }, @@ -1643,6 +1663,7 @@ static const char *colors_renames[][2] = { class ProjectConverter3To4::RegExContainer { public: + // Custom GDScript RegEx reg_is_empty = RegEx("\\bempty\\("); RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])"); RegEx reg_json_to = RegEx("\\bto_json\\b"); @@ -1654,24 +1675,196 @@ public: RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$"); RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$"); RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)"); - RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)"); RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)"); RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)"); RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)"); RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)"); + + // GDScript keywords + RegEx keyword_gdscript_tool = RegEx("^tool"); + RegEx keyword_gdscript_export_single = RegEx("^export"); + RegEx keyword_gdscript_export_mutli = RegEx("([\t]+)export\\b"); + RegEx keyword_gdscript_onready = RegEx("^onready"); + RegEx keyword_gdscript_remote = RegEx("^remote func"); + RegEx keyword_gdscript_remotesync = RegEx("^remotesync func"); + RegEx keyword_gdscript_sync = RegEx("^sync func"); + RegEx keyword_gdscript_slave = RegEx("^slave func"); + RegEx keyword_gdscript_puppet = RegEx("^puppet func"); + RegEx keyword_gdscript_puppetsync = RegEx("^puppetsync func"); + RegEx keyword_gdscript_master = RegEx("^master func"); + RegEx keyword_gdscript_mastersync = RegEx("^mastersync func"); + + // CSharp keywords + RegEx keyword_csharp_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_master = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_mastersync = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); + + // Colors + LocalVector<RegEx *> color_regexes; + LocalVector<String> color_renamed; + + // Classes + LocalVector<RegEx *> class_tscn_regexes; + LocalVector<RegEx *> class_gd_regexes; + LocalVector<RegEx *> class_shader_regexes; + + LocalVector<RegEx *> class_regexes; + + RegEx class_temp_tscn = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b"); + RegEx class_temp_gd = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b"); + RegEx class_temp_shader = RegEx("\\bTEMP_RENAMED_CLASS.shader\\b"); + + LocalVector<String> class_temp_tscn_renames; + LocalVector<String> class_temp_gd_renames; + LocalVector<String> class_temp_shader_renames; + + // Common + LocalVector<RegEx *> enum_regexes; + LocalVector<RegEx *> gdscript_function_regexes; + LocalVector<RegEx *> project_settings_regexes; + LocalVector<RegEx *> gdscript_properties_regexes; + LocalVector<RegEx *> gdscript_signals_regexes; + LocalVector<RegEx *> shaders_regexes; + LocalVector<RegEx *> builtin_types_regexes; + LocalVector<RegEx *> csharp_function_regexes; + LocalVector<RegEx *> csharp_properties_regexes; + LocalVector<RegEx *> csharp_signal_regexes; + + RegExContainer() { + // Common + { + // Enum + for (unsigned int current_index = 0; enum_renames[current_index][0]; current_index++) { + enum_regexes.push_back(memnew(RegEx(String("\\b") + enum_renames[current_index][0] + "\\b"))); + } + // GDScript functions + for (unsigned int current_index = 0; gdscript_function_renames[current_index][0]; current_index++) { + gdscript_function_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_function_renames[current_index][0] + "\\b"))); + } + // Project Settings + for (unsigned int current_index = 0; project_settings_renames[current_index][0]; current_index++) { + project_settings_regexes.push_back(memnew(RegEx(String("\\b") + project_settings_renames[current_index][0] + "\\b"))); + } + // GDScript properties + for (unsigned int current_index = 0; gdscript_properties_renames[current_index][0]; current_index++) { + gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_properties_renames[current_index][0] + "\\b"))); + } + // GDScript Signals + for (unsigned int current_index = 0; gdscript_signals_renames[current_index][0]; current_index++) { + gdscript_signals_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_signals_renames[current_index][0] + "\\b"))); + } + // Shaders + for (unsigned int current_index = 0; shaders_renames[current_index][0]; current_index++) { + shaders_regexes.push_back(memnew(RegEx(String("\\b") + shaders_renames[current_index][0] + "\\b"))); + } + // Builtin types + for (unsigned int current_index = 0; builtin_types_renames[current_index][0]; current_index++) { + builtin_types_regexes.push_back(memnew(RegEx(String("\\b") + builtin_types_renames[current_index][0] + "\\b"))); + } + // CSharp function renames + for (unsigned int current_index = 0; csharp_function_renames[current_index][0]; current_index++) { + csharp_function_regexes.push_back(memnew(RegEx(String("\\b") + csharp_function_renames[current_index][0] + "\\b"))); + } + // CSharp properties renames + for (unsigned int current_index = 0; csharp_properties_renames[current_index][0]; current_index++) { + csharp_properties_regexes.push_back(memnew(RegEx(String("\\b") + csharp_properties_renames[current_index][0] + "\\b"))); + } + // CSharp signals renames + for (unsigned int current_index = 0; csharp_signals_renames[current_index][0]; current_index++) { + csharp_signal_regexes.push_back(memnew(RegEx(String("\\b") + csharp_signals_renames[current_index][0] + "\\b"))); + } + } + + // Colors + { + for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) { + color_regexes.push_back(memnew(RegEx(String("\\bColor.") + color_renames[current_index][0] + "\\b"))); + color_renamed.push_back(String("Color.") + color_renames[current_index][1]); + } + } + // Classes + { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { + class_tscn_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b"))); + class_gd_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b"))); + class_shader_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b"))); + + class_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + "\\b"))); + + class_temp_tscn_renames.push_back(String(class_renames[current_index][0]) + ".tscn"); + class_temp_gd_renames.push_back(String(class_renames[current_index][0]) + ".gd"); + class_temp_shader_renames.push_back(String(class_renames[current_index][0]) + ".shader"); + } + } + } + ~RegExContainer() { + for (unsigned int i = 0; i < color_regexes.size(); i++) { + memdelete(color_regexes[i]); + } + for (unsigned int i = 0; i < class_tscn_regexes.size(); i++) { + memdelete(class_tscn_regexes[i]); + memdelete(class_gd_regexes[i]); + memdelete(class_shader_regexes[i]); + memdelete(class_regexes[i]); + } + for (unsigned int i = 0; i < enum_regexes.size(); i++) { + memdelete(enum_regexes[i]); + } + for (unsigned int i = 0; i < gdscript_function_regexes.size(); i++) { + memdelete(gdscript_function_regexes[i]); + } + for (unsigned int i = 0; i < project_settings_regexes.size(); i++) { + memdelete(project_settings_regexes[i]); + } + for (unsigned int i = 0; i < gdscript_properties_regexes.size(); i++) { + memdelete(gdscript_properties_regexes[i]); + } + for (unsigned int i = 0; i < gdscript_signals_regexes.size(); i++) { + memdelete(gdscript_signals_regexes[i]); + } + for (unsigned int i = 0; i < shaders_regexes.size(); i++) { + memdelete(shaders_regexes[i]); + } + for (unsigned int i = 0; i < builtin_types_regexes.size(); i++) { + memdelete(builtin_types_regexes[i]); + } + for (unsigned int i = 0; i < csharp_function_regexes.size(); i++) { + memdelete(csharp_function_regexes[i]); + } + for (unsigned int i = 0; i < csharp_properties_regexes.size(); i++) { + memdelete(csharp_properties_regexes[i]); + } + for (unsigned int i = 0; i < csharp_signal_regexes.size(); i++) { + memdelete(csharp_signal_regexes[i]); + } + } }; +ProjectConverter3To4::ProjectConverter3To4(int maximum_file_size_kb, int maximum_line_length) { + this->maximum_file_size = maximum_file_size_kb * 1024; + this->maximum_line_length = maximum_line_length; +} + // Function responsible for converting project int ProjectConverter3To4::convert() { print_line("Starting conversion."); + uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec(); RegExContainer reg_container = RegExContainer(); + int cached_maximum_line_length = maximum_line_length; + maximum_line_length = 10000; // Use only for tests bigger value, to not break them + ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays."); ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); + maximum_line_length = cached_maximum_line_length; + // Checking if folder contains valid Godot 3 project. - // Project cannot be converted 2 times + // Project should not be converted more than 1 times { String conventer_text = "; Project was converted by built-in tool to Godot 4.0"; @@ -1681,7 +1874,7 @@ int ProjectConverter3To4::convert() { String project_godot_content = FileAccess::get_file_as_string("project.godot", &err); ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file."); - ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool."); + ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), ERROR_CODE, "Project already was converted with this tool."); Ref<FileAccess> file = FileAccess::open("project.godot", FileAccess::WRITE); ERR_FAIL_COND_V_MSG(file.is_null(), ERROR_CODE, "Failed to open project.godot file."); @@ -1696,11 +1889,19 @@ int ProjectConverter3To4::convert() { // Check file by file for (int i = 0; i < collected_files.size(); i++) { String file_name = collected_files[i]; - Error err = OK; - String file_content = FileAccess::get_file_as_string(file_name, &err); - ERR_CONTINUE_MSG(err != OK, "Failed to read content of \"" + file_name + "\"."); - uint64_t hash_before = file_content.hash64(); - uint64_t file_size = file_content.size(); + Vector<String> lines; + uint32_t ignored_lines = 0; + { + Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ); + ERR_CONTINUE_MSG(file.is_null(), "Failed to read content of \"" + file_name + "\"."); + while (!file->eof_reached()) { + String line = file->get_line(); + lines.append(line); + } + } + String file_content_before = collect_string_from_vector(lines); + uint64_t hash_before = file_content_before.hash(); + uint64_t file_size = file_content_before.size(); print_line("Trying to convert\t" + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB"); Vector<String> reason; @@ -1712,78 +1913,87 @@ int ProjectConverter3To4::convert() { file_name = file_name.replace(".shader", ".gdshader"); } - if (file_size < CONVERSION_MAX_FILE_SIZE) { + if (file_size < uint64_t(maximum_file_size)) { // TSCN must be the same work exactly same as .gd file because it may contains builtin script if (file_name.ends_with(".gd")) { - rename_classes(file_content); // Using only specialized function + rename_classes(lines, reg_container); // Using only specialized function - rename_common(enum_renames, file_content); - rename_enums(file_content); // Require to additional rename + rename_common(enum_renames, reg_container.enum_regexes, lines); + rename_colors(lines, reg_container); // Require to additional rename - rename_common(gdscript_function_renames, file_content); - rename_gdscript_functions(file_content, reg_container, false); // Require to additional rename + rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines); + rename_gdscript_functions(lines, reg_container, false); // Require to additional rename - rename_common(project_settings_renames, file_content); - rename_gdscript_keywords(file_content); - rename_common(gdscript_properties_renames, file_content); - rename_common(gdscript_signals_renames, file_content); - rename_common(shaders_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(project_settings_renames, reg_container.project_settings_regexes, lines); + rename_gdscript_keywords(lines, reg_container); + rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines); + rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); - custom_rename(file_content, "\\.shader", ".gdshader"); + custom_rename(lines, "\\.shader", ".gdshader"); } else if (file_name.ends_with(".tscn")) { - rename_classes(file_content); // Using only specialized function + rename_classes(lines, reg_container); // Using only specialized function - rename_common(enum_renames, file_content); - rename_enums(file_content); // Require to additional rename + rename_common(enum_renames, reg_container.enum_regexes, lines); + rename_colors(lines, reg_container); // Require to additional rename - rename_common(gdscript_function_renames, file_content); - rename_gdscript_functions(file_content, reg_container, true); // Require to additional rename + rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines); + rename_gdscript_functions(lines, reg_container, true); // Require to additional rename - rename_common(project_settings_renames, file_content); - rename_gdscript_keywords(file_content); - rename_common(gdscript_properties_renames, file_content); - rename_common(gdscript_signals_renames, file_content); - rename_common(shaders_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(project_settings_renames, reg_container.project_settings_regexes, lines); + rename_gdscript_keywords(lines, reg_container); + rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines); + rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); - custom_rename(file_content, "\\.shader", ".gdshader"); + custom_rename(lines, "\\.shader", ".gdshader"); } else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods - rename_classes(file_content); // Using only specialized function - rename_common(csharp_function_renames, file_content); - rename_common(builtin_types_renames, file_content); - rename_common(csharp_properties_renames, file_content); - rename_common(csharp_signals_renames, file_content); - rename_csharp_functions(file_content); - rename_csharp_attributes(file_content); - custom_rename(file_content, "public class ", "public partial class "); + rename_classes(lines, reg_container); // Using only specialized function + rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); + rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines); + rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines); + rename_csharp_functions(lines, reg_container); + rename_csharp_attributes(lines, reg_container); + custom_rename(lines, "public class ", "public partial class "); } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) { - rename_common(shaders_renames, file_content); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); } else if (file_name.ends_with("tres")) { - rename_classes(file_content); // Using only specialized function + rename_classes(lines, reg_container); // Using only specialized function - rename_common(shaders_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); - custom_rename(file_content, "\\.shader", ".gdshader"); + custom_rename(lines, "\\.shader", ".gdshader"); } else if (file_name.ends_with("project.godot")) { - rename_common(project_settings_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(project_settings_renames, reg_container.project_settings_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); } else if (file_name.ends_with(".csproj")) { // TODO } else { ERR_PRINT(file_name + " is not supported!"); continue; } + + for (String &line : lines) { + if (uint64_t(line.length()) > maximum_line_length) { + ignored_lines += 1; + } + } } else { - reason.append(" ERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB"); + reason.append(" ERROR: File has exceeded the maximum size allowed - " + itos(maximum_file_size / 1024) + " KB"); is_ignored = true; } uint64_t end_time = Time::get_singleton()->get_ticks_msec(); - - if (!is_ignored) { - uint64_t hash_after = file_content.hash64(); + if (is_ignored) { + String end_message = " Checking file took " + itos(end_time - start_time) + " ms."; + print_line(end_message); + } else { + String file_content_after = collect_string_from_vector(lines); + uint64_t hash_after = file_content_after.hash64(); // Don't need to save file without any changes // Save if this is a shader, because it was renamed if (hash_before != hash_after || file_name.ends_with(".gdshader")) { @@ -1791,11 +2001,14 @@ int ProjectConverter3To4::convert() { Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::WRITE); ERR_CONTINUE_MSG(file.is_null(), "Failed to open \"" + file_name + "\" to save data to file."); - file->store_string(file_content); + file->store_string(file_content_after); reason.append(" File was changed, conversion took " + itos(end_time - start_time) + " ms."); } else { reason.append(" File was not changed, checking took " + itos(end_time - start_time) + " ms."); } + if (ignored_lines != 0) { + reason.append(" Ignored " + itos(ignored_lines) + " lines, because their length exceeds maximum allowed characters - " + itos(maximum_line_length)); + } } for (int k = 0; k < reason.size(); k++) { print_line(reason[k]); @@ -1803,20 +2016,28 @@ int ProjectConverter3To4::convert() { } print_line("Conversion ended - all files(" + itos(collected_files.size()) + "), converted files(" + itos(converted_files) + "), not converted files(" + itos(collected_files.size() - converted_files) + ")."); + uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec(); + print_line("Conversion of all files took " + itos(conversion_end_time - conversion_start_time) + " ms."); return 0; }; // Function responsible for validating project conversion. int ProjectConverter3To4::validate_conversion() { print_line("Starting checking if project conversion can be done."); + uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec(); RegExContainer reg_container = RegExContainer(); + int cached_maximum_line_length = maximum_line_length; + maximum_line_length = 10000; // Use only for tests bigger value, to not break them + ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays."); ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); + maximum_line_length = cached_maximum_line_length; + // Checking if folder contains valid Godot 3 project. - // Project cannot be converted 2 times + // Project should not be converted more than 1 times { String conventer_text = "; Project was converted by built-in tool to Godot 4.0"; @@ -1826,7 +2047,7 @@ int ProjectConverter3To4::validate_conversion() { String project_godot_content = FileAccess::get_file_as_string("project.godot", &err); ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file."); - ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool."); + ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), ERROR_CODE, "Project already was converted with this tool."); } Vector<String> collected_files = check_for_files(); @@ -1836,7 +2057,8 @@ int ProjectConverter3To4::validate_conversion() { // Check file by file for (int i = 0; i < collected_files.size(); i++) { String file_name = collected_files[i]; - Vector<String> file_content; + Vector<String> lines; + uint32_t ignored_lines = 0; uint64_t file_size = 0; { Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ); @@ -1844,7 +2066,7 @@ int ProjectConverter3To4::validate_conversion() { while (!file->eof_reached()) { String line = file->get_line(); file_size += line.size(); - file_content.append(line); + lines.append(line); } } print_line("Checking for conversion - " + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB"); @@ -1858,75 +2080,85 @@ int ProjectConverter3To4::validate_conversion() { reason.append("\tFile extension will be renamed from `shader` to `gdshader`."); } - if (file_size < CONVERSION_MAX_FILE_SIZE) { + if (file_size < uint64_t(maximum_file_size)) { if (file_name.ends_with(".gd")) { - changed_elements.append_array(check_for_rename_classes(file_content)); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(enum_renames, file_content)); - changed_elements.append_array(check_for_rename_enums(file_content)); + changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines)); + changed_elements.append_array(check_for_rename_colors(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, false)); + changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, false)); - changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_keywords(file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content)); - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container)); + changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines)); + changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); - changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader")); + changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader")); } else if (file_name.ends_with(".tscn")) { - changed_elements.append_array(check_for_rename_classes(file_content)); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(enum_renames, file_content)); - changed_elements.append_array(check_for_rename_enums(file_content)); + changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines)); + changed_elements.append_array(check_for_rename_colors(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, true)); + changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, true)); - changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_keywords(file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content)); - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container)); + changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines)); + changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); - changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader")); + changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader")); } else if (file_name.ends_with(".cs")) { - changed_elements.append_array(check_for_rename_common(class_renames, file_content)); - changed_elements.append_array(check_for_rename_common(csharp_function_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); - changed_elements.append_array(check_for_rename_common(csharp_properties_renames, file_content)); - changed_elements.append_array(check_for_rename_common(csharp_signals_renames, file_content)); - changed_elements.append_array(check_for_rename_csharp_functions(file_content)); - changed_elements.append_array(check_for_rename_csharp_attributes(file_content)); - changed_elements.append_array(check_for_custom_rename(file_content, "public class ", "public partial class ")); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); + changed_elements.append_array(check_for_rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); + changed_elements.append_array(check_for_rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines)); + changed_elements.append_array(check_for_rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines)); + changed_elements.append_array(check_for_rename_csharp_functions(lines, reg_container)); + changed_elements.append_array(check_for_rename_csharp_attributes(lines, reg_container)); + changed_elements.append_array(check_for_custom_rename(lines, "public class ", "public partial class ")); } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) { - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); } else if (file_name.ends_with("tres")) { - changed_elements.append_array(check_for_rename_classes(file_content)); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); - changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader")); + changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader")); } else if (file_name.ends_with("project.godot")) { - changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); } else if (file_name.ends_with(".csproj")) { // TODO } else { ERR_PRINT(file_name + " is not supported!"); continue; } + + for (String &line : lines) { + if (uint64_t(line.length()) > maximum_line_length) { + ignored_lines += 1; + } + } } else { - reason.append("\tERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB"); + reason.append("\tERROR: File has exceeded the maximum size allowed - " + itos(maximum_file_size / 1024) + " KB"); is_ignored = true; } uint64_t end_time = Time::get_singleton()->get_ticks_msec(); - print_line(" Checking file took " + itos(end_time - start_time) + " ms."); + String end_message = " Checking file took " + itos(end_time - start_time) + " ms."; + if (ignored_lines != 0) { + end_message += " Ignored " + itos(ignored_lines) + " lines, because their length exceeds maximum allowed characters - " + itos(maximum_line_length); + } + print_line(end_message); for (int k = 0; k < reason.size(); k++) { print_line(reason[k]); @@ -1942,6 +2174,8 @@ int ProjectConverter3To4::validate_conversion() { } print_line("Checking for valid conversion ended - all files(" + itos(collected_files.size()) + "), files which would be converted(" + itos(converted_files) + "), files which would not be converted(" + itos(collected_files.size() - converted_files) + ")."); + uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec(); + print_line("Conversion of all files took " + itos(conversion_end_time - conversion_start_time) + " ms."); return 0; } @@ -1968,14 +2202,14 @@ Vector<String> ProjectConverter3To4::check_for_files() { continue; } if (dir.current_is_dir()) { - directories_to_check.append(current_dir.plus_file(file_name) + "/"); + directories_to_check.append(current_dir.path_join(file_name) + "/"); } else { bool proper_extension = false; if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj")) proper_extension = true; if (proper_extension) { - collected_files.append(current_dir.plus_file(file_name)); + collected_files.append(current_dir.path_join(file_name)); } } file_name = dir.get_next(); @@ -1987,218 +2221,230 @@ Vector<String> ProjectConverter3To4::check_for_files() { return collected_files; } -bool ProjectConverter3To4::test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what) { - String got = name; - (this->*func)(got); - if (expected != got) { - ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`"); +// Test expected results of gdscript +bool ProjectConverter3To4::test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin_script) { + Vector<String> got = name.split("\n"); + (this->*func)(got, reg_container, builtin_script); + String got_str = collect_string_from_vector(got); + if (expected != got_str) { + ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); return false; } return true; } -bool ProjectConverter3To4::test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin_script) { - String got = name; - (this->*func)(got, reg_container, builtin_script); - if (expected != got) { - ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`"); +bool ProjectConverter3To4::test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer ®_container) { + Vector<String> got = name.split("\n"); + (this->*func)(got, reg_container); + String got_str = collect_string_from_vector(got); + if (expected != got_str) { + ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); return false; } return true; } -bool ProjectConverter3To4::test_conversion_single_normal(String name, String expected, const char *array[][2], String what) { - String got = name; - rename_common(array, got); - if (expected != got) { - ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`"); +bool ProjectConverter3To4::test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, String what) { + Vector<String> got = name.split("\n"); + rename_common(array, regex_cache, got); + String got_str = collect_string_from_vector(got); + if (expected != got_str) { + ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); return false; } return true; } // Validate if conversions are proper -bool ProjectConverter3To4::test_conversion(const RegExContainer ®_container) { +bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { bool valid = true; - valid = valid & test_conversion_single_normal("Spatial", "Node3D", class_renames, "class"); + valid = valid & test_conversion_basic("TYPE_REAL", "TYPE_FLOAT", enum_renames, reg_container.enum_regexes, "enum"); - valid = valid & test_conversion_single_normal("TYPE_REAL", "TYPE_FLOAT", enum_renames, "enum"); + valid = valid & test_conversion_basic("can_instance", "can_instantiate", gdscript_function_renames, reg_container.gdscript_function_regexes, "gdscript function"); - valid = valid & test_conversion_single_normal("can_instance", "can_instantiate", gdscript_function_renames, "gdscript function"); + valid = valid & test_conversion_basic("CanInstance", "CanInstantiate", csharp_function_renames, reg_container.csharp_function_regexes, "csharp function"); - valid = valid & test_conversion_single_normal("CanInstance", "CanInstantiate", csharp_function_renames, "csharp function"); + valid = valid & test_conversion_basic("translation", "position", gdscript_properties_renames, reg_container.gdscript_properties_regexes, "gdscript property"); - valid = valid & test_conversion_single_normal("translation", "position", gdscript_properties_renames, "gdscript property"); + valid = valid & test_conversion_basic("Translation", "Position", csharp_properties_renames, reg_container.csharp_properties_regexes, "csharp property"); - valid = valid & test_conversion_single_normal("Translation", "Position", csharp_properties_renames, "csharp property"); + valid = valid & test_conversion_basic("NORMALMAP", "NORMAL_MAP", shaders_renames, reg_container.shaders_regexes, "shader"); - valid = valid & test_conversion_single_normal("NORMALMAP", "NORMAL_MAP", shaders_renames, "shader"); + valid = valid & test_conversion_basic("text_entered", "text_submitted", gdscript_signals_renames, reg_container.gdscript_signals_regexes, "gdscript signal"); - valid = valid & test_conversion_single_normal("text_entered", "text_submitted", gdscript_signals_renames, "gdscript signal"); + valid = valid & test_conversion_basic("TextEntered", "TextSubmitted", csharp_signals_renames, reg_container.csharp_signal_regexes, "csharp signal"); - valid = valid & test_conversion_single_normal("TextEntered", "TextSubmitted", csharp_signals_renames, "csharp signal"); + valid = valid & test_conversion_basic("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, reg_container.project_settings_regexes, "project setting"); - valid = valid & test_conversion_single_normal("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, "project setting"); - - valid = valid & test_conversion_single_normal("Transform", "Transform3D", builtin_types_renames, "builtin type"); + valid = valid & test_conversion_basic("Transform", "Transform3D", builtin_types_renames, reg_container.builtin_types_regexes, "builtin type"); // Custom Renames - valid = valid & test_conversion_single_additional("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp"); - valid = valid & test_conversion_single_additional("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp"); - valid = valid & test_conversion_single_additional("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - - valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); - valid = valid & test_conversion_single_additional_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); - - valid = valid & test_conversion_single_additional_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround - valid = valid & test_conversion_single_additional_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin(" aa", " aa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\taa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\t aa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" \taa", " \taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_enums, "custom rename"); + valid = valid & test_conversion_with_regex("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename", reg_container); + + valid = valid & test_conversion_with_regex("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + + valid = valid & test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); + valid = valid & test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_with_regex("extends CSGBox", "extends CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("CSGBox", "CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial", "Node3D", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.tscn", "Spatial.tscn", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.gd", "Spatial.gd", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.shader", "Spatial.shader", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.other", "Node3D.other", &ProjectConverter3To4::rename_classes, "classes", reg_container); + + valid = valid & test_conversion_with_regex("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); + + valid = valid & test_conversion_gdscript_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround + valid = valid & test_conversion_gdscript_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("func _init(", "func _init(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a,b,c,d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("button.pressed SF", "button.pressed SF", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "custom rename", reg_container); // Custom rule conversion { String from = "instance"; String to = "instantiate"; String name = "AA.instance()"; - String got = "AA.instance()"; + Vector<String> got = String("AA.instance()").split("\n"); String expected = "AA.instantiate()"; custom_rename(got, from, to); - if (got != expected) { - ERR_PRINT("Failed to convert custom rename `" + name + "` to `" + expected + "`, got instead `" + got + "`"); + String got_str = collect_string_from_vector(got); + if (got_str != expected) { + ERR_PRINT("Failed to convert custom rename `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); } - valid = valid & (got == expected); + valid = valid & (got_str == expected); } // get_object_of_execution @@ -2313,8 +2559,7 @@ bool ProjectConverter3To4::test_array_names() { // Validate if all classes are valid { - int current_index = 0; - while (class_renames[current_index][0]) { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { const String old_class = class_renames[current_index][0]; const String new_class = class_renames[current_index][1]; @@ -2329,84 +2574,65 @@ bool ProjectConverter3To4::test_array_names() { ERR_PRINT(String("Class `") + new_class + "` doesn't exists in Godot 4.0, so cannot be used in conversion."); valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI } - current_index++; - } - } - - // // TODO To be able to fully work, it needs https://github.com/godotengine/godot/pull/49053 - // // TODO this needs to be changed to hashset when available https://github.com/godotengine/godot-proposals/issues/867, to speedup searchng - // { - // OrderedHashMap<String, bool> all_functions; - - // List<StringName> classes_list; - // ClassDB::get_class_list(&classes_list); - // for (StringName &name_of_class : classes_list) { - // List<MethodInfo> method_list; - // ClassDB::get_method_list(name_of_class, &method_list, true); - // for (MethodInfo &function_data : method_list) { - // if (!all_functions.has(function_data.name)) { - // all_functions.insert(function_data.name, false); - // } - // } - // } - - // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) { - // List<MethodInfo> method_list; - // Variant::get_method_list_by_type(&method_list, Variant::Type(type)); - // for (MethodInfo &function_data : method_list) { - // if (!all_functions.has(function_data.name)) { - // all_functions.insert(function_data.name, false); - // } - // } - // } - - // int current_element = 0; - // while (gdscript_function_renames[current_element][0] != nullptr) { - // if (!all_functions.has(gdscript_function_renames[current_element][1])) { - // ERR_PRINT(String("Missing gdscript function in pair (") + gdscript_function_renames[current_element][0] + " - ===> " + gdscript_function_renames[current_element][1] + " <===)"); - // valid = false; - // } - // // // DEBUG, disable below after tests - // // if (all_functions.has(gdscript_function_renames[current_element][0])) { - // // String used_in_classes = ""; - // // - // // for (StringName &name_of_class : classes_list) { - // // List<MethodInfo> method_list; - // // ClassDB::get_method_list(name_of_class, &method_list, true); - // // for (MethodInfo &function_data : method_list) { - // // if (function_data.name == gdscript_function_renames[current_element][0]) { - // // used_in_classes += String(name_of_class) + ", "; - // // } - // // } - // // } - // // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) { - // // List<MethodInfo> method_list; - // // Variant::get_method_list_by_type(&method_list, Variant::Type(type)); - // // for (MethodInfo &function_data : method_list) { - // // if (function_data.name == gdscript_function_renames[current_element][0]) { - // // used_in_classes += Variant::get_type_name(Variant::Type(type)) + ", "; - // // } - // // } - // // } - // // used_in_classes = used_in_classes.trim_suffix(", "); - // // - // // WARN_PRINT(String("Godot contains function which will be renamed in pair ( ===> ") + gdscript_function_renames[current_element][0] + " <=== - " + gdscript_function_renames[current_element][1] + ") in class " + used_in_classes + " - check for possible invalid rule."); - // // } - // current_element++; - // } - // } + } + } + + { + HashSet<String> all_functions; + + // List of excluded functions from builtin types and global namespace, because currently it is not possible to get list of functions from them + // This will be available when https://github.com/godotengine/godot/pull/49053 or similar will be included into Godot + static const char *builtin_types_excluded_functions[] = { "dict_to_inst", "inst_to_dict", "bytes_to_var", "bytes_to_var_with_objects", "db_to_linear", "deg_to_rad", "linear_to_db", "rad_to_deg", "randf_range", "snapped", "str_to_var", "var_to_str", "var_to_bytes", "var_to_bytes_with_objects", "move_toward", "uri_encode", "uri_decode", "remove_at", "get_rotation_quaternion", "clamp", "grow_side", "is_absolute_path", "is_valid_int", "lerp", "to_ascii_buffer", "to_utf8_buffer", "to_utf32_buffer", "snapped", nullptr }; + for (int current_index = 0; builtin_types_excluded_functions[current_index]; current_index++) { + all_functions.insert(builtin_types_excluded_functions[current_index]); + } + + // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) { + // List<MethodInfo> method_list; + // Variant::get_method_list_by_type(&method_list, Variant::Type(type)); + // for (MethodInfo &function_data : method_list) { + // if (!all_functions.has(function_data.name)) { + // all_functions.insert(function_data.name); + // } + // } + // } + + List<StringName> classes_list; + ClassDB::get_class_list(&classes_list); + for (StringName &name_of_class : classes_list) { + List<MethodInfo> method_list; + ClassDB::get_method_list(name_of_class, &method_list, true); + for (MethodInfo &function_data : method_list) { + if (!all_functions.has(function_data.name)) { + all_functions.insert(function_data.name); + } + } + } + + int current_element = 0; + while (gdscript_function_renames[current_element][0] != nullptr) { + if (!all_functions.has(gdscript_function_renames[current_element][1])) { + ERR_PRINT(String("Missing gdscript function in pair (") + gdscript_function_renames[current_element][0] + " - ===> " + gdscript_function_renames[current_element][1] + " <===)"); + valid = false; + } + current_element++; + } + } + if (!valid) { + ERR_PRINT("Found function which is used in converter, but cannot be found in Godot 4. Rename this element to new name or remove entire rule about it if is obsolete."); + } valid = valid & test_single_array(enum_renames); valid = valid & test_single_array(class_renames, true); valid = valid & test_single_array(gdscript_function_renames, true); valid = valid & test_single_array(csharp_function_renames, true); - valid = valid & test_single_array(gdscript_properties_renames); + valid = valid & test_single_array(gdscript_properties_renames, true); valid = valid & test_single_array(csharp_properties_renames); - valid = valid & test_single_array(shaders_renames); + valid = valid & test_single_array(shaders_renames, true); valid = valid & test_single_array(gdscript_signals_renames); valid = valid & test_single_array(project_settings_renames); valid = valid & test_single_array(builtin_types_renames); - valid = valid & test_single_array(colors_renames); + valid = valid & test_single_array(color_renames); return valid; } @@ -2415,10 +2641,9 @@ bool ProjectConverter3To4::test_array_names() { // Also checks if in name contains spaces at the end or beginning bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore_second_check) { bool valid = true; - int current_index = 0; Vector<String> names = Vector<String>(); - while (array[current_index][0]) { + for (unsigned int current_index = 0; array[current_index][0]; current_index++) { if (String(array[current_index][0]).begins_with(" ") || String(array[current_index][0]).ends_with(" ")) { { ERR_PRINT(String("Entry \"") + array[current_index][0] + "\" ends or stars with space."); @@ -2444,7 +2669,6 @@ bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore if (!ignore_second_check) { names.append(array[current_index][1]); } - current_index++; } return valid; }; @@ -2454,18 +2678,17 @@ bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore Vector<String> ProjectConverter3To4::parse_arguments(const String &line) { Vector<String> parts; int string_size = line.length(); - int current_index = 0; int start_part = 0; // Index of beginning of start par int parts_counter = 0; char32_t previous_character = '\0'; bool is_inside_string = false; // if true, it ignore this 3 characters ( , ) inside string if (line.count("(") != line.count(")")) { - ERR_PRINT("Bug: substring should have equal number of open and close parenthess - `" + line + "`"); + ERR_PRINT("Converter internal bug: substring should have equal number of open and close parenthess in line - `" + line + "`"); return parts; } - while (current_index < string_size) { + for (int current_index = 0; current_index < string_size; current_index++) { char32_t character = line.get(current_index); switch (character) { case '(': { @@ -2510,7 +2733,6 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) { is_inside_string = !is_inside_string; } } - current_index++; previous_character = character; } @@ -2528,9 +2750,8 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) { // Finds latest parenthess owned by function // `function(abc(a,b),DD)):` finds this parenthess `function(abc(a,b),DD => ) <= ):` int ProjectConverter3To4::get_end_parenthess(const String &line) const { - int current_index = 0; int current_state = 0; - while (line.length() > current_index) { + for (int current_index = 0; line.length() > current_index; current_index++) { char32_t character = line.get(current_index); if (character == '(') { current_state++; @@ -2541,7 +2762,6 @@ int ProjectConverter3To4::get_end_parenthess(const String &line) const { return current_index; } } - current_index++; } return -1; } @@ -2643,229 +2863,217 @@ String ProjectConverter3To4::get_object_of_execution(const String &line) const { return line.substr(variable_start, (end - variable_start)); } -void ProjectConverter3To4::rename_enums(String &file_content) { - int current_index = 0; - - // Rename colors - if (file_content.find("Color.") != -1) { - while (colors_renames[current_index][0]) { - RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, String("Color.") + colors_renames[current_index][1], true); - current_index++; +void ProjectConverter3To4::rename_colors(Vector<String> &lines, const RegExContainer ®_container) { + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + if (line.contains("Color.")) { + for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) { + line = reg_container.color_regexes[current_index]->sub(line, reg_container.color_renamed[current_index], true); + } + } } } }; -Vector<String> ProjectConverter3To4::check_for_rename_enums(Vector<String> &file_content) { - int current_index = 0; - - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer ®_container) { + Vector<String> found_renames; - // Rename colors - if (file_content.find("Color.") != -1) { - while (colors_renames[current_index][0]) { - RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - - int current_line = 1; - for (String &line : file_content) { - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, colors_renames[current_index][0], colors_renames[current_index][1], line)); + int current_line = 1; + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + if (line.contains("Color.")) { + for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) { + TypedArray<RegExMatch> reg_match = reg_container.color_regexes[current_index]->search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, color_renames[current_index][0], color_renames[current_index][1], line)); + } } - current_line++; } - current_index++; } + current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_classes(String &file_content) { - int current_index = 0; - - // TODO Maybe it is better way to not rename gd, tscn and other files which are named as classes - while (class_renames[current_index][0]) { - // Begin renaming workaround `Resource.gd` -> `RefCounter.gd` - RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b"); - CRASH_COND(!reg_before.is_valid()); - file_content = reg_before.sub(file_content, "TEMP_RENAMED_CLASS.tscn", true); - RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b"); - CRASH_COND(!reg_before2.is_valid()); - file_content = reg_before2.sub(file_content, "TEMP_RENAMED_CLASS.gd", true); - RegEx reg_before3 = RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b"); - CRASH_COND(!reg_before3.is_valid()); - file_content = reg_before3.sub(file_content, "TEMP_RENAMED_CLASS.gd", true); - // End - - RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, class_renames[current_index][1], true); - - // Begin renaming workaround `Resource.gd` -> `RefCounter.gd` - RegEx reg_after = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b"); - CRASH_COND(!reg_after.is_valid()); - file_content = reg_after.sub(file_content, String(class_renames[current_index][0]) + ".tscn", true); - RegEx reg_after2 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b"); - CRASH_COND(!reg_after2.is_valid()); - file_content = reg_after2.sub(file_content, String(class_renames[current_index][0]) + ".gd", true); - RegEx reg_after3 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b"); - CRASH_COND(!reg_after3.is_valid()); - file_content = reg_after3.sub(file_content, String(class_renames[current_index][0]) + ".shader", true); - // End - - current_index++; - } - - // OS.get_ticks_msec -> Time.get_ticks_msec - RegEx reg_time1 = RegEx("OS.get_ticks_msec"); - CRASH_COND(!reg_time1.is_valid()); - file_content = reg_time1.sub(file_content, "Time.get_ticks_msec", true); - RegEx reg_time2 = RegEx("OS.get_ticks_usec"); - CRASH_COND(!reg_time2.is_valid()); - file_content = reg_time2.sub(file_content, "Time.get_ticks_usec", true); -}; - -Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &file_content) { - int current_index = 0; - - Vector<String> found_things; - - while (class_renames[current_index][0]) { - RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b"); - CRASH_COND(!reg_before.is_valid()); - RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b"); - CRASH_COND(!reg_before2.is_valid()); - - RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); +void ProjectConverter3To4::rename_classes(Vector<String> &lines, const RegExContainer ®_container) { + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { + if (line.contains(class_renames[current_index][0])) { + bool found_ignored_items = false; + // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn + if (line.contains(String(class_renames[current_index][0]) + ".")) { + found_ignored_items = true; + line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true); + line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true); + line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true); + } - int current_line = 1; - for (String &line : file_content) { - line = reg_before.sub(line, "TEMP_RENAMED_CLASS.tscn", true); - line = reg_before2.sub(line, "TEMP_RENAMED_CLASS.gd", true); + // Causal renaming Spatial -> Node3D + line = reg_container.class_regexes[current_index]->sub(line, class_renames[current_index][1], true); - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], line)); + // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn + if (found_ignored_items) { + line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true); + line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true); + line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true); + } + } } - current_line++; } - current_index++; } +}; + +Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer ®_container) { + Vector<String> found_renames; - // TODO OS -> TIME int current_line = 1; - RegEx reg_time1 = RegEx("OS.get_ticks_msec"); - CRASH_COND(!reg_time1.is_valid()); - RegEx reg_time2 = RegEx("OS.get_ticks_usec"); - CRASH_COND(!reg_time2.is_valid()); - for (String &line : file_content) { - String old = line; - line = reg_time1.sub(line, "Time.get_ticks_msec", true); - line = reg_time2.sub(line, "Time.get_ticks_usec", true); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { + if (line.contains(class_renames[current_index][0])) { + String old_line = line; + bool found_ignored_items = false; + // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn + if (line.contains(String(class_renames[current_index][0]) + ".")) { + found_ignored_items = true; + line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true); + line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true); + line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true); + } - if (old != line) { - found_things.append(simple_line_formatter(current_line, old, line)); + // Causal renaming Spatial -> Node3D + TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], old_line)); + } + + // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn + if (found_ignored_items) { + line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true); + line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true); + line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true); + } + } + } } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_gdscript_functions(String &file_content, const RegExContainer ®_container, bool builtin) { - Vector<String> lines = file_content.split("\n"); - +void ProjectConverter3To4::rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin) { for (String &line : lines) { - process_gdscript_line(line, reg_container, builtin); - } - - // Collect vector to string - file_content = ""; - for (int i = 0; i < lines.size(); i++) { - file_content += lines[i]; - - if (i != lines.size() - 1) { - file_content += "\n"; + if (uint64_t(line.length()) <= maximum_line_length) { + process_gdscript_line(line, reg_container, builtin); } } }; -Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer ®_container, bool builtin) { +Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin) { int current_line = 1; - Vector<String> found_things; + Vector<String> found_renames; - for (String &line : file_content) { - String old_line = line; - process_gdscript_line(line, reg_container, builtin); - if (old_line != line) { - found_things.append(simple_line_formatter(current_line, old_line, line)); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old_line = line; + process_gdscript_line(line, reg_container, builtin); + if (old_line != line) { + found_renames.append(simple_line_formatter(current_line, old_line, line)); + } } } - return found_things; + return found_renames; } + +// TODO, this function should run only on all .gd files and also on lines in tscn files which void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer ®_container, bool builtin) { - if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) { + // In this and other functions, reg.sub are used only after checking line with str.contains function which is sometimes few times faster with bigger line lengths + + if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) { line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); } - // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure - line = reg_container.reg_mixed_tab_space.sub(line, "$1", true); - // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray - line = reg_container.reg_join.sub(line, "$2.join($1)", true); + if (line.contains(".join")) { + line = reg_container.reg_join.sub(line, "$2.join($1)", true); + } // -- empty() -> is_empty() Pool*Array - line = reg_container.reg_is_empty.sub(line, "is_empty(", true); + if (line.contains("empty")) { + line = reg_container.reg_is_empty.sub(line, "is_empty(", true); + } // -- \t.func() -> \tsuper.func() Object - line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore" + if (line.contains("(") && line.contains(".")) { + line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this broke String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore" + } // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON - line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + if (line.contains("parse")) { + line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + } // -- to_json(a) -> JSON.new().stringify(a) Object - line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true); - + if (line.contains("to_json")) { + line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true); + } // -- parse_json(a) -> JSON.get_data() etc. Object - line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + if (line.contains("parse_json")) { + line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + } // -- get_node(@ -> get_node( Node - line = line.replace("get_node(@", "get_node("); + if (line.contains("get_node")) { + line = line.replace("get_node(@", "get_node("); + } // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript - line = reg_container.reg_export.sub(line, "export var $2: $1"); + if (line.contains("export")) { + line = reg_container.reg_export.sub(line, "export var $2: $1"); + } // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript - line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)"); + if (line.contains("export")) { + line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)"); + } // Setget Setget - line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + if (line.contains("setget")) { + line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + } // Setget set - line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + if (line.contains("setget")) { + line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + } // Setget get - line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); + if (line.contains("setget")) { + line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); + } // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true) - if (builtin) { - line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true); - } else { - line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true); + if (line.contains("window_fullscreen")) { + if (builtin) { + line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true); + } else { + line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true); + } } // Instantiate - line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true); + if (line.contains("instance")) { + line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true); + } // -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide(") != -1) { + if (line.contains(("move_and_slide("))) { int start = line.find("move_and_slide("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2911,7 +3119,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide_with_snap(") != -1) { + if (line.contains("move_and_slide_with_snap(")) { int start = line.find("move_and_slide_with_snap("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2962,7 +3170,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object - if (line.find("sort_custom(") != -1) { + if (line.contains("sort_custom(")) { int start = line.find("sort_custom("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2974,7 +3182,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- list_dir_begin( ) -> list_dir_begin() Object - if (line.find("list_dir_begin(") != -1) { + if (line.contains("list_dir_begin(")) { int start = line.find("list_dir_begin("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2983,7 +3191,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem - if (line.find("draw_line(") != -1) { + if (line.contains("draw_line(")) { int start = line.find("draw_line("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2995,7 +3203,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- func c(var a, var b) -> func c(a, b) - if (line.find("func ") != -1 && line.find("var ") != -1) { + if (line.contains("func ") && line.contains("var ")) { int start = line.find("func "); start = line.substr(start).find("(") + start; int end = get_end_parenthess(line.substr(start)) + 1; @@ -3014,7 +3222,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- yield(this, \"timeout\") -> await this.timeout GDScript - if (line.find("yield(") != -1) { + if (line.contains("yield(")) { int start = line.find("yield("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3030,7 +3238,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- parse_json( AA ) -> TODO Object - if (line.find("parse_json(") != -1) { + if (line.contains("parse_json(")) { int start = line.find("parse_json("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3040,7 +3248,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform - if (line.find(".xform(") != -1) { + if (line.contains(".xform(")) { int start = line.find(".xform("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3052,12 +3260,12 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform - if (line.find(".xform_inv(") != -1) { + if (line.contains(".xform_inv(")) { int start = line.find(".xform_inv("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { String object_exec = get_object_of_execution(line.substr(0, start)); - if (line.find(object_exec + ".xform") != -1) { + if (line.contains(object_exec + ".xform")) { int start2 = line.find(object_exec + ".xform"); Vector<String> parts = parse_arguments(line.substr(start, end)); if (parts.size() == 1) { @@ -3068,7 +3276,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- "(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) Object - if (line.find("connect(") != -1) { + if (line.contains("connect(")) { int start = line.find("connect("); // Protection from disconnect if (start == 0 || line.get(start - 1) != 's') { @@ -3084,7 +3292,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object - if (line.find("disconnect(") != -1) { + if (line.contains("disconnect(")) { int start = line.find("disconnect("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3095,7 +3303,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object - if (line.find("is_connected(") != -1) { + if (line.contains("is_connected(")) { int start = line.find("is_connected("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3107,7 +3315,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- "(tween_method(A,B,C,D,E) != OK):", "(tween_method(Callable(A,B),C,D,E) Object // -- "(tween_method(A,B,C,D,E,[F,G]) != OK):", "(tween_method(Callable(A,B).bind(F,G),C,D,E) Object - if (line.find("tween_method(") != -1) { + if (line.contains("tween_method(")) { int start = line.find("tween_method("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3120,7 +3328,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- "(tween_callback(A,B,[C,D]) != OK):", "(connect(Callable(A,B).bind(C,D)) Object - if (line.find("tween_callback(") != -1) { + if (line.contains("tween_callback(")) { int start = line.find("tween_callback("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3134,7 +3342,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- start(a,b) -> start(Callable(a,b)) Thread // -- start(a,b,c,d) -> start(Callable(a,b).bind(c),d) Thread - if (line.find("start(") != -1) { + if (line.contains("start(")) { int start = line.find("start("); int end = get_end_parenthess(line.substr(start)) + 1; // Protection from 'func start' @@ -3150,16 +3358,18 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589 - if (line.find(" _init(") != -1) { + if (line.contains(" _init(")) { int start = line.find(" _init("); - int end = line.rfind(":") + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start); + if (line.contains(":")) { + int end = line.rfind(":") + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start); + } } } // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message - if (line.find("assert(") != -1) { + if (line.contains("assert(")) { int start = line.find("assert("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3170,7 +3380,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture - if (line.find("create_from_image(") != -1) { + if (line.contains("create_from_image(")) { int start = line.find("create_from_image("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3181,7 +3391,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e) - if (line.find("set_cell_item(") != -1) { + if (line.contains("set_cell_item(")) { int start = line.find("set_cell_item("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3192,7 +3402,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c)) - if (line.find("get_cell_item(") != -1) { + if (line.contains("get_cell_item(")) { int start = line.find("get_cell_item("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3203,7 +3413,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c)) - if (line.find("get_cell_item_orientation(") != -1) { + if (line.contains("get_cell_item_orientation(")) { int start = line.find("get_cell_item_orientation("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3214,7 +3424,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // apply_impulse(A, B) -> apply_impulse(B, A) - if (line.find("apply_impulse(") != -1) { + if (line.contains("apply_impulse(")) { int start = line.find("apply_impulse("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3225,7 +3435,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // apply_force(A, B) -> apply_force(B, A) - if (line.find("apply_force(") != -1) { + if (line.contains("apply_force(")) { int start = line.find("apply_force("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3236,7 +3446,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c)) - if (line.find("map_to_world(") != -1) { + if (line.contains("map_to_world(")) { int start = line.find("map_to_world("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3247,7 +3457,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // OS.get_window_safe_area() -> DisplayServer.get_display_safe_area() - if (line.find("OS.get_window_safe_area(") != -1) { + if (line.contains("OS.get_window_safe_area(")) { int start = line.find("OS.get_window_safe_area("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3257,14 +3467,59 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } } + // draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOGODOT4 Antialiasing argument is missing + if (line.contains("draw_rect(")) { + int start = line.find("draw_rect("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 5) { + line = line.substr(0, start) + "draw_rect(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing"; + } + } + } + // get_focus_owner() -> get_viewport().gui_get_focus_owner() + if (line.contains("get_focus_owner()")) { + line = line.replace("get_focus_owner()", "get_viewport().gui_get_focus_owner()"); + } + + // button.pressed = 1 -> button.button_pressed = 1 + if (line.contains(".pressed")) { + int start = line.find(".pressed"); + bool foundNextEqual = false; + String line_to_check = line.substr(start + String(".pressed").length()); + for (int current_index = 0; line_to_check.length() > current_index; current_index++) { + char32_t chr = line_to_check.get(current_index); + if (chr == '\t' || chr == ' ') { + continue; + } else if (chr == '=') { + foundNextEqual = true; + } else { + break; + } + } + if (foundNextEqual) { + line = line.substr(0, start) + ".button_pressed" + line.substr(start + String(".pressed").length()); + } + } + + // OS -> Time functions + if (line.contains("OS.get_ticks_msec")) { + line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec"); + } + if (line.contains("OS.get_ticks_usec")) { + line = line.replace("OS.get_ticks_usec", "Time.get_ticks_usec"); + } + if (line.contains("OS.get_unix_time")) { + line = line.replace("OS.get_unix_time", "Time.get_unix_time_from_system"); + } } -void ProjectConverter3To4::process_csharp_line(String &line) { - // TODO maybe this can be changed to normal rule +void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer ®_container) { line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()"); // -- Connect(,,,things) -> Connect(,Callable(,),things) Object - if (line.find("Connect(") != -1) { + if (line.contains("Connect(")) { int start = line.find("Connect("); // Protection from disconnect if (start == 0 || line.get(start - 1) != 's') { @@ -3278,7 +3533,7 @@ void ProjectConverter3To4::process_csharp_line(String &line) { } } // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object - if (line.find("Disconnect(") != -1) { + if (line.contains("Disconnect(")) { int start = line.find("Disconnect("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3289,7 +3544,7 @@ void ProjectConverter3To4::process_csharp_line(String &line) { } } // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object - if (line.find("IsConnected(") != -1) { + if (line.contains("IsConnected(")) { int start = line.find("IsConnected("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3301,415 +3556,317 @@ void ProjectConverter3To4::process_csharp_line(String &line) { } } -void ProjectConverter3To4::rename_csharp_functions(String &file_content) { - Vector<String> lines = file_content.split("\n"); - +void ProjectConverter3To4::rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container) { for (String &line : lines) { - process_csharp_line(line); - } - - // Collect vector to string - file_content = ""; - for (int i = 0; i < lines.size(); i++) { - file_content += lines[i]; - - if (i != lines.size() - 1) { - file_content += "\n"; + if (uint64_t(line.length()) <= maximum_line_length) { + process_csharp_line(line, reg_container); } } }; -// This is almost 1:1 copy of function which rename gdscript functions -Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &file_content) { +Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container) { int current_line = 1; - Vector<String> found_things; + Vector<String> found_renames; - for (String &line : file_content) { - String old_line = line; - process_csharp_line(line); - if (old_line != line) { - found_things.append(simple_line_formatter(current_line, old_line, line)); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old_line = line; + process_csharp_line(line, reg_container); + if (old_line != line) { + found_renames.append(simple_line_formatter(current_line, old_line, line)); + } } } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_csharp_attributes(String &file_content) { - // -- [Remote] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer)] - { - RegEx reg_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remote.is_valid()); - file_content = reg_remote.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); - } - // -- [RemoteSync] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)] - { - RegEx reg_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remotesync.is_valid()); - file_content = reg_remotesync.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); - } - // -- [Puppet] -> [RPC] - { - RegEx reg_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_puppet.is_valid()); - file_content = reg_puppet.sub(file_content, "[RPC]", true); - } - // -- [PuppetSync] -> [RPC(CallLocal = true)] - { - RegEx reg_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_puppetsync.is_valid()); - file_content = reg_puppetsync.sub(file_content, "[RPC(CallLocal = true)]", true); - } - String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n"; - // -- [Master] -> [RPC] - { - RegEx reg_remote = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remote.is_valid()); - file_content = reg_remote.sub(file_content, error_message + "[RPC]", true); - } - // -- [MasterSync] -> [RPC(CallLocal = true)] - { - RegEx reg_remote = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remote.is_valid()); - file_content = reg_remote.sub(file_content, error_message + "[RPC(CallLocal = true)]", true); +void ProjectConverter3To4::rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container) { + static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n"; + + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); + line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); + line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true); + line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true); + line = reg_container.keyword_csharp_master.sub(line, error_message + "[RPC]", true); + line = reg_container.keyword_csharp_mastersync.sub(line, error_message + "[RPC(CallLocal = true)]", true); + } } } -Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &file_content) { +Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container) { int current_line = 1; - Vector<String> found_things; + Vector<String> found_renames; - for (String &line : file_content) { - String old; - old = line; - { - RegEx regex = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[Puppet(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[Puppet]", "[RPC]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[(Puppet|Slave)Sync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(CallLocal = true)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[Master]", "[RPC]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(CallLocal = true)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line)); - } + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old; + old = line; + line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line)); + } + old = line; + line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line)); + } + + old = line; + line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[Puppet]", "[RPC]", line)); + } + + old = line; + line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line)); + } + + old = line; + line = reg_container.keyword_csharp_master.sub(line, "[RPC]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[Master]", "[RPC]", line)); + } + + old = line; + line = reg_container.keyword_csharp_mastersync.sub(line, "[RPC(CallLocal = true)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line)); + } + } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_gdscript_keywords(String &file_content) { - { - RegEx reg_first = RegEx("([\n]+)tool"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@tool", true); - RegEx reg_second = RegEx("^tool"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@tool", true); - } - { - RegEx reg_first = RegEx("([\n\t]+)export\\b"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@export", true); - RegEx reg_second = RegEx("^export"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@export", true); - } - { - RegEx reg_first = RegEx("([\n]+)onready"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@onready", true); - RegEx reg_second = RegEx("^onready"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@onready", true); - } - { - RegEx reg_first = RegEx("([\n]+)remote func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(any_peer) func", true); - RegEx reg_second = RegEx("^remote func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(any_peer) func", true); - } - { - RegEx reg_first = RegEx("([\n]+)remotesync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true); - RegEx reg_second = RegEx("^remotesync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true); - } - { - RegEx reg_first = RegEx("([\n]+)sync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true); - RegEx reg_second = RegEx("^sync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true); - } - { - RegEx reg_first = RegEx("([\n]+)slave func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc func", true); - RegEx reg_second = RegEx("^slave func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc func", true); - } - { - RegEx reg_first = RegEx("([\n]+)puppet func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc func", true); - RegEx reg_second = RegEx("^puppet func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc func", true); - } - { - RegEx reg_first = RegEx("([\n]+)puppetsync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(call_local) func", true); - RegEx reg_second = RegEx("^puppetsync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(call_local) func", true); - } - String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n"; - { - RegEx reg_first = RegEx("([\n]+)master func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc func", true); - RegEx reg_second = RegEx("^master func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, error_message + "@rpc func", true); - } - { - RegEx reg_first = RegEx("([\n]+)mastersync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc(call_local) func", true); - RegEx reg_second = RegEx("^mastersync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, error_message + "@rpc(call_local) func", true); +void ProjectConverter3To4::rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container) { + static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n"; + + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + if (line.contains("tool")) { + line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true); + } + if (line.contains("export")) { + line = reg_container.keyword_gdscript_export_single.sub(line, "@export", true); + } + if (line.contains("export")) { + line = reg_container.keyword_gdscript_export_mutli.sub(line, "$1@export", true); + } + if (line.contains("onready")) { + line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true); + } + if (line.contains("remote")) { + line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true); + } + if (line.contains("remote")) { + line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local) func", true); + } + if (line.contains("sync")) { + line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local) func", true); + } + if (line.contains("slave")) { + line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true); + } + if (line.contains("puppet")) { + line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true); + } + if (line.contains("puppet")) { + line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true); + } + if (line.contains("master")) { + line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true); + } + if (line.contains("master")) { + line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(call_local) func", true); + } + } } } -Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &file_content) { - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container) { + Vector<String> found_renames; int current_line = 1; + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old; + + if (line.contains("tool")) { + old = line; + line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "tool", "@tool", line)); + } + } - for (String &line : file_content) { - String old; - old = line; - { - RegEx reg_first = RegEx("^tool"); - CRASH_COND(!reg_first.is_valid()); - line = reg_first.sub(line, "@tool", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "tool", "@tool", line)); - } - old = line; - { - RegEx reg_first = RegEx("([\t]+)export\\b"); - CRASH_COND(!reg_first.is_valid()); - line = reg_first.sub(line, "$1@export", true); - RegEx reg_second = RegEx("^export"); - CRASH_COND(!reg_second.is_valid()); - line = reg_second.sub(line, "@export", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "export", "@export", line)); - } - old = line; - { - RegEx reg_first = RegEx("^onready"); - CRASH_COND(!reg_first.is_valid()); - line = reg_first.sub(line, "@onready", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "onready", "@onready", line)); - } - old = line; - { - RegEx regex = RegEx("^remote func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(any_peer) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line)); - } - old = line; - { - RegEx regex = RegEx("^remotesync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(any_peer, call_local)) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line)); - } - old = line; - { - RegEx regex = RegEx("^sync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(any_peer, call_local)) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line)); - } - old = line; - { - RegEx regex = RegEx("^slave func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "slave func", "@rpc func", line)); - } - old = line; - { - RegEx regex = RegEx("^puppet func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "puppet func", "@rpc func", line)); - } - old = line; - { - RegEx regex = RegEx("^puppetsync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(call_local) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line)); - } - old = line; - { - RegEx regex = RegEx("^master func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "master func", "@rpc func", line)); - } - old = line; - { - RegEx regex = RegEx("^mastersync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(call_local) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line)); - } - old = line; + if (line.contains("export")) { + old = line; + line = reg_container.keyword_gdscript_export_single.sub(line, "$1@export", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "export", "@export", line)); + } + } + if (line.contains("export")) { + old = line; + line = reg_container.keyword_gdscript_export_mutli.sub(line, "@export", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "export", "@export", line)); + } + } + + if (line.contains("onready")) { + old = line; + line = reg_container.keyword_gdscript_tool.sub(line, "@onready", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "onready", "@onready", line)); + } + } + + if (line.contains("remote")) { + old = line; + line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line)); + } + } + + if (line.contains("remote")) { + old = line; + line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local)) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line)); + } + } + + if (line.contains("sync")) { + old = line; + line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local)) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line)); + } + } + + if (line.contains("slave")) { + old = line; + line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "slave func", "@rpc func", line)); + } + } + + if (line.contains("puppet")) { + old = line; + line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "puppet func", "@rpc func", line)); + } + } + + if (line.contains("puppet")) { + old = line; + line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line)); + } + } + + if (line.contains("master")) { + old = line; + line = reg_container.keyword_gdscript_master.sub(line, "@rpc func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "master func", "@rpc func", line)); + } + } + + if (line.contains("master")) { + old = line; + line = reg_container.keyword_gdscript_master.sub(line, "@rpc(call_local) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line)); + } + } + } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::custom_rename(String &file_content, String from, String to) { +void ProjectConverter3To4::custom_rename(Vector<String> &lines, String from, String to) { RegEx reg = RegEx(String("\\b") + from + "\\b"); CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, to, true); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + line = reg.sub(line, to, true); + } + } }; -Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &file_content, String from, String to) { - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, String from, String to) { + Vector<String> found_renames; RegEx reg = RegEx(String("\\b") + from + "\\b"); CRASH_COND(!reg.is_valid()); int current_line = 1; - for (String &line : file_content) { - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader" + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + TypedArray<RegExMatch> reg_match = reg.search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader" + } } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_common(const char *array[][2], String &file_content) { - int current_index = 0; - while (array[current_index][0]) { - RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, array[current_index][1], true); - current_index++; +void ProjectConverter3To4::rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) { + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) { + if (line.contains(array[current_index][0])) { + line = cached_regexes[current_index]->sub(line, array[current_index][1], true); + } + } + } } } -// Common renaming, -Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], Vector<String> &file_content) { - int current_index = 0; - - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) { + Vector<String> found_renames; - while (array[current_index][0]) { - RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); + int current_line = 1; - int current_line = 1; - for (String &line : file_content) { - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line)); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) { + if (line.contains(array[current_index][0])) { + TypedArray<RegExMatch> reg_match = cached_regexes[current_index]->search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line)); + } + } } - current_line++; } - current_index++; + current_line++; } - return found_things; + + return found_renames; } -// Formats data to print them into user console when trying to convert data +// Prints full info about renamed things e.g.: +// Line (67) remove -> remove_at - LINE """ doubler._blacklist.remove(0) """ String ProjectConverter3To4::line_formatter(int current_line, String from, String to, String line) { if (from.size() > 200) { from = from.substr(0, 197) + "..."; @@ -3723,6 +3880,8 @@ String ProjectConverter3To4::line_formatter(int current_line, String from, Strin return String("Line (") + itos(current_line) + ") " + from.replace("\r", "").replace("\n", "") + " -> " + to.replace("\r", "").replace("\n", "") + " - LINE \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\""; } +// Prints only full lines e.g.: +// Line (1) - FULL LINES - """yield(get_tree().create_timer(3), 'timeout')""" =====> """ await get_tree().create_timer(3).timeout """ String ProjectConverter3To4::simple_line_formatter(int current_line, String old_line, String line) { if (old_line.size() > 1000) { old_line = old_line.substr(0, 997) + "..."; @@ -3733,6 +3892,19 @@ String ProjectConverter3To4::simple_line_formatter(int current_line, String old_ return String("Line (") + itos(current_line) + ") - FULL LINES - \"\"\"" + old_line.replace("\r", "").replace("\n", "").strip_edges() + "\"\"\" =====> \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\""; } +// Collects string from vector strings +String ProjectConverter3To4::collect_string_from_vector(Vector<String> &vector) { + String string = ""; + for (int i = 0; i < vector.size(); i++) { + string += vector[i]; + + if (i != vector.size() - 1) { + string += "\n"; + } + } + return string; +} + #else // No regex. int ProjectConverter3To4::convert() { diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h index 8526e2ceb9..fc6d66c9a8 100644 --- a/editor/project_converter_3_to_4.h +++ b/editor/project_converter_3_to_4.h @@ -35,37 +35,43 @@ #include "core/io/file_access.h" #include "core/object/ref_counted.h" #include "core/string/ustring.h" +#include "core/templates/local_vector.h" + +class RegEx; class ProjectConverter3To4 { public: class RegExContainer; private: - void rename_enums(String &file_content); - Vector<String> check_for_rename_enums(Vector<String> &file_content); + uint64_t maximum_file_size; + uint64_t maximum_line_length; + + void rename_colors(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_colors(Vector<String> &lines, const RegExContainer ®_container); - void rename_classes(String &file_content); - Vector<String> check_for_rename_classes(Vector<String> &file_content); + void rename_classes(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_classes(Vector<String> &lines, const RegExContainer ®_container); - void rename_gdscript_functions(String &file_content, const RegExContainer ®_container, bool builtin); - Vector<String> check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer ®_container, bool builtin); + void rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin); + Vector<String> check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin); void process_gdscript_line(String &line, const RegExContainer ®_container, bool builtin); - void rename_csharp_functions(String &file_content); - Vector<String> check_for_rename_csharp_functions(Vector<String> &file_content); - void process_csharp_line(String &line); + void rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container); + void process_csharp_line(String &line, const RegExContainer ®_container); - void rename_csharp_attributes(String &file_content); - Vector<String> check_for_rename_csharp_attributes(Vector<String> &file_content); + void rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container); - void rename_gdscript_keywords(String &file_content); - Vector<String> check_for_rename_gdscript_keywords(Vector<String> &file_content); + void rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container); - void custom_rename(String &file_content, String from, String to); - Vector<String> check_for_custom_rename(Vector<String> &file_content, String from, String to); + void custom_rename(Vector<String> &lines, String from, String to); + Vector<String> check_for_custom_rename(Vector<String> &lines, String from, String to); - void rename_common(const char *array[][2], String &file_content); - Vector<String> check_for_rename_common(const char *array[][2], Vector<String> &file_content); + void rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines); + Vector<String> check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines); Vector<String> check_for_files(); @@ -77,15 +83,17 @@ private: String line_formatter(int current_line, String from, String to, String line); String simple_line_formatter(int current_line, String old_line, String line); + String collect_string_from_vector(Vector<String> &vector); bool test_single_array(const char *array[][2], bool ignore_second_check = false); - bool test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what); - bool test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin); - bool test_conversion_single_normal(String name, String expected, const char *array[][2], String what); + bool test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin); + bool test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer ®_container); + bool test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, String what); bool test_array_names(); - bool test_conversion(const RegExContainer ®_container); + bool test_conversion(RegExContainer ®_container); public: + ProjectConverter3To4(int, int); int validate_conversion(); int convert(); }; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index cce71d9508..ed8c7b14c8 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -438,7 +438,7 @@ private: ProjectSettings::CustomMap edited_settings; edited_settings["application/config/name"] = project_name->get_text().strip_edges(); - if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) { + if (current->save_custom(dir2.path_join("project.godot"), edited_settings, Vector<String>(), true) != OK) { set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR); } } @@ -486,12 +486,12 @@ private: initial_settings["application/config/name"] = project_name->get_text().strip_edges(); initial_settings["application/config/icon"] = "res://icon.svg"; - if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) { + if (ProjectSettings::get_singleton()->save_custom(dir.path_join("project.godot"), initial_settings, Vector<String>(), false) != OK) { set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR); } else { // Store default project icon in SVG format. Error err; - Ref<FileAccess> fa_icon = FileAccess::open(dir.plus_file("icon.svg"), FileAccess::WRITE, &err); + Ref<FileAccess> fa_icon = FileAccess::open(dir.path_join("icon.svg"), FileAccess::WRITE, &err); fa_icon->store_string(get_default_project_icon()); if (err != OK) { @@ -556,7 +556,7 @@ private: String rel_path = path.substr(zip_root.length()); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - da->make_dir(dir.plus_file(rel_path)); + da->make_dir(dir.path_join(rel_path)); } else { Vector<uint8_t> data; data.resize(info.uncompressed_size); @@ -568,7 +568,7 @@ private: ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", rel_path)); unzCloseCurrentFile(pkg); - Ref<FileAccess> f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(dir.path_join(rel_path), FileAccess::WRITE); if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); } else { @@ -962,12 +962,12 @@ public: switch (p_what) { case NOTIFICATION_MOUSE_ENTER: { hover = true; - update(); + queue_redraw(); } break; case NOTIFICATION_MOUSE_EXIT: { hover = false; - update(); + queue_redraw(); } break; case NOTIFICATION_DRAW: { @@ -1126,7 +1126,7 @@ ProjectList::ProjectList() { _icon_load_index = 0; project_opening_initiated = false; - _config_path = EditorPaths::get_singleton()->get_data_dir().plus_file("projects.cfg"); + _config_path = EditorPaths::get_singleton()->get_data_dir().path_join("projects.cfg"); } ProjectList::~ProjectList() { @@ -1185,7 +1185,7 @@ void ProjectList::load_project_icon(int p_index) { // Load project data from p_property_key and return it in a ProjectList::Item. p_favorite is passed directly into the Item. ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_favorite) { - String conf = p_path.plus_file("project.godot"); + String conf = p_path.path_join("project.godot"); bool grayed = false; bool missing = false; @@ -1221,7 +1221,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa // when editing a project (but not when running it). last_edited = FileAccess::get_modified_time(conf); - String fscache = p_path.plus_file(".fscache"); + String fscache = p_path.path_join(".fscache"); if (FileAccess::exists(fscache)) { uint64_t cache_modified = FileAccess::get_modified_time(fscache); if (cache_modified > last_edited) { @@ -1321,7 +1321,7 @@ void ProjectList::update_dock_menu() { } favs_added = 0; } - DisplayServer::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", callable_mp(this, &ProjectList::_global_menu_open_project), i); + DisplayServer::get_singleton()->global_menu_add_item("_dock", _projects[i].project_name + " ( " + _projects[i].path + " )", callable_mp(this, &ProjectList::_global_menu_open_project), Callable(), i); total_added++; } } @@ -1341,7 +1341,7 @@ void ProjectList::_global_menu_open_project(const Variant &p_tag) { int idx = (int)p_tag; if (idx >= 0 && idx < _projects.size()) { - String conf = _projects[idx].path.plus_file("project.godot"); + String conf = _projects[idx].path.path_join("project.godot"); List<String> args; args.push_back(conf); OS::get_singleton()->create_instance(args); @@ -1362,7 +1362,7 @@ void ProjectList::create_project_item_control(int p_index) { hb->connect("draw", callable_mp(this, &ProjectList::_panel_draw).bind(hb)); hb->connect("gui_input", callable_mp(this, &ProjectList::_panel_input).bind(hb)); hb->add_theme_constant_override("separation", 10 * EDSCALE); - hb->set_tooltip(item.description); + hb->set_tooltip_text(item.description); VBoxContainer *favorite_box = memnew(VBoxContainer); favorite_box->set_name("FavoriteBox"); @@ -1445,9 +1445,9 @@ void ProjectList::create_project_item_control(int p_index) { if (!item.missing) { show->connect("pressed", callable_mp(this, &ProjectList::_show_project).bind(item.path)); - show->set_tooltip(TTR("Show in File Manager")); + show->set_tooltip_text(TTR("Show in File Manager")); } else { - show->set_tooltip(TTR("Error: Project is missing on the filesystem.")); + show->set_tooltip_text(TTR("Error: Project is missing on the filesystem.")); } Label *fpath = memnew(Label(item.path)); @@ -1682,7 +1682,7 @@ void ProjectList::select_project(int p_index) { _selected_project_paths.clear(); for (int i = 0; i < previous_selected_items.size(); ++i) { - previous_selected_items[i].control->update(); + previous_selected_items[i].control->queue_redraw(); } toggle_select(p_index); @@ -1728,7 +1728,7 @@ void ProjectList::toggle_select(int p_index) { } else { _selected_project_paths.insert(item.path); } - item.control->update(); + item.control->queue_redraw(); } void ProjectList::erase_selected_projects(bool p_delete_project_contents) { @@ -1860,7 +1860,7 @@ void ProjectManager::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT); - update(); + queue_redraw(); } break; case NOTIFICATION_ENTER_TREE: { @@ -2106,13 +2106,13 @@ void ProjectManager::_confirm_update_settings() { void ProjectManager::_open_selected_projects() { // Show loading text to tell the user that the project manager is busy loading. - // This is especially important for the HTML5 project manager. + // This is especially important for the Web project manager. loading_label->show(); const HashSet<String> &selected_list = _project_list->get_selected_project_keys(); for (const String &path : selected_list) { - String conf = path.plus_file("project.godot"); + String conf = path.path_join("project.godot"); if (!FileAccess::exists(conf)) { dialog_error->set_text(vformat(TTR("Can't open project at '%s'."), path)); @@ -2162,7 +2162,7 @@ void ProjectManager::_open_selected_projects_ask() { } // Update the project settings or don't open - const String conf = project.path.plus_file("project.godot"); + const String conf = project.path.path_join("project.godot"); const int config_version = project.version; PackedStringArray unsupported_features = project.unsupported_features; @@ -2235,7 +2235,7 @@ void ProjectManager::_run_project_confirm() { const String &path = selected_list[i].path; // `.substr(6)` on `ProjectSettings::get_singleton()->get_imported_files_path()` strips away the leading "res://". - if (!DirAccess::exists(path.plus_file(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) { + if (!DirAccess::exists(path.path_join(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) { run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import.")); run_error_diag->popup_centered(); continue; @@ -2280,7 +2280,7 @@ void ProjectManager::_scan_dir(const String &path) { String n = da->get_next(); while (!n.is_empty()) { if (da->current_is_dir() && !n.begins_with(".")) { - _scan_dir(da->get_current_dir().plus_file(n)); + _scan_dir(da->get_current_dir().path_join(n)); } else if (n == "project.godot") { _project_list->add_project(da->get_current_dir(), false); } @@ -2570,7 +2570,7 @@ ProjectManager::ProjectManager() { search_box = memnew(LineEdit); search_box->set_placeholder(TTR("Filter Projects")); - search_box->set_tooltip(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character.")); + search_box->set_tooltip_text(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character.")); search_box->connect("text_changed", callable_mp(this, &ProjectManager::_on_search_term_changed)); search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); hb->add_child(search_box); @@ -2710,7 +2710,7 @@ ProjectManager::ProjectManager() { // Fade the version label to be less prominent, but still readable. version_btn->set_self_modulate(Color(1, 1, 1, 0.6)); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip(TTR("Click to copy.")); + version_btn->set_tooltip_text(TTR("Click to copy.")); version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed)); spacer_vb->add_child(version_btn); diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 84923a94a2..300a3d0f05 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -139,7 +139,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR but_insert_name = memnew(Button); but_insert_name->set_text("NAME"); - but_insert_name->set_tooltip(String("${NAME}\n") + TTR("Node name.")); + but_insert_name->set_tooltip_text(String("${NAME}\n") + TTR("Node name.")); but_insert_name->set_focus_mode(Control::FOCUS_NONE); but_insert_name->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${NAME}")); but_insert_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -149,7 +149,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR but_insert_parent = memnew(Button); but_insert_parent->set_text("PARENT"); - but_insert_parent->set_tooltip(String("${PARENT}\n") + TTR("Node's parent name, if available.")); + but_insert_parent->set_tooltip_text(String("${PARENT}\n") + TTR("Node's parent name, if available.")); but_insert_parent->set_focus_mode(Control::FOCUS_NONE); but_insert_parent->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${PARENT}")); but_insert_parent->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -159,7 +159,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR but_insert_type = memnew(Button); but_insert_type->set_text("TYPE"); - but_insert_type->set_tooltip(String("${TYPE}\n") + TTR("Node type.")); + but_insert_type->set_tooltip_text(String("${TYPE}\n") + TTR("Node type.")); but_insert_type->set_focus_mode(Control::FOCUS_NONE); but_insert_type->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${TYPE}")); but_insert_type->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -169,7 +169,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR but_insert_scene = memnew(Button); but_insert_scene->set_text("SCENE"); - but_insert_scene->set_tooltip(String("${SCENE}\n") + TTR("Current scene name.")); + but_insert_scene->set_tooltip_text(String("${SCENE}\n") + TTR("Current scene name.")); but_insert_scene->set_focus_mode(Control::FOCUS_NONE); but_insert_scene->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${SCENE}")); but_insert_scene->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -179,7 +179,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR but_insert_root = memnew(Button); but_insert_root->set_text("ROOT"); - but_insert_root->set_tooltip(String("${ROOT}\n") + TTR("Root node name.")); + but_insert_root->set_tooltip_text(String("${ROOT}\n") + TTR("Root node name.")); but_insert_root->set_focus_mode(Control::FOCUS_NONE); but_insert_root->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${ROOT}")); but_insert_root->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -189,7 +189,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR but_insert_count = memnew(Button); but_insert_count->set_text("COUNTER"); - but_insert_count->set_tooltip(String("${COUNTER}\n") + TTR("Sequential integer counter.\nCompare counter options.")); + but_insert_count->set_tooltip_text(String("${COUNTER}\n") + TTR("Sequential integer counter.\nCompare counter options.")); but_insert_count->set_focus_mode(Control::FOCUS_NONE); but_insert_count->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${COUNTER}")); but_insert_count->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -197,7 +197,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR chk_per_level_counter = memnew(CheckBox); chk_per_level_counter->set_text(TTR("Per-level Counter")); - chk_per_level_counter->set_tooltip(TTR("If set, the counter restarts for each group of child nodes.")); + chk_per_level_counter->set_tooltip_text(TTR("If set, the counter restarts for each group of child nodes.")); vbc_substitute->add_child(chk_per_level_counter); HBoxContainer *hbc_count_options = memnew(HBoxContainer); @@ -205,32 +205,32 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoR Label *lbl_count_start = memnew(Label); lbl_count_start->set_text(TTR("Start")); - lbl_count_start->set_tooltip(TTR("Initial value for the counter.")); + lbl_count_start->set_tooltip_text(TTR("Initial value for the counter.")); hbc_count_options->add_child(lbl_count_start); spn_count_start = memnew(SpinBox); - spn_count_start->set_tooltip(TTR("Initial value for the counter.")); + spn_count_start->set_tooltip_text(TTR("Initial value for the counter.")); spn_count_start->set_step(1); spn_count_start->set_min(0); hbc_count_options->add_child(spn_count_start); Label *lbl_count_step = memnew(Label); lbl_count_step->set_text(TTR("Step")); - lbl_count_step->set_tooltip(TTR("Amount by which counter is incremented for each node.")); + lbl_count_step->set_tooltip_text(TTR("Amount by which counter is incremented for each node.")); hbc_count_options->add_child(lbl_count_step); spn_count_step = memnew(SpinBox); - spn_count_step->set_tooltip(TTR("Amount by which counter is incremented for each node.")); + spn_count_step->set_tooltip_text(TTR("Amount by which counter is incremented for each node.")); spn_count_step->set_step(1); hbc_count_options->add_child(spn_count_step); Label *lbl_count_padding = memnew(Label); lbl_count_padding->set_text(TTR("Padding")); - lbl_count_padding->set_tooltip(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros.")); + lbl_count_padding->set_tooltip_text(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros.")); hbc_count_options->add_child(lbl_count_padding); spn_count_padding = memnew(SpinBox); - spn_count_padding->set_tooltip(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros.")); + spn_count_padding->set_tooltip_text(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros.")); spn_count_padding->set_step(1); hbc_count_options->add_child(spn_count_padding); @@ -500,7 +500,7 @@ String RenameDialog::_postprocess(const String &subject) { if (style_id == 1) { // PascalCase to snake_case - result = result.camelcase_to_underscore(true); + result = result.to_snake_case(); result = _regex("_+", result, "_"); } else if (style_id == 2) { @@ -521,7 +521,7 @@ String RenameDialog::_postprocess(const String &subject) { end = start + 1; } buffer += result.substr(end, result.size() - (end + 1)); - result = buffer.replace("_", "").capitalize(); + result = buffer.to_pascal_case(); } } diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp index 94a5c07709..9b8684b7b8 100644 --- a/editor/scene_create_dialog.cpp +++ b/editor/scene_create_dialog.cpp @@ -111,7 +111,7 @@ void SceneCreateDialog::update_dialog() { } if (is_valid) { - scene_name = directory.plus_file(scene_name); + scene_name = directory.path_join(scene_name); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->file_exists(scene_name)) { update_error(file_error_label, MSG_ERROR, TTR("File already exists.")); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 9f80119c35..e2265f2f83 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -240,7 +240,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name); - editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(new_name))); } editor_data->get_undo_redo()->commit_action(); @@ -691,7 +691,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); editor_data->get_undo_redo()->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name()); - editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name()))); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name()))); add_below_node = dup; } @@ -1068,24 +1068,61 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } break; case TOOL_TOGGLE_SCENE_UNIQUE_NAME: { - List<Node *> selection = editor_selection->get_selected_node_list(); - List<Node *>::Element *e = selection.front(); - if (e) { - Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); - Node *node = e->get(); - bool enabled = node->is_unique_name_in_owner(); - if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) { - accept->set_text(TTR("Another node already uses this unique name in the scene.")); + // Enabling/disabling based on the same node based on which the checkbox in the menu is checked/unchecked. + List<Node *>::Element *first_selected = editor_selection->get_selected_node_list().front(); + if (first_selected == nullptr) { + return; + } + bool enabling = !first_selected->get()->is_unique_name_in_owner(); + + List<Node *> full_selection = editor_selection->get_full_selected_node_list(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); + + if (enabling) { + Vector<Node *> new_unique_nodes; + Vector<StringName> new_unique_names; + Vector<StringName> cant_be_set_unique_names; + + for (Node *node : full_selection) { + if (node->is_unique_name_in_owner()) { + continue; + } + StringName name = node->get_name(); + if (new_unique_names.find(name) != -1 || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) { + cant_be_set_unique_names.push_back(name); + } else { + new_unique_nodes.push_back(node); + new_unique_names.push_back(name); + } + } + + if (new_unique_nodes.size()) { + undo_redo->create_action(TTR("Enable Scene Unique Name(s)")); + for (Node *node : new_unique_nodes) { + undo_redo->add_do_method(node, "set_unique_name_in_owner", true); + undo_redo->add_undo_method(node, "set_unique_name_in_owner", false); + } + undo_redo->commit_action(); + } + + if (cant_be_set_unique_names.size()) { + String popup_text = TTR("Unique names already used by another node in the scene:"); + popup_text += "\n"; + for (StringName name : cant_be_set_unique_names) { + popup_text += "\n" + String(name); + } + accept->set_text(popup_text); accept->popup_centered(); - return; } - if (!enabled) { - undo_redo->create_action(TTR("Enable Scene Unique Name")); - } else { - undo_redo->create_action(TTR("Disable Scene Unique Name")); + } else { // Disabling. + undo_redo->create_action(TTR("Disable Scene Unique Name(s)")); + for (Node *node : full_selection) { + if (!node->is_unique_name_in_owner()) { + continue; + } + undo_redo->add_do_method(node, "set_unique_name_in_owner", false); + undo_redo->add_undo_method(node, "set_unique_name_in_owner", true); } - undo_redo->add_do_method(node, "set_unique_name_in_owner", !enabled); - undo_redo->add_undo_method(node, "set_unique_name_in_owner", enabled); undo_redo->commit_action(); } } break; @@ -1200,7 +1237,7 @@ void SceneTreeDock::_notification(int p_what) { if (canvas_item_plugin) { canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", Callable(scene_tree, "_update_tree")); canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", Callable(scene_tree, "_update_tree")); - scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::update)); + scene_tree->connect("node_changed", callable_mp((CanvasItem *)canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), &CanvasItem::queue_redraw)); } Node3DEditorPlugin *spatial_editor_plugin = Object::cast_to<Node3DEditorPlugin>(editor_data->get_editor("3D")); @@ -1230,7 +1267,7 @@ void SceneTreeDock::_notification(int p_what) { node_shortcuts_toggle->set_name("NodeShortcutsToggle"); node_shortcuts_toggle->set_icon(get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons"))); node_shortcuts_toggle->set_toggle_mode(true); - node_shortcuts_toggle->set_tooltip(TTR("Switch to Favorite Nodes")); + node_shortcuts_toggle->set_tooltip_text(TTR("Switch to Favorite Nodes")); node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection")); node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT); node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog)); @@ -1469,7 +1506,7 @@ bool SceneTreeDock::_update_node_path(Node *p_root_node, NodePath &r_node_path, if (found_root_path) { NodePath root_path_new = found_root_path->value; if (!root_path_new.is_empty()) { - NodePath old_abs_path = NodePath(String(p_root_node->get_path()).plus_file(r_node_path)); + NodePath old_abs_path = NodePath(String(p_root_node->get_path()).path_join(r_node_path)); old_abs_path.simplify(); r_node_path = root_path_new.rel_path_to(old_abs_path); } @@ -1839,7 +1876,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V } editor_data->get_undo_redo()->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc); - editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); if (p_keep_global_xform) { if (Object::cast_to<Node2D>(node)) { @@ -2127,7 +2164,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { // hack, force 2d editor viewport to refresh after deletion if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton()) { - editor->get_viewport_control()->update(); + editor->get_viewport_control()->queue_redraw(); } _push_item(nullptr); @@ -2202,7 +2239,7 @@ void SceneTreeDock::_do_create(Node *p_parent) { String new_name = p_parent->validate_child_name(child); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name); - editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name))); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name))); } else { editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); @@ -2821,14 +2858,26 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_separator(); menu->add_icon_shortcut(get_theme_icon(SNAME("CopyNodePath"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); } + } - if (selection[0]->get_owner() == EditorNode::get_singleton()->get_edited_scene()) { - // Only for nodes owned by the edited scene root. + if (profile_allow_editing) { + // Allow multi-toggling scene unique names but only if all selected nodes are owned by the edited scene root. + bool all_owned = true; + for (Node *node : full_selection) { + if (node->get_owner() != EditorNode::get_singleton()->get_edited_scene()) { + all_owned = false; + break; + } + } + if (all_owned) { menu->add_separator(); menu->add_icon_check_item(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME); + // Checked based on `selection[0]` because `full_selection` has undesired ordering. menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner()); } + } + if (selection.size() == 1) { bool is_external = (!selection[0]->get_scene_file_path().is_empty()); if (is_external) { bool is_inherited = selection[0]->get_scene_inherited_state() != nullptr; @@ -2938,9 +2987,9 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) { if (path.is_empty()) { String root_path = editor_data->get_edited_scene_root()->get_scene_file_path(); if (root_path.is_empty()) { - path = String("res://").plus_file(selected->get_name()); + path = String("res://").path_join(selected->get_name()); } else { - path = root_path.get_base_dir().plus_file(selected->get_name()); + path = root_path.get_base_dir().path_join(selected->get_name()); } } @@ -2997,9 +3046,9 @@ void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) { shader_name = selected_shader_material->get_name(); } if (root_path.is_empty()) { - path = String("res://").plus_file(shader_name); + path = String("res://").path_join(shader_name); } else { - path = root_path.get_base_dir().plus_file(shader_name); + path = root_path.get_base_dir().path_join(shader_name); } } @@ -3199,7 +3248,7 @@ void SceneTreeDock::_update_create_root_dialog() { favorite_nodes->get_child(i)->queue_delete(); } - Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ); + Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites.Node"), FileAccess::READ); if (f.is_valid()) { while (!f->eof_reached()) { String l = f->get_line().strip_edges(); @@ -3397,14 +3446,14 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec button_add = memnew(Button); button_add->set_flat(true); button_add->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false)); - button_add->set_tooltip(TTR("Add/Create a New Node.")); + button_add->set_tooltip_text(TTR("Add/Create a New Node.")); button_add->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node")); filter_hbc->add_child(button_add); button_instance = memnew(Button); button_instance->set_flat(true); button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_INSTANTIATE, false)); - button_instance->set_tooltip(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists.")); + button_instance->set_tooltip_text(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists.")); button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene")); filter_hbc->add_child(button_instance); @@ -3419,7 +3468,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec button_create_script = memnew(Button); button_create_script->set_flat(true); button_create_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_ATTACH_SCRIPT, false)); - button_create_script->set_tooltip(TTR("Attach a new or existing script to the selected node.")); + button_create_script->set_tooltip_text(TTR("Attach a new or existing script to the selected node.")); button_create_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script")); filter_hbc->add_child(button_create_script); button_create_script->hide(); @@ -3427,7 +3476,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec button_detach_script = memnew(Button); button_detach_script->set_flat(true); button_detach_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_DETACH_SCRIPT, false)); - button_detach_script->set_tooltip(TTR("Detach the script from the selected node.")); + button_detach_script->set_tooltip_text(TTR("Detach the script from the selected node.")); button_detach_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/detach_script")); filter_hbc->add_child(button_detach_script); button_detach_script->hide(); @@ -3450,7 +3499,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec edit_remote->set_h_size_flags(SIZE_EXPAND_FILL); edit_remote->set_text(TTR("Remote")); edit_remote->set_toggle_mode(true); - edit_remote->set_tooltip(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance.")); + edit_remote->set_tooltip_text(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance.")); edit_remote->connect("pressed", callable_mp(this, &SceneTreeDock::_remote_tree_selected)); edit_local = memnew(Button); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 00fd0c3aac..c120468ecb 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -354,7 +354,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { tooltip += "\n\n" + p_node->get_editor_description(); } - item->set_tooltip(0, tooltip); + item->set_tooltip_text(0, tooltip); } else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) { item->add_button(0, get_theme_icon(SNAME("InstanceOptions"), SNAME("EditorIcons")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); @@ -363,7 +363,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { tooltip += "\n\n" + p_node->get_editor_description(); } - item->set_tooltip(0, tooltip); + item->set_tooltip_text(0, tooltip); } else { StringName type = EditorNode::get_singleton()->get_object_custom_type_name(p_node); if (type == StringName()) { @@ -375,7 +375,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { tooltip += "\n\n" + p_node->get_editor_description(); } - item->set_tooltip(0, tooltip); + item->set_tooltip_text(0, tooltip); } if (can_open_instance && undo_redo.is_valid()) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes @@ -386,10 +386,18 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { Ref<Script> script = p_node->get_script(); if (!script.is_null()) { - item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path()); + String additional_notes; + // Can't set tooltip after adding button, need to do it before. + if (script->is_tool()) { + additional_notes += "\n" + TTR("This script is currently running in the editor."); + } + item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path() + additional_notes); if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) { item->set_button_color(0, item->get_button_count(0) - 1, Color(1, 1, 1, 0.5)); } + if (script->is_tool()) { + item->set_button_color(0, item->get_button_count(0) - 1, get_theme_color(SNAME("accent_color"), SNAME("Editor"))); + } } if (p_node->is_class("CanvasItem")) { @@ -505,7 +513,7 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) { if (p_node->is_class("CanvasItem") || p_node->is_class("CanvasLayer") || p_node->is_class("Window")) { visible = p_node->call("is_visible"); - CanvasItemEditor::get_singleton()->get_viewport_control()->update(); + CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw(); } else if (p_node->is_class("Node3D")) { visible = p_node->call("is_visible"); } diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 15e992ce18..7d065b4920 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -824,7 +824,7 @@ Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(c Vector<ScriptLanguage::ScriptTemplate> user_templates; String extension = language->get_extension(); - String dir_path = p_dir.plus_file(p_object); + String dir_path = p_dir.path_join(p_object); Ref<DirAccess> d = DirAccess::open(dir_path); if (d.is_valid()) { @@ -860,7 +860,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL // Parse file for meta-information and script content Error err; - Ref<FileAccess> file = FileAccess::open(p_path.plus_file(p_filename), FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_path.path_join(p_filename), FileAccess::READ, &err); if (!err) { while (!file->eof_reached()) { String line = file->get_line(); @@ -898,7 +898,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL // Get name from file name if no name in meta information if (script_template.name == String()) { - script_template.name = p_filename.get_basename().replace("_", " ").capitalize(); + script_template.name = p_filename.get_basename().capitalize(); } return script_template; diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp index 8c4a231e8a..522fd7c645 100644 --- a/editor/shader_create_dialog.cpp +++ b/editor/shader_create_dialog.cpp @@ -161,7 +161,7 @@ void ShaderCreateDialog::_create_new() { shader = text_shader; StringBuilder code; - code += vformat("shader_type %s;\n", mode_menu->get_text().replace(" ", "").camelcase_to_underscore()); + code += vformat("shader_type %s;\n", mode_menu->get_text().to_snake_case()); if (current_template == 0) { // Default template. code += "\n"; diff --git a/editor/translations/extract.py b/editor/translations/extract.py index 7f3da400e7..07026baee2 100755 --- a/editor/translations/extract.py +++ b/editor/translations/extract.py @@ -139,7 +139,7 @@ theme_property_patterns = { } -# See String::camelcase_to_underscore(). +# See String::_camelcase_to_underscore(). capitalize_re = re.compile(r"(?<=\D)(?=\d)|(?<=\d)(?=\D([a-z]|\d))") |