Merge pull request #72651 from dalexeev/rtl-context-menu
Fix `RichTextLabel` context menu not customizable
This commit is contained in:
commit
3c81bff6c1
3 changed files with 92 additions and 14 deletions
|
@ -106,6 +106,45 @@
|
||||||
<return type="PopupMenu" />
|
<return type="PopupMenu" />
|
||||||
<description>
|
<description>
|
||||||
Returns the [PopupMenu] of this [RichTextLabel]. By default, this menu is displayed when right-clicking on the [RichTextLabel].
|
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.
|
[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>
|
</description>
|
||||||
</method>
|
</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].
|
If [member threaded] is enabled, returns [code]true[/code] if the background thread has finished text processing, otherwise always return [code]true[/code].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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">
|
<method name="newline">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<description>
|
<description>
|
||||||
|
@ -633,6 +679,15 @@
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="ITEM_CUSTOMFX" value="26" enum="ItemType">
|
<constant name="ITEM_CUSTOMFX" value="26" enum="ItemType">
|
||||||
</constant>
|
</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>
|
</constants>
|
||||||
<theme_items>
|
<theme_items>
|
||||||
<theme_item name="default_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
|
<theme_item name="default_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
|
||||||
|
|
|
@ -2031,7 +2031,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) {
|
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->set_position(get_screen_position() + b->get_position());
|
||||||
menu->reset_size();
|
menu->reset_size();
|
||||||
menu->popup();
|
menu->popup();
|
||||||
|
@ -2090,7 +2090,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
if (k->is_action("ui_menu", true)) {
|
if (k->is_action("ui_menu", true)) {
|
||||||
if (context_menu_enabled) {
|
if (context_menu_enabled) {
|
||||||
_generate_context_menu();
|
_update_context_menu();
|
||||||
menu->set_position(get_screen_position());
|
menu->set_position(get_screen_position());
|
||||||
menu->reset_size();
|
menu->reset_size();
|
||||||
menu->popup();
|
menu->popup();
|
||||||
|
@ -4992,7 +4992,9 @@ bool RichTextLabel::is_shortcut_keys_enabled() const {
|
||||||
|
|
||||||
// Context menu.
|
// Context menu.
|
||||||
PopupMenu *RichTextLabel::get_menu() const {
|
PopupMenu *RichTextLabel::get_menu() const {
|
||||||
|
if (!menu) {
|
||||||
const_cast<RichTextLabel *>(this)->_generate_context_menu();
|
const_cast<RichTextLabel *>(this)->_generate_context_menu();
|
||||||
|
}
|
||||||
return 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("get_menu"), &RichTextLabel::get_menu);
|
||||||
ClassDB::bind_method(D_METHOD("is_menu_visible"), &RichTextLabel::is_menu_visible);
|
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);
|
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_HINT);
|
||||||
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
|
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
|
||||||
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
|
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 {
|
TextServer::VisibleCharactersBehavior RichTextLabel::get_visible_characters_behavior() const {
|
||||||
|
@ -5675,19 +5682,32 @@ Size2 RichTextLabel::get_minimum_size() const {
|
||||||
|
|
||||||
// Context menu.
|
// Context menu.
|
||||||
void RichTextLabel::_generate_context_menu() {
|
void RichTextLabel::_generate_context_menu() {
|
||||||
if (!menu) {
|
|
||||||
menu = memnew(PopupMenu);
|
menu = memnew(PopupMenu);
|
||||||
add_child(menu, false, INTERNAL_MODE_FRONT);
|
add_child(menu, false, INTERNAL_MODE_FRONT);
|
||||||
|
menu->connect("id_pressed", callable_mp(this, &RichTextLabel::menu_option));
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reorganize context menu.
|
void RichTextLabel::_update_context_menu() {
|
||||||
menu->clear();
|
if (!menu) {
|
||||||
if (selection.enabled) {
|
_generate_context_menu();
|
||||||
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) {
|
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) {
|
switch (p_option) {
|
||||||
case MENU_COPY: {
|
case MENU_COPY: {
|
||||||
selection_copy();
|
selection_copy();
|
||||||
|
|
|
@ -81,6 +81,7 @@ public:
|
||||||
enum MenuItems {
|
enum MenuItems {
|
||||||
MENU_COPY,
|
MENU_COPY,
|
||||||
MENU_SELECT_ALL,
|
MENU_SELECT_ALL,
|
||||||
|
MENU_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DefaultFont {
|
enum DefaultFont {
|
||||||
|
@ -454,8 +455,8 @@ private:
|
||||||
// Context menu.
|
// Context menu.
|
||||||
PopupMenu *menu = nullptr;
|
PopupMenu *menu = nullptr;
|
||||||
void _generate_context_menu();
|
void _generate_context_menu();
|
||||||
|
void _update_context_menu();
|
||||||
Key _get_menu_action_accelerator(const String &p_action);
|
Key _get_menu_action_accelerator(const String &p_action);
|
||||||
void _menu_option(int p_option);
|
|
||||||
|
|
||||||
int visible_characters = -1;
|
int visible_characters = -1;
|
||||||
float visible_ratio = 1.0;
|
float visible_ratio = 1.0;
|
||||||
|
@ -688,6 +689,7 @@ public:
|
||||||
// Context menu.
|
// Context menu.
|
||||||
PopupMenu *get_menu() const;
|
PopupMenu *get_menu() const;
|
||||||
bool is_menu_visible() const;
|
bool is_menu_visible() const;
|
||||||
|
void menu_option(int p_option);
|
||||||
|
|
||||||
void parse_bbcode(const String &p_bbcode);
|
void parse_bbcode(const String &p_bbcode);
|
||||||
void append_text(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::ListType);
|
||||||
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
|
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
|
||||||
|
VARIANT_ENUM_CAST(RichTextLabel::MenuItems);
|
||||||
|
|
||||||
#endif // RICH_TEXT_LABEL_H
|
#endif // RICH_TEXT_LABEL_H
|
||||||
|
|
Loading…
Reference in a new issue