From b2528671450068d528f7501c84655cfd51ebdb68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:27:35 +0200 Subject: [PATCH] [macOS/Windows] Add `Emoji & Symbols` context menu item to LineEdit/TextEdit to show system character picker. --- doc/classes/DisplayServer.xml | 10 ++++++ doc/classes/LineEdit.xml | 8 ++++- doc/classes/TextEdit.xml | 8 ++++- editor/gui/editor_spin_slider.cpp | 1 + editor/plugins/script_text_editor.cpp | 7 +++++ editor/plugins/script_text_editor.h | 1 + editor/plugins/text_editor.cpp | 7 +++++ editor/plugins/text_editor.h | 1 + editor/plugins/text_shader_editor.cpp | 7 +++++ editor/plugins/text_shader_editor.h | 1 + platform/macos/display_server_macos.h | 1 + platform/macos/display_server_macos.mm | 5 +++ platform/windows/display_server_windows.cpp | 23 ++++++++++++++ platform/windows/display_server_windows.h | 1 + scene/gui/line_edit.cpp | 33 +++++++++++++++++++- scene/gui/line_edit.h | 7 +++++ scene/gui/spin_box.cpp | 1 + scene/gui/text_edit.cpp | 34 ++++++++++++++++++++- scene/gui/text_edit.h | 7 +++++ servers/display_server.cpp | 6 ++++ servers/display_server.h | 2 ++ 21 files changed, 167 insertions(+), 4 deletions(-) diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 1f98e3f4867..a607d6b8ff7 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1215,6 +1215,13 @@ [b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11/Wayland). + + + + Opens system emoji and symbol picker. + [b]Note:[/b] This method is implemented on macOS and Windows. + + @@ -1941,6 +1948,9 @@ Native file selection dialog supports MIME types as filters. + + Display server supports system emoji and symbol picker. [b]Windows, macOS[/b] + Makes the mouse cursor visible if it is hidden. diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 6948d7d454d..dd0d6ed4117 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -276,6 +276,9 @@ If [code]false[/code], existing text cannot be modified and new text cannot be added. + + If [code]false[/code], "Emoji and Symbols" menu is enabled. + If [code]true[/code], the [LineEdit] width will increase to stay longer than the [member text]. It will [b]not[/b] compress if the [member text] is shortened. @@ -478,7 +481,10 @@ Inserts soft hyphen (SHY) character. - + + Opens system emoji and symbol picker. + + Represents the size of the [enum MenuItems] enum. diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index b884fa59586..89e2a2017af 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1299,6 +1299,9 @@ If [code]false[/code], existing text cannot be modified and new text cannot be added. + + If [code]false[/code], "Emoji and Symbols" menu is enabled. + If [code]true[/code], copying or cutting without a selection is performed on all lines with a caret. Otherwise, copy and cut require a selection. @@ -1519,7 +1522,10 @@ Inserts soft hyphen (SHY) character. - + + Opens system emoji and symbol picker. + + Represents the size of the [enum MenuItems] enum. diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp index 35ae1de5c89..cef23fdda1f 100644 --- a/editor/gui/editor_spin_slider.cpp +++ b/editor/gui/editor_spin_slider.cpp @@ -715,6 +715,7 @@ void EditorSpinSlider::_ensure_input_popup() { add_child(value_input_popup); value_input = memnew(LineEdit); + value_input->set_emoji_menu_enabled(false); value_input->set_focus_mode(FOCUS_CLICK); value_input_popup->add_child(value_input); value_input->set_anchors_and_offsets_preset(PRESET_FULL_RECT); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index c1ef99d6533..fa16aba6b91 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1738,6 +1738,9 @@ void ScriptTextEditor::_edit_option(int p_op) { _lookup_symbol(text, tx->get_caret_line(0), tx->get_caret_column(0)); } } break; + case EDIT_EMOJI_AND_SYMBOL: { + code_editor->get_text_editor()->show_emoji_and_symbol_picker(); + } break; default: { if (p_op >= EditorContextMenuPlugin::BASE_ID) { EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_SCRIPT_EDITOR_CODE, p_op, tx); @@ -2294,6 +2297,10 @@ void ScriptTextEditor::_prepare_edit_menu() { void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition, Vector2 p_pos) { context_menu->clear(); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) { + context_menu->add_item(TTR("Emoji & Symbols"), EDIT_EMOJI_AND_SYMBOL); + context_menu->add_separator(); + } context_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO); context_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 0b81490d39a..6bf3f9f1ded 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -157,6 +157,7 @@ class ScriptTextEditor : public ScriptEditorBase { DEBUG_GOTO_PREV_BREAKPOINT, HELP_CONTEXTUAL, LOOKUP_SYMBOL, + EDIT_EMOJI_AND_SYMBOL, }; void _enable_code_editor(); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 274f4ee62cb..ee2d592ed3f 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -481,6 +481,9 @@ void TextEditor::_edit_option(int p_op) { case BOOKMARK_REMOVE_ALL: { code_editor->remove_all_bookmarks(); } break; + case EDIT_EMOJI_AND_SYMBOL: { + code_editor->get_text_editor()->show_emoji_and_symbol_picker(); + } break; } } @@ -560,6 +563,10 @@ void TextEditor::_prepare_edit_menu() { void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position) { context_menu->clear(); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) { + context_menu->add_item(TTR("Emoji & Symbols"), EDIT_EMOJI_AND_SYMBOL); + context_menu->add_separator(); + } if (p_selection) { context_menu->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT); context_menu->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index badeb91817a..e2e7fada7b9 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -91,6 +91,7 @@ private: BOOKMARK_GOTO_NEXT, BOOKMARK_GOTO_PREV, BOOKMARK_REMOVE_ALL, + EDIT_EMOJI_AND_SYMBOL, }; protected: diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 207a56edbb0..2bf14203e66 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -729,6 +729,9 @@ void TextShaderEditor::_menu_option(int p_option) { case HELP_DOCS: { OS::get_singleton()->shell_open(vformat("%s/tutorials/shaders/shader_reference/index.html", VERSION_DOCS_URL)); } break; + case EDIT_EMOJI_AND_SYMBOL: { + code_editor->get_text_editor()->show_emoji_and_symbol_picker(); + } break; } if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) { callable_mp((Control *)code_editor->get_text_editor(), &Control::grab_focus).call_deferred(); @@ -1087,6 +1090,10 @@ void TextShaderEditor::_bookmark_item_pressed(int p_idx) { void TextShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) { context_menu->clear(); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) { + context_menu->add_item(TTR("Emoji & Symbols"), EDIT_EMOJI_AND_SYMBOL); + context_menu->add_separator(); + } if (p_selection) { context_menu->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT); context_menu->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY); diff --git a/editor/plugins/text_shader_editor.h b/editor/plugins/text_shader_editor.h index 33372595549..21d57c5ee6e 100644 --- a/editor/plugins/text_shader_editor.h +++ b/editor/plugins/text_shader_editor.h @@ -134,6 +134,7 @@ class TextShaderEditor : public ShaderEditor { BOOKMARK_GOTO_PREV, BOOKMARK_REMOVE_ALL, HELP_DOCS, + EDIT_EMOJI_AND_SYMBOL, }; MenuButton *edit_menu = nullptr; diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index cc7ef3507e7..32ab1fc478d 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -432,6 +432,7 @@ public: virtual String keyboard_get_layout_name(int p_index) const override; virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; virtual Key keyboard_get_label_from_physical(Key p_keycode) const override; + virtual void show_emoji_and_symbol_picker() const override; virtual void process_events() override; virtual void force_process_and_drop_events() override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 2e1326ae4f6..174e28310ef 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -789,6 +789,7 @@ bool DisplayServerMacOS::has_feature(Feature p_feature) const { case FEATURE_NATIVE_HELP: case FEATURE_WINDOW_DRAG: case FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE: + case FEATURE_EMOJI_AND_SYMBOL_PICKER: return true; default: { } @@ -3134,6 +3135,10 @@ Key DisplayServerMacOS::keyboard_get_label_from_physical(Key p_keycode) const { return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0, true) | modifiers); } +void DisplayServerMacOS::show_emoji_and_symbol_picker() const { + [[NSApplication sharedApplication] orderFrontCharacterPalette:nil]; +} + void DisplayServerMacOS::process_events() { ERR_FAIL_COND(!Thread::is_main_thread()); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index d6e4063d4cd..4d9e7b3965d 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -140,6 +140,8 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const { case FEATURE_WINDOW_EMBEDDING: case FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE: return true; + case FEATURE_EMOJI_AND_SYMBOL_PICKER: + return (os_ver.dwBuildNumber >= 17134); // Windows 10 Redstone 4 (1803)+ only. default: return false; } @@ -3433,6 +3435,27 @@ Key DisplayServerWindows::keyboard_get_label_from_physical(Key p_keycode) const return p_keycode; } +void DisplayServerWindows::show_emoji_and_symbol_picker() const { + // Send Win + Period shortcut, there's no non-WinRT public API. + + INPUT input[4] = {}; + input[0].type = INPUT_KEYBOARD; // Win down. + input[0].ki.wVk = VK_LWIN; + + input[1].type = INPUT_KEYBOARD; // Period down. + input[1].ki.wVk = VK_OEM_PERIOD; + + input[2].type = INPUT_KEYBOARD; // Win up. + input[2].ki.wVk = VK_LWIN; + input[2].ki.dwFlags = KEYEVENTF_KEYUP; + + input[3].type = INPUT_KEYBOARD; // Period up. + input[3].ki.wVk = VK_OEM_PERIOD; + input[3].ki.dwFlags = KEYEVENTF_KEYUP; + + SendInput(4, input, sizeof(INPUT)); +} + String DisplayServerWindows::_get_keyboard_layout_display_name(const String &p_klid) const { String ret; HKEY key; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 5d69e1490d6..b85394366e8 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -842,6 +842,7 @@ public: virtual String keyboard_get_layout_name(int p_index) const override; virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; virtual Key keyboard_get_label_from_physical(Key p_keycode) const override; + virtual void show_emoji_and_symbol_picker() const override; virtual int tablet_get_driver_count() const override; virtual String tablet_get_driver_name(int p_driver) const override; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 77c5b01e925..d54e31b4511 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2369,7 +2369,10 @@ void LineEdit::menu_option(int p_option) { if (editable) { insert_text_at_caret(String::chr(0x00AD)); } - } + } break; + case MENU_EMOJI_AND_SYMBOL: { + show_emoji_and_symbol_picker(); + } break; } } @@ -2381,6 +2384,22 @@ bool LineEdit::is_context_menu_enabled() { return context_menu_enabled; } +void LineEdit::show_emoji_and_symbol_picker() { + _update_ime_window_position(); + DisplayServer::get_singleton()->show_emoji_and_symbol_picker(); +} + +void LineEdit::set_emoji_menu_enabled(bool p_enabled) { + if (emoji_menu_enabled != p_enabled) { + emoji_menu_enabled = p_enabled; + _update_context_menu(); + } +} + +bool LineEdit::is_emoji_menu_enabled() const { + return emoji_menu_enabled; +} + bool LineEdit::is_menu_visible() const { return menu && menu->is_visible(); } @@ -2709,6 +2728,11 @@ void LineEdit::_generate_context_menu() { menu_ctl->add_item(ETR("Word Joiner (WJ)"), MENU_INSERT_WJ); menu_ctl->add_item(ETR("Soft Hyphen (SHY)"), MENU_INSERT_SHY); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) { + menu->add_item(ETR("Emoji & Symbols"), MENU_EMOJI_AND_SYMBOL); + menu->add_separator(); + } + menu->add_item(ETR("Cut"), MENU_CUT); menu->add_item(ETR("Copy"), MENU_COPY); menu->add_item(ETR("Paste"), MENU_PASTE); @@ -2764,6 +2788,9 @@ void LineEdit::_update_context_menu() { m_menu->set_item_checked(idx, m_checked); \ } + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) { + MENU_ITEM_DISABLED(menu, MENU_EMOJI_AND_SYMBOL, !editable || !emoji_menu_enabled) + } MENU_ITEM_ACTION_DISABLED(menu, MENU_CUT, "ui_cut", !editable) MENU_ITEM_ACTION(menu, MENU_COPY, "ui_copy") MENU_ITEM_ACTION_DISABLED(menu, MENU_PASTE, "ui_paste", !editable) @@ -2859,6 +2886,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_menu_visible"), &LineEdit::is_menu_visible); ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled); ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled); + ClassDB::bind_method(D_METHOD("set_emoji_menu_enabled", "enable"), &LineEdit::set_emoji_menu_enabled); + ClassDB::bind_method(D_METHOD("is_emoji_menu_enabled"), &LineEdit::is_emoji_menu_enabled); ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &LineEdit::set_virtual_keyboard_enabled); ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &LineEdit::is_virtual_keyboard_enabled); ClassDB::bind_method(D_METHOD("set_virtual_keyboard_type", "type"), &LineEdit::set_virtual_keyboard_type); @@ -2917,6 +2946,7 @@ void LineEdit::_bind_methods() { BIND_ENUM_CONSTANT(MENU_INSERT_ZWNJ); BIND_ENUM_CONSTANT(MENU_INSERT_WJ); BIND_ENUM_CONSTANT(MENU_INSERT_SHY); + BIND_ENUM_CONSTANT(MENU_EMOJI_AND_SYMBOL); BIND_ENUM_CONSTANT(MENU_MAX); BIND_ENUM_CONSTANT(KEYBOARD_TYPE_DEFAULT); @@ -2936,6 +2966,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_editing_on_text_submit"), "set_keep_editing_on_text_submit", "is_editing_kept_on_text_submit"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length_enabled", "is_expand_to_text_length_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emoji_menu_enabled"), "set_emoji_menu_enabled", "is_emoji_menu_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "virtual_keyboard_type", PROPERTY_HINT_ENUM, "Default,Multiline,Number,Decimal,Phone,Email,Password,URL"), "set_virtual_keyboard_type", "get_virtual_keyboard_type"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled"); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index b60493b32dc..6f6b49307c9 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -69,6 +69,7 @@ public: MENU_INSERT_ZWNJ, MENU_INSERT_WJ, MENU_INSERT_SHY, + MENU_EMOJI_AND_SYMBOL, MENU_MAX }; @@ -112,6 +113,7 @@ private: bool drag_and_drop_selection_enabled = true; bool context_menu_enabled = true; + bool emoji_menu_enabled = true; PopupMenu *menu = nullptr; PopupMenu *menu_dir = nullptr; PopupMenu *menu_ctl = nullptr; @@ -289,6 +291,11 @@ public: PopupMenu *get_menu() const; bool is_menu_visible() const; + void show_emoji_and_symbol_picker(); + + void set_emoji_menu_enabled(bool p_enabled); + bool is_emoji_menu_enabled() const; + void select(int p_from = 0, int p_to = -1); void select_all(); void selection_delete(); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index ffe6e2bb978..785ffa14e92 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -622,6 +622,7 @@ void SpinBox::_bind_methods() { SpinBox::SpinBox() { line_edit = memnew(LineEdit); + line_edit->set_emoji_menu_enabled(false); add_child(line_edit, false, INTERNAL_MODE_FRONT); line_edit->set_theme_type_variation("SpinBoxInnerLineEdit"); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index e4469167a74..85a6dce028e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3357,6 +3357,22 @@ bool TextEdit::is_context_menu_enabled() const { return context_menu_enabled; } +void TextEdit::show_emoji_and_symbol_picker() { + _update_ime_window_position(); + DisplayServer::get_singleton()->show_emoji_and_symbol_picker(); +} + +void TextEdit::set_emoji_menu_enabled(bool p_enabled) { + if (emoji_menu_enabled != p_enabled) { + emoji_menu_enabled = p_enabled; + _update_context_menu(); + } +} + +bool TextEdit::is_emoji_menu_enabled() const { + return emoji_menu_enabled; +} + void TextEdit::set_shortcut_keys_enabled(bool p_enabled) { shortcut_keys_enabled = p_enabled; } @@ -4031,7 +4047,10 @@ void TextEdit::menu_option(int p_option) { if (editable) { insert_text_at_caret(String::chr(0x00AD)); } - } + } break; + case MENU_EMOJI_AND_SYMBOL: { + show_emoji_and_symbol_picker(); + } break; } } @@ -6583,6 +6602,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enabled"), &TextEdit::set_context_menu_enabled); ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled); + ClassDB::bind_method(D_METHOD("set_emoji_menu_enabled", "enable"), &TextEdit::set_emoji_menu_enabled); + ClassDB::bind_method(D_METHOD("is_emoji_menu_enabled"), &TextEdit::is_emoji_menu_enabled); + ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enabled"), &TextEdit::set_shortcut_keys_enabled); ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &TextEdit::is_shortcut_keys_enabled); @@ -6674,6 +6696,7 @@ void TextEdit::_bind_methods() { BIND_ENUM_CONSTANT(MENU_INSERT_ZWNJ); BIND_ENUM_CONSTANT(MENU_INSERT_WJ); BIND_ENUM_CONSTANT(MENU_INSERT_SHY); + BIND_ENUM_CONSTANT(MENU_EMOJI_AND_SYMBOL); BIND_ENUM_CONSTANT(MENU_MAX); /* Versioning */ @@ -6982,6 +7005,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emoji_menu_enabled"), "set_emoji_menu_enabled", "is_emoji_menu_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled"); @@ -7433,6 +7457,11 @@ void TextEdit::_generate_context_menu() { menu_ctl->add_item(ETR("Word Joiner (WJ)"), MENU_INSERT_WJ); menu_ctl->add_item(ETR("Soft Hyphen (SHY)"), MENU_INSERT_SHY); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) { + menu->add_item(ETR("Emoji & Symbols"), MENU_EMOJI_AND_SYMBOL); + menu->add_separator(); + } + menu->add_item(ETR("Cut"), MENU_CUT); menu->add_item(ETR("Copy"), MENU_COPY); menu->add_item(ETR("Paste"), MENU_PASTE); @@ -7485,6 +7514,9 @@ void TextEdit::_update_context_menu() { m_menu->set_item_checked(idx, m_checked); \ } + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EMOJI_AND_SYMBOL_PICKER)) { + MENU_ITEM_DISABLED(menu, MENU_EMOJI_AND_SYMBOL, !editable || !emoji_menu_enabled) + } MENU_ITEM_ACTION_DISABLED(menu, MENU_CUT, "ui_cut", !editable) MENU_ITEM_ACTION(menu, MENU_COPY, "ui_copy") MENU_ITEM_ACTION_DISABLED(menu, MENU_PASTE, "ui_paste", !editable) diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 04ddb1895fc..ef511096302 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -110,6 +110,7 @@ public: MENU_INSERT_ZWNJ, MENU_INSERT_WJ, MENU_INSERT_SHY, + MENU_EMOJI_AND_SYMBOL, MENU_MAX }; @@ -316,6 +317,7 @@ private: // User control. bool overtype_mode = false; bool context_menu_enabled = true; + bool emoji_menu_enabled = true; bool shortcut_keys_enabled = true; bool virtual_keyboard_enabled = true; bool middle_mouse_paste_enabled = true; @@ -762,6 +764,11 @@ public: void set_context_menu_enabled(bool p_enabled); bool is_context_menu_enabled() const; + void show_emoji_and_symbol_picker(); + + void set_emoji_menu_enabled(bool p_enabled); + bool is_emoji_menu_enabled() const; + void set_shortcut_keys_enabled(bool p_enabled); bool is_shortcut_keys_enabled() const; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index c30a619d8cf..bf3dacc7f7d 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -723,6 +723,9 @@ Key DisplayServer::keyboard_get_label_from_physical(Key p_keycode) const { ERR_FAIL_V_MSG(p_keycode, "Not supported by this display server."); } +void DisplayServer::show_emoji_and_symbol_picker() const { +} + void DisplayServer::force_process_and_drop_events() { } @@ -1029,6 +1032,8 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("keyboard_get_keycode_from_physical", "keycode"), &DisplayServer::keyboard_get_keycode_from_physical); ClassDB::bind_method(D_METHOD("keyboard_get_label_from_physical", "keycode"), &DisplayServer::keyboard_get_label_from_physical); + ClassDB::bind_method(D_METHOD("show_emoji_and_symbol_picker"), &DisplayServer::show_emoji_and_symbol_picker); + ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events); ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events); @@ -1086,6 +1091,7 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE); BIND_ENUM_CONSTANT(FEATURE_WINDOW_EMBEDDING); BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE_MIME); + BIND_ENUM_CONSTANT(FEATURE_EMOJI_AND_SYMBOL_PICKER); BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); diff --git a/servers/display_server.h b/servers/display_server.h index 460c1610ec7..562c2bf5abe 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -157,6 +157,7 @@ public: FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE, FEATURE_WINDOW_EMBEDDING, FEATURE_NATIVE_DIALOG_FILE_MIME, + FEATURE_EMOJI_AND_SYMBOL_PICKER, }; virtual bool has_feature(Feature p_feature) const = 0; @@ -593,6 +594,7 @@ public: virtual String keyboard_get_layout_name(int p_index) const; virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const; virtual Key keyboard_get_label_from_physical(Key p_keycode) const; + virtual void show_emoji_and_symbol_picker() const; virtual int tablet_get_driver_count() const { return 1; } virtual String tablet_get_driver_name(int p_driver) const { return "default"; }