diff --git a/editor/doc/editor_help.cpp b/editor/doc/editor_help.cpp index ea6c2d4a71..a2ed9d83d0 100644 --- a/editor/doc/editor_help.cpp +++ b/editor/doc/editor_help.cpp @@ -4640,6 +4640,20 @@ void EditorHelpBitTooltip::_target_gui_input(const Ref &p_event) { break; } } + + const Ref k = p_event; + if (k.is_valid() && k->is_pressed()) { + queue_free(); + } +} + +void EditorHelpBitTooltip::_shortcut_pressed(Control *p_target) { + TextEdit *tx = Object::cast_to(p_target); + if (tx) { + popup_under_position( + tx->get_global_position() + tx->get_caret_draw_pos() + + Point2(0, tx->get_line_height()) + tx->get_window()->get_position_with_decorations()); + } } void EditorHelpBitTooltip::_notification(int p_what) { @@ -4659,7 +4673,7 @@ void EditorHelpBitTooltip::_notification(int p_what) { _is_mouse_inside_tooltip = false; _start_timer(); break; - case NOTIFICATION_INTERNAL_PROCESS: + case NOTIFICATION_INTERNAL_PROCESS: { // A workaround to hide the tooltip since the window does not receive keyboard events // with `FLAG_POPUP` and `FLAG_NO_FOCUS` flags, so we can't use `_input_from_window()`. if (is_inside_tree()) { @@ -4667,9 +4681,11 @@ void EditorHelpBitTooltip::_notification(int p_what) { queue_free(); get_parent_viewport()->set_input_as_handled(); } else if (Input::get_singleton()->is_any_key_pressed()) { - queue_free(); + if (!_is_shortcut_pressed) { + queue_free(); + } } else if (!Input::get_singleton()->get_mouse_button_mask().is_empty()) { - if (!_is_mouse_inside_tooltip) { + if (!_is_mouse_inside_tooltip && !_is_shortcut_pressed) { queue_free(); } } else if (!Input::get_singleton()->get_last_mouse_velocity().is_zero_approx()) { @@ -4678,38 +4694,41 @@ void EditorHelpBitTooltip::_notification(int p_what) { } } } - break; + } break; } } -Control *EditorHelpBitTooltip::make_tooltip(Control *p_target, const String &p_symbol, const String &p_prologue, bool p_use_class_prefix) { +Control *EditorHelpBitTooltip::make_tooltip(Control *p_target, const String &p_symbol, const String &p_prologue, bool p_use_class_prefix, bool p_shortcut) { ERR_FAIL_NULL_V(p_target, _make_invisible_control()); // Show the custom tooltip only if it is not already visible. // The viewport will retrigger `make_custom_tooltip()` every few seconds // because the return control is not visible even if the custom tooltip is displayed. - if (_is_tooltip_visible || Input::get_singleton()->is_anything_pressed()) { + if (_is_tooltip_visible || (!p_shortcut && Input::get_singleton()->is_anything_pressed())) { return _make_invisible_control(); } EditorHelpBit *help_bit = memnew(EditorHelpBit(p_symbol, p_prologue, p_use_class_prefix, false, true)); - EditorHelpBitTooltip *tooltip = memnew(EditorHelpBitTooltip(p_target)); + EditorHelpBitTooltip *tooltip = memnew(EditorHelpBitTooltip(p_target, p_shortcut)); help_bit->connect("request_hide", callable_mp(static_cast(tooltip), &Node::queue_free)); tooltip->add_child(help_bit); p_target->add_child(tooltip); help_bit->update_content_height(); - tooltip->popup_under_cursor(); + if (tooltip->is_shortcut_pressed()) { + tooltip->_shortcut_pressed(p_target); + } else { + tooltip->popup_under_position(tooltip->get_mouse_position()); + } return _make_invisible_control(); } // Copy-paste from `Viewport::_gui_show_tooltip()`. -void EditorHelpBitTooltip::popup_under_cursor() { - Point2 mouse_pos = get_mouse_position(); +void EditorHelpBitTooltip::popup_under_position(const Point2 &p_point) { Point2 tooltip_offset = GLOBAL_GET_CACHED(Point2, "display/mouse_cursor/tooltip_position_offset"); - Rect2 r(mouse_pos + tooltip_offset, get_contents_minimum_size()); + Rect2 r(p_point + tooltip_offset, get_contents_minimum_size()); r.size = r.size.min(get_max_size()); Window *window = get_parent_visible_window(); @@ -4723,7 +4742,7 @@ void EditorHelpBitTooltip::popup_under_cursor() { if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SELF_FITTING_WINDOWS) || is_embedded()) { if (r.size.x + r.position.x > vr.size.x + vr.position.x) { // Place it in the opposite direction. If it fails, just hug the border. - r.position.x = mouse_pos.x - r.size.x - tooltip_offset.x; + r.position.x = p_point.x - r.size.x - tooltip_offset.x; if (r.position.x < vr.position.x) { r.position.x = vr.position.x + vr.size.x - r.size.x; @@ -4734,7 +4753,7 @@ void EditorHelpBitTooltip::popup_under_cursor() { if (r.size.y + r.position.y > vr.size.y + vr.position.y) { // Same as above. - r.position.y = mouse_pos.y - r.size.y - tooltip_offset.y; + r.position.y = p_point.y - r.size.y - tooltip_offset.y; if (r.position.y < vr.position.y) { r.position.y = vr.position.y + vr.size.y - r.size.y; @@ -4751,9 +4770,11 @@ void EditorHelpBitTooltip::popup_under_cursor() { popup(r); } -EditorHelpBitTooltip::EditorHelpBitTooltip(Control *p_target) { +EditorHelpBitTooltip::EditorHelpBitTooltip(Control *p_target, bool p_shortcut) { ERR_FAIL_NULL(p_target); + _is_shortcut_pressed = p_shortcut; + set_theme_type_variation("TooltipPanel"); timer = memnew(Timer); diff --git a/editor/doc/editor_help.h b/editor/doc/editor_help.h index f72246ed22..114062f4b4 100644 --- a/editor/doc/editor_help.h +++ b/editor/doc/editor_help.h @@ -369,22 +369,26 @@ class EditorHelpBitTooltip : public PopupPanel { Timer *timer = nullptr; uint64_t _enter_tree_time = 0; bool _is_mouse_inside_tooltip = false; + bool _is_shortcut_pressed = false; static Control *_make_invisible_control(); void _start_timer(); void _target_gui_input(const Ref &p_event); + void _shortcut_pressed(Control *p_target); protected: void _notification(int p_what); public: // The returned control is an orphan node, which is to make the standard tooltip invisible. - [[nodiscard]] static Control *make_tooltip(Control *p_target, const String &p_symbol, const String &p_prologue = String(), bool p_use_class_prefix = false); + [[nodiscard]] static Control *make_tooltip(Control *p_target, const String &p_symbol, const String &p_prologue = String(), bool p_use_class_prefix = false, bool p_shortcut = false); - void popup_under_cursor(); + void popup_under_position(const Point2 &p_point); - EditorHelpBitTooltip(Control *p_target); + bool is_shortcut_pressed() const { return _is_shortcut_pressed; } + + EditorHelpBitTooltip(Control *p_target, bool p_shortcut = false); }; class EditorSyntaxHighlighter; diff --git a/editor/script/script_text_editor.cpp b/editor/script/script_text_editor.cpp index 20c0f6ce69..14b03b9aee 100644 --- a/editor/script/script_text_editor.cpp +++ b/editor/script/script_text_editor.cpp @@ -184,6 +184,7 @@ ScriptTextEditor::EditMenusSTE::EditMenusSTE() { edit_menu_convert_indent->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT); search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/show_tooltip"), SHOW_TOOLTIP_AT_CARET); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); breakpoints_menu = memnew(PopupMenu); @@ -1300,7 +1301,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) { } } -void ScriptTextEditor::_show_symbol_tooltip(const String &p_symbol, int p_row, int p_column) { +void ScriptTextEditor::_show_symbol_tooltip(const String &p_symbol, int p_row, int p_column, bool p_shortcut) { if (!EDITOR_GET("text_editor/behavior/documentation/enable_tooltips").booleanize()) { return; } @@ -1418,7 +1419,7 @@ void ScriptTextEditor::_show_symbol_tooltip(const String &p_symbol, int p_row, i } if (!doc_symbol.is_empty() || !debug_value.is_empty()) { - Control *tmp = EditorHelpBitTooltip::make_tooltip(code_editor->get_text_editor(), doc_symbol, debug_value, true); + Control *tmp = EditorHelpBitTooltip::make_tooltip(code_editor->get_text_editor(), doc_symbol, debug_value, true, p_shortcut); memdelete(tmp); } } @@ -1793,6 +1794,9 @@ bool ScriptTextEditor::_edit_option(int p_op) { } code_editor->goto_line_centered(bpoints[bpoint_idx]); } break; + case SHOW_TOOLTIP_AT_CARET: { + _show_symbol_tooltip(tx->get_word_under_caret(), tx->get_caret_line(), tx->get_caret_column(), true); + } break; case HELP_CONTEXTUAL: { String text = tx->get_selected_text(0); if (text.is_empty()) { @@ -2565,6 +2569,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/replace_in_files", TTRC("Replace in Files..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::R); + ED_SHORTCUT("script_text_editor/show_tooltip", TTRC("Show Tooltip"), KeyModifierMask::ALT | Key::SLASH, true); ED_SHORTCUT("script_text_editor/contextual_help", TTRC("Contextual Help"), KeyModifierMask::ALT | Key::F1); ED_SHORTCUT_OVERRIDE("script_text_editor/contextual_help", "macos", KeyModifierMask::ALT | KeyModifierMask::SHIFT | Key::SPACE); @@ -2598,7 +2603,7 @@ void ScriptTextEditor::_enable_code_editor() { code_editor->connect("show_errors_panel", callable_mp(this, &ScriptTextEditor::_show_errors_panel)); code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); code_editor->get_text_editor()->connect("symbol_lookup", callable_mp(this, &ScriptTextEditor::_lookup_symbol)); - code_editor->get_text_editor()->connect("symbol_hovered", callable_mp(this, &ScriptTextEditor::_show_symbol_tooltip)); + code_editor->get_text_editor()->connect("symbol_hovered", callable_mp(this, &ScriptTextEditor::_show_symbol_tooltip).bind(false)); code_editor->get_text_editor()->connect("symbol_validate", callable_mp(this, &ScriptTextEditor::_validate_symbol)); code_editor->get_text_editor()->connect("gutter_added", callable_mp(this, &ScriptTextEditor::_update_gutter_indexes)); code_editor->get_text_editor()->connect("gutter_removed", callable_mp(this, &ScriptTextEditor::_update_gutter_indexes)); diff --git a/editor/script/script_text_editor.h b/editor/script/script_text_editor.h index 35d7d23218..bb5c877d20 100644 --- a/editor/script/script_text_editor.h +++ b/editor/script/script_text_editor.h @@ -115,6 +115,7 @@ class ScriptTextEditor : public CodeEditorBase { DEBUG_GOTO_NEXT_BREAKPOINT, DEBUG_GOTO_PREV_BREAKPOINT, + SHOW_TOOLTIP_AT_CARET, HELP_CONTEXTUAL, LOOKUP_SYMBOL, }; @@ -191,7 +192,7 @@ protected: void _lookup_symbol(const String &p_symbol, int p_row, int p_column); void _validate_symbol(const String &p_symbol); - void _show_symbol_tooltip(const String &p_symbol, int p_row, int p_column); + void _show_symbol_tooltip(const String &p_symbol, int p_row, int p_column, bool p_shortcut = false); Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;