Fix `RichTextLabel` context menu not customizable

This commit is contained in:
Danil Alexeev 2023-02-03 12:07:36 +03:00
parent 1ed549e64b
commit fb107e04d3
No known key found for this signature in database
GPG Key ID: 124453E157DA8DC7
3 changed files with 92 additions and 14 deletions

View File

@ -106,6 +106,45 @@
<return type="PopupMenu" />
<description>
Returns the [PopupMenu] of this [RichTextLabel]. By default, this menu is displayed when right-clicking on the [RichTextLabel].
You can add custom menu items or remove standard ones. Make sure your IDs don't conflict with the standard ones (see [enum MenuItems]). For example:
[codeblocks]
[gdscript]
func _ready():
var menu = get_menu()
# Remove "Select All" item.
menu.remove_item(MENU_SELECT_ALL)
# Add custom items.
menu.add_separator()
menu.add_item("Duplicate Text", MENU_MAX + 1)
# Connect callback.
menu.id_pressed.connect(_on_item_pressed)
func _on_item_pressed(id):
if id == MENU_MAX + 1:
add_text("\n" + get_parsed_text())
[/gdscript]
[csharp]
public override void _Ready()
{
var menu = GetMenu();
// Remove "Select All" item.
menu.RemoveItem(RichTextLabel.MenuItems.SelectAll);
// Add custom items.
menu.AddSeparator();
menu.AddItem("Duplicate Text", RichTextLabel.MenuItems.Max + 1);
// Add event handler.
menu.IdPressed += OnItemPressed;
}
public void OnItemPressed(int id)
{
if (id == TextEdit.MenuItems.Max + 1)
{
AddText("\n" + GetParsedText());
}
}
[/csharp]
[/codeblocks]
[b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member Window.visible] property.
</description>
</method>
@ -193,6 +232,13 @@
If [member threaded] is enabled, returns [code]true[/code] if the background thread has finished text processing, otherwise always return [code]true[/code].
</description>
</method>
<method name="menu_option">
<return type="void" />
<param index="0" name="option" type="int" />
<description>
Executes a given action as defined in the [enum MenuItems] enum.
</description>
</method>
<method name="newline">
<return type="void" />
<description>
@ -633,6 +679,15 @@
</constant>
<constant name="ITEM_CUSTOMFX" value="26" enum="ItemType">
</constant>
<constant name="MENU_COPY" value="0" enum="MenuItems">
Copies the selected text.
</constant>
<constant name="MENU_SELECT_ALL" value="1" enum="MenuItems">
Selects the whole [RichTextLabel] text.
</constant>
<constant name="MENU_MAX" value="2" enum="MenuItems">
Represents the size of the [enum MenuItems] enum.
</constant>
</constants>
<theme_items>
<theme_item name="default_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">

View File

@ -2031,7 +2031,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
}
if (b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) {
_generate_context_menu();
_update_context_menu();
menu->set_position(get_screen_position() + b->get_position());
menu->reset_size();
menu->popup();
@ -2090,7 +2090,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
if (k->is_action("ui_menu", true)) {
if (context_menu_enabled) {
_generate_context_menu();
_update_context_menu();
menu->set_position(get_screen_position());
menu->reset_size();
menu->popup();
@ -4992,7 +4992,9 @@ bool RichTextLabel::is_shortcut_keys_enabled() const {
// Context menu.
PopupMenu *RichTextLabel::get_menu() const {
const_cast<RichTextLabel *>(this)->_generate_context_menu();
if (!menu) {
const_cast<RichTextLabel *>(this)->_generate_context_menu();
}
return menu;
}
@ -5466,6 +5468,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_menu"), &RichTextLabel::get_menu);
ClassDB::bind_method(D_METHOD("is_menu_visible"), &RichTextLabel::is_menu_visible);
ClassDB::bind_method(D_METHOD("menu_option", "option"), &RichTextLabel::menu_option);
ClassDB::bind_method(D_METHOD("_thread_end"), &RichTextLabel::_thread_end);
@ -5544,6 +5547,10 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(ITEM_HINT);
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
BIND_ENUM_CONSTANT(MENU_COPY);
BIND_ENUM_CONSTANT(MENU_SELECT_ALL);
BIND_ENUM_CONSTANT(MENU_MAX);
}
TextServer::VisibleCharactersBehavior RichTextLabel::get_visible_characters_behavior() const {
@ -5675,19 +5682,32 @@ Size2 RichTextLabel::get_minimum_size() const {
// Context menu.
void RichTextLabel::_generate_context_menu() {
menu = memnew(PopupMenu);
add_child(menu, false, INTERNAL_MODE_FRONT);
menu->connect("id_pressed", callable_mp(this, &RichTextLabel::menu_option));
menu->add_item(RTR("Copy"), MENU_COPY);
menu->add_item(RTR("Select All"), MENU_SELECT_ALL);
}
void RichTextLabel::_update_context_menu() {
if (!menu) {
menu = memnew(PopupMenu);
add_child(menu, false, INTERNAL_MODE_FRONT);
menu->connect("id_pressed", callable_mp(this, &RichTextLabel::_menu_option));
_generate_context_menu();
}
// Reorganize context menu.
menu->clear();
if (selection.enabled) {
menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : Key::NONE);
menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : Key::NONE);
int idx = -1;
#define MENU_ITEM_ACTION_DISABLED(m_menu, m_id, m_action, m_disabled) \
idx = m_menu->get_item_index(m_id); \
if (idx >= 0) { \
m_menu->set_item_accelerator(idx, shortcut_keys_enabled ? _get_menu_action_accelerator(m_action) : Key::NONE); \
m_menu->set_item_disabled(idx, m_disabled); \
}
MENU_ITEM_ACTION_DISABLED(menu, MENU_COPY, "ui_copy", !selection.enabled)
MENU_ITEM_ACTION_DISABLED(menu, MENU_SELECT_ALL, "ui_text_select_all", !selection.enabled)
#undef MENU_ITEM_ACTION_DISABLED
}
Key RichTextLabel::_get_menu_action_accelerator(const String &p_action) {
@ -5715,7 +5735,7 @@ Key RichTextLabel::_get_menu_action_accelerator(const String &p_action) {
}
}
void RichTextLabel::_menu_option(int p_option) {
void RichTextLabel::menu_option(int p_option) {
switch (p_option) {
case MENU_COPY: {
selection_copy();

View File

@ -81,6 +81,7 @@ public:
enum MenuItems {
MENU_COPY,
MENU_SELECT_ALL,
MENU_MAX
};
enum DefaultFont {
@ -454,8 +455,8 @@ private:
// Context menu.
PopupMenu *menu = nullptr;
void _generate_context_menu();
void _update_context_menu();
Key _get_menu_action_accelerator(const String &p_action);
void _menu_option(int p_option);
int visible_characters = -1;
float visible_ratio = 1.0;
@ -688,6 +689,7 @@ public:
// Context menu.
PopupMenu *get_menu() const;
bool is_menu_visible() const;
void menu_option(int p_option);
void parse_bbcode(const String &p_bbcode);
void append_text(const String &p_bbcode);
@ -739,5 +741,6 @@ public:
VARIANT_ENUM_CAST(RichTextLabel::ListType);
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
VARIANT_ENUM_CAST(RichTextLabel::MenuItems);
#endif // RICH_TEXT_LABEL_H