From 47833d6e1639bde39d4d9b867a56625964861121 Mon Sep 17 00:00:00 2001 From: Nodragem Date: Sat, 18 May 2024 15:01:55 +0100 Subject: [PATCH 1/3] adding tooltips when dropping files --- editor/scene/3d/node_3d_editor_plugin.cpp | 258 +++++++++++++-------- editor/scene/3d/node_3d_editor_plugin.h | 4 +- editor/scene/canvas_item_editor_plugin.cpp | 91 ++++---- editor/scene/canvas_item_editor_plugin.h | 4 +- 4 files changed, 211 insertions(+), 146 deletions(-) diff --git a/editor/scene/3d/node_3d_editor_plugin.cpp b/editor/scene/3d/node_3d_editor_plugin.cpp index eea4a9703c..e3bcd6aff4 100644 --- a/editor/scene/3d/node_3d_editor_plugin.cpp +++ b/editor/scene/3d/node_3d_editor_plugin.cpp @@ -3219,9 +3219,6 @@ void Node3DEditorViewport::_notification(int p_what) { _update_centered_labels(); message_time = MIN(message_time, 0.001); // Make it disappear. - Key key = OS::prefer_meta_over_ctrl() ? Key::META : Key::CTRL; - preview_material_label_desc->set_text(vformat(TTR("Drag and drop to override the material of any geometry node.\nHold %s when dropping to override a specific surface."), find_keycode_name(key))); - const int item_count = display_submenu->get_item_count(); for (int i = 0; i < item_count; i++) { const Array item_data = display_submenu->get_item_metadata(i); @@ -3585,6 +3582,7 @@ void Node3DEditorViewport::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { + tooltip_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); surface->connect(SceneStringName(draw), callable_mp(this, &Node3DEditorViewport::_draw)); surface->connect(SceneStringName(gui_input), callable_mp(this, &Node3DEditorViewport::_sinput)); surface->connect(SceneStringName(mouse_entered), callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter)); @@ -3604,6 +3602,8 @@ void Node3DEditorViewport::_notification(int p_what) { view_display_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHlDarkBackground"))); preview_camera->set_button_icon(get_editor_theme_icon(SNAME("Camera3DDarkBackground"))); + + tooltip_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); Control *gui_base = EditorNode::get_singleton()->get_gui_base(); const Ref &information_3d_stylebox = gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)); @@ -5098,6 +5098,9 @@ void Node3DEditorViewport::_create_preview_node(const Vector &files) con } void Node3DEditorViewport::_remove_preview_node() { + tooltip_label->hide(); + tooltip_label_desc->hide(); + set_message(""); if (preview_node->get_parent()) { for (int i = preview_node->get_child_count() - 1; i >= 0; i--) { @@ -5198,8 +5201,8 @@ void Node3DEditorViewport::_reset_preview_material() const { } void Node3DEditorViewport::_remove_preview_material() { - preview_material_label->hide(); - preview_material_label_desc->hide(); + tooltip_label->hide(); + tooltip_label_desc->hide(); spatial_editor->set_preview_material(Ref()); spatial_editor->set_preview_reset_material(Ref()); @@ -5402,91 +5405,115 @@ void Node3DEditorViewport::_perform_drop_data() { bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { if (p_point == Vector2(Math::INF, Math::INF)) { + tooltip_label->hide(); return false; } preview_node_viewport_pos = p_point; + Dictionary d = p_data; + if (!d.has("type") || String(d["type"]) != "files") { + tooltip_label->hide(); + return false; + } + Vector files = d["files"]; + + // If we already have a preview material or preview node, + // We just need to update them. + if (spatial_editor->get_preview_material().is_valid()) { + ObjectID new_preview_material_target = _select_ray(p_point); + return _apply_preview_material(new_preview_material_target, p_point); + } + + if (preview_node->is_inside_tree()) { + preview_node_viewport_pos = p_point; + update_preview_node = true; + return true; + } + + // If we don't already have a preview material or preview node, + // it means that this is the first time we are visiting this function. + // In that case, we need to check that the file(s) are droppable. bool can_instantiate = false; bool is_cyclical_dep = false; String error_file; - if (!preview_node->is_inside_tree() && spatial_editor->get_preview_material().is_null()) { - Dictionary d = p_data; - if (d.has("type") && (String(d["type"]) == "files")) { - Vector files = d["files"]; + enum { + SCENE = 1 << 0, + TEXTURE = 1 << 1, + AUDIO = 1 << 2, + MESH = 1 << 3, + MATERIAL = 1 << 4, + }; + int instantiate_type = 0; - // Track whether a type other than PackedScene is valid to stop checking them and only - // continue to check if the rest of the scenes are valid (don't have cyclic dependencies). - bool is_other_valid = false; - // Check if at least one of the dragged files is a mesh, material, texture or scene. - for (int i = 0; i < files.size(); i++) { - const String &res_type = ResourceLoader::get_resource_type(files[i]); - bool is_scene = ClassDB::is_parent_class(res_type, "PackedScene"); - bool is_mesh = ClassDB::is_parent_class(res_type, "Mesh"); - bool is_material = ClassDB::is_parent_class(res_type, "Material"); - bool is_texture = ClassDB::is_parent_class(res_type, "Texture"); - bool is_audio = ClassDB::is_parent_class(res_type, "AudioStream"); + // Track whether a type other than PackedScene is valid to stop checking them and only + // continue to check if the rest of the scenes are valid (don't have cyclic dependencies). + bool is_other_valid = false; + // Check if at least one of the dragged files is a mesh, material, texture, or scene. + for (int i = 0; i < files.size(); i++) { + const String &res_type = ResourceLoader::get_resource_type(files[i]); + bool is_scene = ClassDB::is_parent_class(res_type, "PackedScene"); + bool is_mesh = ClassDB::is_parent_class(res_type, "Mesh"); + bool is_material = ClassDB::is_parent_class(res_type, "Material"); + bool is_texture = ClassDB::is_parent_class(res_type, "Texture"); + bool is_audio = ClassDB::is_parent_class(res_type, "AudioStream"); - if (is_mesh || is_scene || is_material || is_texture || is_audio) { - Ref res = ResourceLoader::load(files[i]); - if (res.is_null()) { - continue; - } - Ref scn = res; - Ref mesh = res; - Ref mat = res; - Ref tex = res; - Ref audio = res; - if (scn.is_valid()) { - Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instantiated_scene) { - continue; - } - Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); - if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) { - memdelete(instantiated_scene); - can_instantiate = false; - is_cyclical_dep = true; - error_file = files[i].get_file(); - break; - } - memdelete(instantiated_scene); - } else if (!is_other_valid && mat.is_valid()) { - Ref base_mat = res; - Ref shader_mat = res; - - if (base_mat.is_null() && shader_mat.is_null()) { - continue; - } - - spatial_editor->set_preview_material(mat); - is_other_valid = true; - continue; - } else if (!is_other_valid && mesh.is_valid()) { - // Let the mesh pass. - is_other_valid = true; - } else if (!is_other_valid && tex.is_valid()) { - Ref new_mat = memnew(StandardMaterial3D); - new_mat->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, tex); - - spatial_editor->set_preview_material(new_mat); - is_other_valid = true; - continue; - } else if (!is_other_valid && audio.is_valid()) { - is_other_valid = true; - } else { - continue; - } - can_instantiate = true; + if (is_mesh || is_scene || is_material || is_texture || is_audio) { + Ref res = ResourceLoader::load(files[i]); + if (res.is_null()) { + continue; + } + Ref scn = res; + Ref mesh = res; + Ref mat = res; + Ref tex = res; + Ref audio = res; + if (scn.is_valid()) { + Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { + continue; } + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) { + memdelete(instantiated_scene); + can_instantiate = false; + is_cyclical_dep = true; + error_file = files[i].get_file(); + break; + } + memdelete(instantiated_scene); + instantiate_type |= SCENE; + } else if (!is_other_valid && mat.is_valid()) { + Ref base_mat = res; + Ref shader_mat = res; + + if (base_mat.is_null() && shader_mat.is_null()) { + continue; + } + + spatial_editor->set_preview_material(mat); + is_other_valid = true; + instantiate_type |= MATERIAL; + continue; + } else if (!is_other_valid && mesh.is_valid()) { + // Let the mesh pass. + is_other_valid = true; + instantiate_type |= MESH; + } else if (!is_other_valid && tex.is_valid()) { + Ref new_mat; + new_mat.instantiate(); + new_mat->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, tex); + + spatial_editor->set_preview_material(new_mat); + is_other_valid = true; + instantiate_type |= TEXTURE; + continue; + } else if (!is_other_valid && audio.is_valid()) { + is_other_valid = true; + instantiate_type |= AUDIO; + } else { + continue; } - if (can_instantiate) { - _create_preview_node(files); - preview_node->hide(); - } - } - } else { - if (preview_node->is_inside_tree()) { can_instantiate = true; } } @@ -5497,17 +5524,44 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant } if (can_instantiate) { - update_preview_node = true; - return true; + // Only droppable file(s), on first frame, will make it to this point. + // Hence it is a good place to create the previews and tooltips. + _create_preview_node(files); + preview_node->hide(); } - if (spatial_editor->get_preview_material().is_valid()) { - preview_material_label->show(); - preview_material_label_desc->show(); + String title = "Dropping Unrecognized File(s)"; + String desc = "File format is not supported..."; - ObjectID new_preview_material_target = _select_ray(p_point); - return _apply_preview_material(new_preview_material_target, p_point); + if (instantiate_type != 0) { + desc = TTR("Default: Added as sibling of selected node (except when root is selected).") + + "\n" + TTR("Hold Shift: Added as child of selected node.") + + "\n" + TTR("Hold Alt: Added as child of root node."); } + if (files.size() > 1) { + title = TTR("Dropping multiple files..."); + } else if (instantiate_type & SCENE) { + title = TTR("Dropping a Scene file..."); + } else if (instantiate_type & MESH) { + title = TTR("Dropping a Mesh file..."); + } else if (instantiate_type & AUDIO) { + title = TTR("Dropping an Audio file..."); + } else if (instantiate_type & MATERIAL || instantiate_type & TEXTURE) { + title = TTR("Dropping a Material..."); + Key ctrl_key = (OS::get_singleton()->has_feature("macos") || + OS::get_singleton()->has_feature("web_macos") || + OS::get_singleton()->has_feature("web_ios")) + ? Key::META + : Key::CTRL; + desc = vformat(TTR("Default: Placed in Geometry's Material Override slot.") + + "\n" + TTR("Hold %s: Placed in Mesh's Surface Material Override slot."), + find_keycode_name(ctrl_key)); + } + + tooltip_label->set_text(title); + tooltip_label_desc->set_text(desc); + tooltip_label->show(); + tooltip_label_desc->show(); return false; } @@ -6307,22 +6361,26 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p zoom_limit_label->hide(); bottom_center_vbox->add_child(zoom_limit_label); - preview_material_label = memnew(Label); - preview_material_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); - preview_material_label->set_offset(Side::SIDE_TOP, -70 * EDSCALE); - preview_material_label->set_text(TTRC("Overriding material...")); - preview_material_label->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1)); - preview_material_label->hide(); - surface->add_child(preview_material_label); + tooltip_label = memnew(Label); + tooltip_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); + tooltip_label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); + tooltip_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); + tooltip_label->set_offset(Side::SIDE_TOP, -70 * EDSCALE); + tooltip_label->set_text(TTRC("Overriding material...")); + tooltip_label->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1)); + tooltip_label->hide(); + vbox->add_child(tooltip_label); - preview_material_label_desc = memnew(Label); - preview_material_label_desc->set_focus_mode(FOCUS_ACCESSIBILITY); - preview_material_label_desc->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); - preview_material_label_desc->set_offset(Side::SIDE_TOP, -50 * EDSCALE); - preview_material_label_desc->add_theme_color_override(SceneStringName(font_color), Color(0.8, 0.8, 0.8, 1)); - preview_material_label_desc->add_theme_constant_override("line_spacing", 0); - preview_material_label_desc->hide(); - surface->add_child(preview_material_label_desc); + tooltip_label_desc = memnew(Label); + tooltip_label_desc->set_focus_mode(FOCUS_ACCESSIBILITY); + tooltip_label_desc->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); + tooltip_label_desc->set_offset(Side::SIDE_TOP, -50 * EDSCALE); + tooltip_label_desc->add_theme_color_override(SceneStringName(font_color), Color(0.8f, 0.8f, 0.8f, 1)); + tooltip_label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); + tooltip_label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); + tooltip_label_desc->add_theme_constant_override("line_spacing", 0); + tooltip_label_desc->hide(); + vbox->add_child(tooltip_label_desc); frame_time_gradient = memnew(Gradient); // The color is set when the theme changes. diff --git a/editor/scene/3d/node_3d_editor_plugin.h b/editor/scene/3d/node_3d_editor_plugin.h index 7a1db01d52..3f493a2c0f 100644 --- a/editor/scene/3d/node_3d_editor_plugin.h +++ b/editor/scene/3d/node_3d_editor_plugin.h @@ -273,8 +273,8 @@ private: Label *locked_label = nullptr; Label *zoom_limit_label = nullptr; - Label *preview_material_label = nullptr; - Label *preview_material_label_desc = nullptr; + Label *tooltip_label = nullptr; + Label *tooltip_label_desc = nullptr; VBoxContainer *top_right_vbox = nullptr; VBoxContainer *bottom_center_vbox = nullptr; diff --git a/editor/scene/canvas_item_editor_plugin.cpp b/editor/scene/canvas_item_editor_plugin.cpp index 6d3469e541..c4eb1c74c8 100644 --- a/editor/scene/canvas_item_editor_plugin.cpp +++ b/editor/scene/canvas_item_editor_plugin.cpp @@ -6098,7 +6098,7 @@ void CanvasItemEditorViewport::_on_select_texture_node_type(Object *selected) { CheckBox *check = Object::cast_to(selected); String type = check->get_text(); texture_node_type_selector->set_title(vformat(TTR("Add %s"), type)); - label->set_text(vformat(TTR("Adding %s..."), type)); + dropping_tooltip_label->set_text(vformat(TTR("Adding %s..."), type)); } void CanvasItemEditorViewport::_on_change_type_confirmed() { @@ -6118,6 +6118,7 @@ void CanvasItemEditorViewport::_on_change_type_closed() { void CanvasItemEditorViewport::_create_preview(const Vector &files) const { bool add_preview = false; + for (int i = 0; i < files.size(); i++) { Ref res = ResourceLoader::load(files[i]); ERR_CONTINUE(res.is_null()); @@ -6161,6 +6162,8 @@ void CanvasItemEditorViewport::_remove_preview() { canvas_item_editor->message = ""; canvas_item_editor->update_viewport(); } + dropping_tooltip_label->hide(); + dropping_tooltip_label_desc->hide(); if (preview_node->get_parent()) { for (int i = preview_node->get_child_count() - 1; i >= 0; i--) { Node *node = preview_node->get_child(i); @@ -6168,9 +6171,6 @@ void CanvasItemEditorViewport::_remove_preview() { preview_node->remove_child(node); } EditorNode::get_singleton()->get_scene_root()->remove_child(preview_node); - - label->hide(); - label_desc->hide(); } } @@ -6430,11 +6430,12 @@ void CanvasItemEditorViewport::_perform_drop_data() { bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Variant &p_data) const { if (p_point == Vector2(Math::INF, Math::INF)) { + dropping_tooltip_label->hide(); return false; } Dictionary d = p_data; if (!d.has("type") || (String(d["type"]) != "files")) { - label->hide(); + dropping_tooltip_label->hide(); return false; } @@ -6486,7 +6487,15 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian return false; } } + + String desc = "File format is not supported..."; + String title = "Dropping Unrecognized File(s)"; + if (instantiate_type == 0) { + dropping_tooltip_label->set_text(title); + dropping_tooltip_label_desc->set_text(desc); + dropping_tooltip_label->show(); + dropping_tooltip_label_desc->show(); return false; } @@ -6512,31 +6521,28 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian } canvas_item_editor->update_viewport(); - if (instantiate_type & TEXTURE && instantiate_type & AUDIO) { - // TRANSLATORS: The placeholders are the types of nodes being instantiated. - label->set_text(vformat(TTR("Adding %s and %s..."), default_texture_node_type, "AudioStreamPlayer2D")); - } else { - String node_type; - if (instantiate_type & TEXTURE) { - node_type = default_texture_node_type; - } else if (instantiate_type & AUDIO) { - node_type = "AudioStreamPlayer2D"; - } - if (!node_type.is_empty()) { - // TRANSLATORS: The placeholder is the type of node being instantiated. - label->set_text(vformat(TTR("Adding %s..."), node_type)); - } - } - label->set_visible(instantiate_type & ~SCENE); + desc = TTR("Default: Added as sibling of selected node (except when root is selected).") + + "\n" + TTR("Hold Shift: Added as child of selected node.") + + "\n" + TTR("Hold Alt: Added as child of root node."); - String desc = TTR("Drag and drop to add as sibling of selected node (except when root is selected).") + - "\n" + TTR("Hold Shift when dropping to add as child of selected node.") + - "\n" + TTR("Hold Alt when dropping to add as child of root node."); - if (instantiate_type & TEXTURE) { - desc += "\n" + TTR("Hold Alt + Shift when dropping to add as different node type."); + if (files.size() > 1) { + title = TTR("Dropping multiple files..."); + } else if (instantiate_type & SCENE) { + title = TTR("Dropping a Scene file..."); + } else if (instantiate_type & AUDIO) { + title = TTR("Dropping an Audio file..."); + } else if (instantiate_type & TEXTURE) { + // TRANSLATORS: The placeholders are the types of nodes being instantiated. + title = vformat(TTR("Dropping a Texture file as a %s node..."), default_texture_node_type); } - label_desc->set_text(desc); - label_desc->show(); + if (instantiate_type & TEXTURE) { + desc += "\n" + TTR("Hold Alt + Shift: Add Texture as a different node type."); + } + + dropping_tooltip_label->set_text(title); + dropping_tooltip_label_desc->set_text(desc); + dropping_tooltip_label->show(); + dropping_tooltip_label_desc->show(); return true; } @@ -6616,7 +6622,8 @@ void CanvasItemEditorViewport::_update_theme() { check->set_button_icon(get_editor_theme_icon(check->get_text())); } - label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); + dropping_tooltip_label->add_theme_color_override(SceneStringName(font_color), + get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); } void CanvasItemEditorViewport::_notification(int p_what) { @@ -6686,20 +6693,20 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it check->connect("button_down", callable_mp(this, &CanvasItemEditorViewport::_on_select_texture_node_type).bind(check)); } - label = memnew(Label); - label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); - label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - label->hide(); - canvas_item_editor->get_controls_container()->add_child(label); + dropping_tooltip_label = memnew(Label); + dropping_tooltip_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); + dropping_tooltip_label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); + dropping_tooltip_label->hide(); + canvas_item_editor->get_controls_container()->add_child(dropping_tooltip_label); - label_desc = memnew(Label); - label_desc->set_focus_mode(FOCUS_ACCESSIBILITY); - label_desc->add_theme_color_override(SceneStringName(font_color), Color(0.6f, 0.6f, 0.6f, 1)); - label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); - label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - label_desc->add_theme_constant_override("line_spacing", 0); - label_desc->hide(); - canvas_item_editor->get_controls_container()->add_child(label_desc); + dropping_tooltip_label_desc = memnew(Label); + dropping_tooltip_label_desc->set_focus_mode(FOCUS_ACCESSIBILITY); + dropping_tooltip_label_desc->add_theme_color_override(SceneStringName(font_color), Color(0.8f, 0.8f, 0.8f, 1)); + dropping_tooltip_label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); + dropping_tooltip_label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); + dropping_tooltip_label_desc->add_theme_constant_override("line_spacing", 0); + dropping_tooltip_label_desc->hide(); + canvas_item_editor->get_controls_container()->add_child(dropping_tooltip_label_desc); RS::get_singleton()->canvas_set_disable_scale(true); } diff --git a/editor/scene/canvas_item_editor_plugin.h b/editor/scene/canvas_item_editor_plugin.h index 3c5baebfda..10ec26386b 100644 --- a/editor/scene/canvas_item_editor_plugin.h +++ b/editor/scene/canvas_item_editor_plugin.h @@ -652,8 +652,8 @@ class CanvasItemEditorViewport : public Control { Control *preview_node = nullptr; AcceptDialog *accept = nullptr; AcceptDialog *texture_node_type_selector = nullptr; - Label *label = nullptr; - Label *label_desc = nullptr; + Label *dropping_tooltip_label = nullptr; + Label *dropping_tooltip_label_desc = nullptr; Ref button_group; void _on_mouse_exit(); From 1523979fa5b6bbefecf7f184c64efd996099a314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20M=C3=A9gardon?= Date: Fri, 12 Dec 2025 13:07:28 +0000 Subject: [PATCH 2/3] adding panel and richlabeltext --- editor/scene/3d/node_3d_editor_plugin.cpp | 70 +++++++++++++---------- editor/scene/3d/node_3d_editor_plugin.h | 4 +- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/editor/scene/3d/node_3d_editor_plugin.cpp b/editor/scene/3d/node_3d_editor_plugin.cpp index e3bcd6aff4..cf901b381a 100644 --- a/editor/scene/3d/node_3d_editor_plugin.cpp +++ b/editor/scene/3d/node_3d_editor_plugin.cpp @@ -3603,7 +3603,6 @@ void Node3DEditorViewport::_notification(int p_what) { view_display_menu->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHlDarkBackground"))); preview_camera->set_button_icon(get_editor_theme_icon(SNAME("Camera3DDarkBackground"))); - tooltip_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); Control *gui_base = EditorNode::get_singleton()->get_gui_base(); const Ref &information_3d_stylebox = gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)); @@ -3621,7 +3620,9 @@ void Node3DEditorViewport::_notification(int p_what) { info_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); override_label_colors(info_label); - + tooltip_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); + tooltip_label->add_theme_font_size_override(SceneStringName(font_size), get_theme_default_font_size()+2); + tooltip_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); frame_time_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); // Set a minimum width to prevent the width from changing all the time // when numbers vary rapidly. This minimum width is set based on a @@ -5098,8 +5099,7 @@ void Node3DEditorViewport::_create_preview_node(const Vector &files) con } void Node3DEditorViewport::_remove_preview_node() { - tooltip_label->hide(); - tooltip_label_desc->hide(); + tooltip_panel->hide(); set_message(""); if (preview_node->get_parent()) { @@ -5201,8 +5201,7 @@ void Node3DEditorViewport::_reset_preview_material() const { } void Node3DEditorViewport::_remove_preview_material() { - tooltip_label->hide(); - tooltip_label_desc->hide(); + tooltip_panel->hide(); spatial_editor->set_preview_material(Ref()); spatial_editor->set_preview_reset_material(Ref()); @@ -5405,14 +5404,14 @@ void Node3DEditorViewport::_perform_drop_data() { bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { if (p_point == Vector2(Math::INF, Math::INF)) { - tooltip_label->hide(); + tooltip_panel->hide(); return false; } preview_node_viewport_pos = p_point; Dictionary d = p_data; if (!d.has("type") || String(d["type"]) != "files") { - tooltip_label->hide(); + tooltip_panel->hide(); return false; } Vector files = d["files"]; @@ -5534,9 +5533,9 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant String desc = "File format is not supported..."; if (instantiate_type != 0) { - desc = TTR("Default: Added as sibling of selected node (except when root is selected).") + - "\n" + TTR("Hold Shift: Added as child of selected node.") + - "\n" + TTR("Hold Alt: Added as child of root node."); + desc = TTR("[ul][b]Default:[/b] Added as sibling of selected node (except when root is selected).") + + "\n" + TTR("[b]Hold Shift:[/b] Added as child of selected node.") + + "\n" + TTR("[b]Hold Alt:[/b] Added as child of root node.[/ul]"); } if (files.size() > 1) { title = TTR("Dropping multiple files..."); @@ -5553,15 +5552,14 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL; - desc = vformat(TTR("Default: Placed in Geometry's Material Override slot.") + - "\n" + TTR("Hold %s: Placed in Mesh's Surface Material Override slot."), + desc = vformat(TTR("[ul][b]Default:[/b] Placed in Geometry's Material Override slot.") + + "\n" + TTR("[b]Hold %s:[/b] Placed in Mesh's Surface Material Override slot.[/ul]"), find_keycode_name(ctrl_key)); } tooltip_label->set_text(title); tooltip_label_desc->set_text(desc); - tooltip_label->show(); - tooltip_label_desc->show(); + tooltip_panel->show(); return false; } @@ -6361,27 +6359,39 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p zoom_limit_label->hide(); bottom_center_vbox->add_child(zoom_limit_label); + tooltip_panel = memnew(PanelContainer); + tooltip_panel->set_h_grow_direction(GROW_DIRECTION_BEGIN); + tooltip_panel->set_v_grow_direction(GROW_DIRECTION_BEGIN); + tooltip_panel->set_mouse_filter(MOUSE_FILTER_IGNORE); + vbox->add_child(tooltip_panel); + tooltip_panel->hide(); + + VBoxContainer *tooltip_vbox = memnew(VBoxContainer); + tooltip_panel->add_child(tooltip_vbox); tooltip_label = memnew(Label); - tooltip_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); - tooltip_label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - tooltip_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); - tooltip_label->set_offset(Side::SIDE_TOP, -70 * EDSCALE); + // tooltip_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); + // tooltip_label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); + tooltip_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT); tooltip_label->set_text(TTRC("Overriding material...")); tooltip_label->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1)); - tooltip_label->hide(); - vbox->add_child(tooltip_label); + tooltip_vbox->add_child(tooltip_label); - tooltip_label_desc = memnew(Label); + tooltip_label_desc = memnew(RichTextLabel); tooltip_label_desc->set_focus_mode(FOCUS_ACCESSIBILITY); - tooltip_label_desc->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); - tooltip_label_desc->set_offset(Side::SIDE_TOP, -50 * EDSCALE); + tooltip_label_desc->set_use_bbcode(true); + tooltip_label_desc->set_fit_content(true); + tooltip_label_desc->set_scroll_active(false); + tooltip_label_desc->set_autowrap_mode(TextServer::AUTOWRAP_OFF); + tooltip_label_desc->set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT); tooltip_label_desc->add_theme_color_override(SceneStringName(font_color), Color(0.8f, 0.8f, 0.8f, 1)); - tooltip_label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); - tooltip_label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - tooltip_label_desc->add_theme_constant_override("line_spacing", 0); - tooltip_label_desc->hide(); - vbox->add_child(tooltip_label_desc); - + StyleBoxEmpty *empty_stylebox = memnew(StyleBoxEmpty); + empty_stylebox->set_content_margin(SIDE_LEFT, 5.0); + tooltip_label_desc->add_theme_style_override("normal", empty_stylebox); + // tooltip_label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); + // tooltip_label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); + tooltip_label_desc->add_theme_constant_override("paragraph_separation", 5); + tooltip_vbox->add_child(tooltip_label_desc); + frame_time_gradient = memnew(Gradient); // The color is set when the theme changes. frame_time_gradient->add_point(0.5, Color()); diff --git a/editor/scene/3d/node_3d_editor_plugin.h b/editor/scene/3d/node_3d_editor_plugin.h index 3f493a2c0f..c2ec6735c8 100644 --- a/editor/scene/3d/node_3d_editor_plugin.h +++ b/editor/scene/3d/node_3d_editor_plugin.h @@ -36,6 +36,7 @@ #include "editor/themes/editor_scale.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" +#include "scene/gui/rich_text_label.h" #include "scene/gui/spin_box.h" #include "scene/resources/gradient.h" #include "scene/resources/immediate_mesh.h" @@ -273,8 +274,9 @@ private: Label *locked_label = nullptr; Label *zoom_limit_label = nullptr; + PanelContainer *tooltip_panel = nullptr; Label *tooltip_label = nullptr; - Label *tooltip_label_desc = nullptr; + RichTextLabel *tooltip_label_desc = nullptr; VBoxContainer *top_right_vbox = nullptr; VBoxContainer *bottom_center_vbox = nullptr; From b8b3e66c1ba9c864131c521540589cb48c33e4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20M=C3=A9gardon?= Date: Sun, 1 Mar 2026 16:25:36 +0000 Subject: [PATCH 3/3] improve tooltips when dropping files in viewport remove can_instantiate --- editor/scene/3d/node_3d_editor_plugin.cpp | 117 ++++++++++----------- editor/scene/3d/node_3d_editor_plugin.h | 8 +- editor/scene/canvas_item_editor_plugin.cpp | 101 ++++++++++-------- editor/scene/canvas_item_editor_plugin.h | 6 +- 4 files changed, 118 insertions(+), 114 deletions(-) diff --git a/editor/scene/3d/node_3d_editor_plugin.cpp b/editor/scene/3d/node_3d_editor_plugin.cpp index cf901b381a..339a2da408 100644 --- a/editor/scene/3d/node_3d_editor_plugin.cpp +++ b/editor/scene/3d/node_3d_editor_plugin.cpp @@ -98,6 +98,7 @@ #include "scene/gui/center_container.h" #include "scene/gui/color_picker.h" #include "scene/gui/flow_container.h" +#include "scene/gui/rich_text_label.h" #include "scene/gui/separator.h" #include "scene/gui/split_container.h" #include "scene/gui/subviewport_container.h" @@ -3582,7 +3583,6 @@ void Node3DEditorViewport::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { - tooltip_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); surface->connect(SceneStringName(draw), callable_mp(this, &Node3DEditorViewport::_draw)); surface->connect(SceneStringName(gui_input), callable_mp(this, &Node3DEditorViewport::_sinput)); surface->connect(SceneStringName(mouse_entered), callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter)); @@ -3620,9 +3620,8 @@ void Node3DEditorViewport::_notification(int p_what) { info_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); override_label_colors(info_label); - tooltip_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); - tooltip_label->add_theme_font_size_override(SceneStringName(font_size), get_theme_default_font_size()+2); - tooltip_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); + tooltip_panel->add_theme_style_override(CoreStringName(normal), information_3d_stylebox); + frame_time_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox); // Set a minimum width to prevent the width from changing all the time // when numbers vary rapidly. This minimum width is set based on a @@ -5093,9 +5092,8 @@ void Node3DEditorViewport::_create_preview_node(const Vector &files) con } if (add_preview) { EditorNode::get_singleton()->get_scene_root()->add_child(preview_node); + *preview_bounds = _calculate_spatial_bounds(preview_node); } - - *preview_bounds = _calculate_spatial_bounds(preview_node); } void Node3DEditorViewport::_remove_preview_node() { @@ -5402,6 +5400,15 @@ void Node3DEditorViewport::_perform_drop_data() { } } +void Node3DEditorViewport::_show_tooltip(const String &p_title, const String &p_description) const { + tooltip_panel->set_text( + vformat("[font_size=%s][b][color=%s]%s[/color][/b][/font_size]\n%s", + get_theme_default_font_size() + 2, + get_theme_color(SNAME("accent_color"), EditorStringName(Editor)).to_html(false), + p_title, p_description)); + tooltip_panel->show(); +} + bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { if (p_point == Vector2(Math::INF, Math::INF)) { tooltip_panel->hide(); @@ -5432,7 +5439,6 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant // If we don't already have a preview material or preview node, // it means that this is the first time we are visiting this function. // In that case, we need to check that the file(s) are droppable. - bool can_instantiate = false; bool is_cyclical_dep = false; String error_file; @@ -5475,7 +5481,6 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) { memdelete(instantiated_scene); - can_instantiate = false; is_cyclical_dep = true; error_file = files[i].get_file(); break; @@ -5513,30 +5518,38 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant } else { continue; } - can_instantiate = true; } } + String title = TTRN("Can't drop the file...", "Can't drop the files...", files.size()); if (is_cyclical_dep) { - set_message(vformat(TTR("Can't instantiate: %s."), vformat(TTR("Circular dependency found at %s"), error_file))); + _show_tooltip(title, vformat(TTR("Circular dependency found at %s."), error_file)); return false; } - if (can_instantiate) { - // Only droppable file(s), on first frame, will make it to this point. - // Hence it is a good place to create the previews and tooltips. - _create_preview_node(files); - preview_node->hide(); + if (instantiate_type == 0) { + _show_tooltip(title, TTR("File format is not supported.")); + return false; } - String title = "Dropping Unrecognized File(s)"; - String desc = "File format is not supported..."; + // Only droppable file(s), on first frame, will make it to this point. + // Hence it is a good place to create the previews and tooltips. + _create_preview_node(files); + preview_node->hide(); + + String desc = "[ul]" + + TTRN("[b]Default:[/b] Add as sibling of selected node (except when root is selected).", + "[b]Default:[/b] Add as siblings of selected node (except when root is selected).", + files.size()) + + "\n" + + TTRN("[b]Hold Shift:[/b] Add as child of selected node.", + "[b]Hold Shift:[/b] Add as children of selected node.", + files.size()) + + "\n" + + TTRN("[b]Hold Alt:[/b] Add as child of root node.", + "[b]Hold Alt:[/b] Add as children of root node.", + files.size()); - if (instantiate_type != 0) { - desc = TTR("[ul][b]Default:[/b] Added as sibling of selected node (except when root is selected).") + - "\n" + TTR("[b]Hold Shift:[/b] Added as child of selected node.") + - "\n" + TTR("[b]Hold Alt:[/b] Added as child of root node.[/ul]"); - } if (files.size() > 1) { title = TTR("Dropping multiple files..."); } else if (instantiate_type & SCENE) { @@ -5547,21 +5560,16 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant title = TTR("Dropping an Audio file..."); } else if (instantiate_type & MATERIAL || instantiate_type & TEXTURE) { title = TTR("Dropping a Material..."); - Key ctrl_key = (OS::get_singleton()->has_feature("macos") || - OS::get_singleton()->has_feature("web_macos") || - OS::get_singleton()->has_feature("web_ios")) - ? Key::META - : Key::CTRL; - desc = vformat(TTR("[ul][b]Default:[/b] Placed in Geometry's Material Override slot.") + - "\n" + TTR("[b]Hold %s:[/b] Placed in Mesh's Surface Material Override slot.[/ul]"), - find_keycode_name(ctrl_key)); + desc = "[ul]"; + desc += vformat(TTR("[b]Default:[/b] Place in Geometry's Material Override slot.") + + "\n" + TTR("[b]Hold %s:[/b] Place in Mesh's Surface Material Override slot."), + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL)); } + desc += "[/ul]"; - tooltip_label->set_text(title); - tooltip_label_desc->set_text(desc); - tooltip_panel->show(); + _show_tooltip(title, desc); - return false; + return true; } void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { @@ -6359,39 +6367,22 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p zoom_limit_label->hide(); bottom_center_vbox->add_child(zoom_limit_label); - tooltip_panel = memnew(PanelContainer); + tooltip_panel = memnew(RichTextLabel); + vbox->add_child(tooltip_panel); + tooltip_panel->hide(); tooltip_panel->set_h_grow_direction(GROW_DIRECTION_BEGIN); tooltip_panel->set_v_grow_direction(GROW_DIRECTION_BEGIN); tooltip_panel->set_mouse_filter(MOUSE_FILTER_IGNORE); - vbox->add_child(tooltip_panel); - tooltip_panel->hide(); + tooltip_panel->set_focus_mode(FOCUS_ACCESSIBILITY); + tooltip_panel->set_use_bbcode(true); + tooltip_panel->set_fit_content(true); + tooltip_panel->set_scroll_active(false); + tooltip_panel->set_tab_size(1); + tooltip_panel->set_autowrap_mode(TextServer::AUTOWRAP_OFF); + tooltip_panel->set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT); + tooltip_panel->add_theme_color_override(SceneStringName(font_color), Color(0.8f, 0.8f, 0.8f, 1)); + tooltip_panel->add_theme_constant_override("paragraph_separation", 5); - VBoxContainer *tooltip_vbox = memnew(VBoxContainer); - tooltip_panel->add_child(tooltip_vbox); - tooltip_label = memnew(Label); - // tooltip_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); - // tooltip_label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - tooltip_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT); - tooltip_label->set_text(TTRC("Overriding material...")); - tooltip_label->add_theme_color_override(SceneStringName(font_color), Color(1, 1, 1, 1)); - tooltip_vbox->add_child(tooltip_label); - - tooltip_label_desc = memnew(RichTextLabel); - tooltip_label_desc->set_focus_mode(FOCUS_ACCESSIBILITY); - tooltip_label_desc->set_use_bbcode(true); - tooltip_label_desc->set_fit_content(true); - tooltip_label_desc->set_scroll_active(false); - tooltip_label_desc->set_autowrap_mode(TextServer::AUTOWRAP_OFF); - tooltip_label_desc->set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT); - tooltip_label_desc->add_theme_color_override(SceneStringName(font_color), Color(0.8f, 0.8f, 0.8f, 1)); - StyleBoxEmpty *empty_stylebox = memnew(StyleBoxEmpty); - empty_stylebox->set_content_margin(SIDE_LEFT, 5.0); - tooltip_label_desc->add_theme_style_override("normal", empty_stylebox); - // tooltip_label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); - // tooltip_label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - tooltip_label_desc->add_theme_constant_override("paragraph_separation", 5); - tooltip_vbox->add_child(tooltip_label_desc); - frame_time_gradient = memnew(Gradient); // The color is set when the theme changes. frame_time_gradient->add_point(0.5, Color()); diff --git a/editor/scene/3d/node_3d_editor_plugin.h b/editor/scene/3d/node_3d_editor_plugin.h index c2ec6735c8..2eb88b5734 100644 --- a/editor/scene/3d/node_3d_editor_plugin.h +++ b/editor/scene/3d/node_3d_editor_plugin.h @@ -36,7 +36,6 @@ #include "editor/themes/editor_scale.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" -#include "scene/gui/rich_text_label.h" #include "scene/gui/spin_box.h" #include "scene/resources/gradient.h" #include "scene/resources/immediate_mesh.h" @@ -57,6 +56,7 @@ class Node3DEditorViewport; class OptionButton; class PanelContainer; class ProceduralSkyMaterial; +class RichTextLabel; class SubViewport; class SubViewportContainer; class VSeparator; @@ -274,9 +274,7 @@ private: Label *locked_label = nullptr; Label *zoom_limit_label = nullptr; - PanelContainer *tooltip_panel = nullptr; - Label *tooltip_label = nullptr; - RichTextLabel *tooltip_label_desc = nullptr; + RichTextLabel *tooltip_panel = nullptr; VBoxContainer *top_right_vbox = nullptr; VBoxContainer *bottom_center_vbox = nullptr; @@ -330,6 +328,8 @@ private: float get_zfar() const; float get_fov() const; + void _show_tooltip(const String &p_title, const String &p_description) const; + ObjectID clicked; ObjectID material_target; Vector selection_results; diff --git a/editor/scene/canvas_item_editor_plugin.cpp b/editor/scene/canvas_item_editor_plugin.cpp index c4eb1c74c8..0eed1538de 100644 --- a/editor/scene/canvas_item_editor_plugin.cpp +++ b/editor/scene/canvas_item_editor_plugin.cpp @@ -60,6 +60,7 @@ #include "scene/gui/base_button.h" #include "scene/gui/flow_container.h" #include "scene/gui/grid_container.h" +#include "scene/gui/rich_text_label.h" #include "scene/gui/separator.h" #include "scene/gui/split_container.h" #include "scene/gui/subviewport_container.h" @@ -6098,7 +6099,7 @@ void CanvasItemEditorViewport::_on_select_texture_node_type(Object *selected) { CheckBox *check = Object::cast_to(selected); String type = check->get_text(); texture_node_type_selector->set_title(vformat(TTR("Add %s"), type)); - dropping_tooltip_label->set_text(vformat(TTR("Adding %s..."), type)); + tooltip_panel->set_text(vformat(TTR("Adding %s..."), type)); } void CanvasItemEditorViewport::_on_change_type_confirmed() { @@ -6162,8 +6163,7 @@ void CanvasItemEditorViewport::_remove_preview() { canvas_item_editor->message = ""; canvas_item_editor->update_viewport(); } - dropping_tooltip_label->hide(); - dropping_tooltip_label_desc->hide(); + tooltip_panel->hide(); if (preview_node->get_parent()) { for (int i = preview_node->get_child_count() - 1; i >= 0; i--) { Node *node = preview_node->get_child(i); @@ -6428,14 +6428,23 @@ void CanvasItemEditorViewport::_perform_drop_data() { } } +void CanvasItemEditorViewport::_show_tooltip(const String &p_title, const String &p_description) const { + tooltip_panel->set_text( + vformat("[font_size=%s][b][color=%s]%s[/color][/b][/font_size]\n%s", + get_theme_default_font_size() + 2, + get_theme_color(SNAME("accent_color"), EditorStringName(Editor)).to_html(false), + p_title, p_description)); + tooltip_panel->show(); +} + bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Variant &p_data) const { if (p_point == Vector2(Math::INF, Math::INF)) { - dropping_tooltip_label->hide(); + tooltip_panel->hide(); return false; } Dictionary d = p_data; if (!d.has("type") || (String(d["type"]) != "files")) { - dropping_tooltip_label->hide(); + tooltip_panel->hide(); return false; } @@ -6455,9 +6464,9 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian }; int instantiate_type = 0; + String error_message; for (const String &path : files) { const String &res_type = ResourceLoader::get_resource_type(path); - String error_message; if (ClassDB::is_parent_class(res_type, "PackedScene")) { Ref scn = ResourceLoader::load(path); @@ -6469,6 +6478,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian } if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) { error_message = vformat(TTR("Circular dependency found at %s."), path.get_file()); + break; } memdelete(instantiated_scene); instantiate_type |= SCENE; @@ -6479,23 +6489,16 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian if (ClassDB::is_parent_class(res_type, "AudioStream")) { instantiate_type |= AUDIO; } - - if (!error_message.is_empty()) { - // TRANSLATORS: The placeholder is the error message. - canvas_item_editor->message = vformat(TTR("Can't instantiate: %s"), error_message); - canvas_item_editor->update_viewport(); - return false; - } } - String desc = "File format is not supported..."; - String title = "Dropping Unrecognized File(s)"; - + String title = TTRN("Can't drop the file...", "Can't drop the files...", files.size()); + if (!error_message.is_empty()) { + _show_tooltip(title, error_message); + canvas_item_editor->update_viewport(); + return false; + } if (instantiate_type == 0) { - dropping_tooltip_label->set_text(title); - dropping_tooltip_label_desc->set_text(desc); - dropping_tooltip_label->show(); - dropping_tooltip_label_desc->show(); + _show_tooltip(title, TTR("This file format is not supported.")); return false; } @@ -6521,9 +6524,18 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian } canvas_item_editor->update_viewport(); - desc = TTR("Default: Added as sibling of selected node (except when root is selected).") + - "\n" + TTR("Hold Shift: Added as child of selected node.") + - "\n" + TTR("Hold Alt: Added as child of root node."); + String desc = "[ul]" + + TTRN("[b]Default:[/b] Add as sibling of selected node (except when root is selected).", + "[b]Default:[/b] Add as siblings of selected node (except when root is selected).", + files.size()) + + "\n" + + TTRN("[b]Hold Shift:[/b] Add as child of selected node.", + "[b]Hold Shift:[/b] Add as children of selected node.", + files.size()) + + "\n" + + TTRN("[b]Hold Alt:[/b] Add as child of root node.", + "[b]Hold Alt:[/b] Add as children of root node.", + files.size()); if (files.size() > 1) { title = TTR("Dropping multiple files..."); @@ -6536,13 +6548,11 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian title = vformat(TTR("Dropping a Texture file as a %s node..."), default_texture_node_type); } if (instantiate_type & TEXTURE) { - desc += "\n" + TTR("Hold Alt + Shift: Add Texture as a different node type."); + desc += "\n" + TTR("[b]Hold Alt + Shift:[/b] Add Texture as a different node type."); } + desc += "[/ul]"; - dropping_tooltip_label->set_text(title); - dropping_tooltip_label_desc->set_text(desc); - dropping_tooltip_label->show(); - dropping_tooltip_label_desc->show(); + _show_tooltip(title, desc); return true; } @@ -6621,9 +6631,9 @@ void CanvasItemEditorViewport::_update_theme() { CheckBox *check = Object::cast_to(btn); check->set_button_icon(get_editor_theme_icon(check->get_text())); } - - dropping_tooltip_label->add_theme_color_override(SceneStringName(font_color), - get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); + Control *gui_base = EditorNode::get_singleton()->get_gui_base(); + const Ref &information_3d_stylebox = gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)); + tooltip_panel->add_theme_style_override(CoreStringName(normal), information_3d_stylebox); } void CanvasItemEditorViewport::_notification(int p_what) { @@ -6693,20 +6703,21 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it check->connect("button_down", callable_mp(this, &CanvasItemEditorViewport::_on_select_texture_node_type).bind(check)); } - dropping_tooltip_label = memnew(Label); - dropping_tooltip_label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); - dropping_tooltip_label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - dropping_tooltip_label->hide(); - canvas_item_editor->get_controls_container()->add_child(dropping_tooltip_label); - - dropping_tooltip_label_desc = memnew(Label); - dropping_tooltip_label_desc->set_focus_mode(FOCUS_ACCESSIBILITY); - dropping_tooltip_label_desc->add_theme_color_override(SceneStringName(font_color), Color(0.8f, 0.8f, 0.8f, 1)); - dropping_tooltip_label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); - dropping_tooltip_label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); - dropping_tooltip_label_desc->add_theme_constant_override("line_spacing", 0); - dropping_tooltip_label_desc->hide(); - canvas_item_editor->get_controls_container()->add_child(dropping_tooltip_label_desc); + tooltip_panel = memnew(RichTextLabel); + canvas_item_editor->get_controls_container()->add_child(tooltip_panel); + tooltip_panel->hide(); + tooltip_panel->set_h_grow_direction(GROW_DIRECTION_BEGIN); + tooltip_panel->set_v_grow_direction(GROW_DIRECTION_BEGIN); + tooltip_panel->set_mouse_filter(MOUSE_FILTER_IGNORE); + tooltip_panel->set_focus_mode(FOCUS_ACCESSIBILITY); + tooltip_panel->set_use_bbcode(true); + tooltip_panel->set_fit_content(true); + tooltip_panel->set_scroll_active(false); + tooltip_panel->set_tab_size(0); + tooltip_panel->set_autowrap_mode(TextServer::AUTOWRAP_OFF); + tooltip_panel->set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT); + tooltip_panel->add_theme_color_override(SceneStringName(font_color), Color(0.8f, 0.8f, 0.8f, 1)); + tooltip_panel->add_theme_constant_override("paragraph_separation", 5); RS::get_singleton()->canvas_set_disable_scale(true); } diff --git a/editor/scene/canvas_item_editor_plugin.h b/editor/scene/canvas_item_editor_plugin.h index 10ec26386b..b012d283fe 100644 --- a/editor/scene/canvas_item_editor_plugin.h +++ b/editor/scene/canvas_item_editor_plugin.h @@ -45,6 +45,7 @@ class HScrollBar; class HSplitContainer; class MenuButton; class PanelContainer; +class RichTextLabel; class StyleBoxTexture; class ViewPanner; class VScrollBar; @@ -652,8 +653,7 @@ class CanvasItemEditorViewport : public Control { Control *preview_node = nullptr; AcceptDialog *accept = nullptr; AcceptDialog *texture_node_type_selector = nullptr; - Label *dropping_tooltip_label = nullptr; - Label *dropping_tooltip_label_desc = nullptr; + RichTextLabel *tooltip_panel = nullptr; Ref button_group; void _on_mouse_exit(); @@ -673,6 +673,8 @@ class CanvasItemEditorViewport : public Control { void _show_texture_node_type_selector(); void _update_theme(); + void _show_tooltip(const String &p_title, const String &p_description) const; + protected: void _notification(int p_what);