Merge pull request #60170 from ConteZero/context_menu

This commit is contained in:
Rémi Verschelde 2022-04-12 18:42:58 +02:00 committed by GitHub
commit d9cb39c2e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 160 additions and 5 deletions

View file

@ -94,6 +94,13 @@
Returns the vertical offset of the line found at the provided index.
</description>
</method>
<method name="get_menu" qualifiers="const">
<return type="PopupMenu" />
<description>
Returns the [PopupMenu] of this [RichTextLabel]. By default, this menu is displayed when right-clicking on the [RichTextLabel].
[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>
<method name="get_paragraph_count" qualifiers="const">
<return type="int" />
<description>
@ -163,6 +170,12 @@
Installs a custom effect. [code]effect[/code] should be a valid [RichTextEffect].
</description>
</method>
<method name="is_menu_visible" qualifiers="const">
<return type="bool" />
<description>
Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided).
</description>
</method>
<method name="newline">
<return type="void" />
<description>
@ -433,6 +446,9 @@
If [code]true[/code], the label uses BBCode formatting.
</member>
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" overrides="Control" default="true" />
<member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled" default="false">
If [code]true[/code], a right-click displays the context menu.
</member>
<member name="custom_effects" type="Array" setter="set_effects" getter="get_effects" default="[]">
The currently installed custom effects. This is an array of [RichTextEffect]s.
To add a custom effect, it's more convenient to use [method install_effect].
@ -469,6 +485,9 @@
<member name="selection_enabled" type="bool" setter="set_selection_enabled" getter="is_selection_enabled" default="false">
If [code]true[/code], the label allows text selection.
</member>
<member name="shortcut_keys_enabled" type="bool" setter="set_shortcut_keys_enabled" getter="is_shortcut_keys_enabled" default="true">
If [code]true[/code], shortcut keys for context menu items are enabled, even if the context menu is disabled.
</member>
<member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0">
Set BiDi algorithm override for the structured text.
</member>

View file

@ -30,6 +30,7 @@
#include "rich_text_label.h"
#include "core/input/input_map.h"
#include "core/math/math_defs.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@ -1868,6 +1869,13 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
vscroll->set_value(vscroll->get_value() + vscroll->get_page() * b->get_factor() * 0.5 / 8);
}
}
if (b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) {
_generate_context_menu();
menu->set_position(get_screen_position() + b->get_position());
menu->reset_size();
menu->popup();
grab_focus();
}
}
Ref<InputEventPanGesture> pan_gesture = p_event;
@ -1909,12 +1917,24 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
vscroll->set_value(vscroll->get_max());
handled = true;
}
if (k->is_action("ui_text_select_all")) {
select_all();
handled = true;
if (is_shortcut_keys_enabled()) {
if (k->is_action("ui_text_select_all")) {
select_all();
handled = true;
}
if (k->is_action("ui_copy")) {
selection_copy();
handled = true;
}
}
if (k->is_action("ui_copy")) {
selection_copy();
if (k->is_action("ui_menu", true)) {
if (context_menu_enabled) {
_generate_context_menu();
menu->set_position(get_screen_position());
menu->reset_size();
menu->popup();
menu->grab_focus();
}
handled = true;
}
@ -4175,6 +4195,32 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p
return text;
}
void RichTextLabel::set_context_menu_enabled(bool p_enabled) {
context_menu_enabled = p_enabled;
}
bool RichTextLabel::is_context_menu_enabled() const {
return context_menu_enabled;
}
void RichTextLabel::set_shortcut_keys_enabled(bool p_enabled) {
shortcut_keys_enabled = p_enabled;
}
bool RichTextLabel::is_shortcut_keys_enabled() const {
return shortcut_keys_enabled;
}
// Context menu.
PopupMenu *RichTextLabel::get_menu() const {
const_cast<RichTextLabel *>(this)->_generate_context_menu();
return menu;
}
bool RichTextLabel::is_menu_visible() const {
return menu && menu->is_visible();
}
String RichTextLabel::get_selected_text() const {
if (!selection.active || !selection.enabled) {
return "";
@ -4527,6 +4573,12 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selection_enabled", "enabled"), &RichTextLabel::set_selection_enabled);
ClassDB::bind_method(D_METHOD("is_selection_enabled"), &RichTextLabel::is_selection_enabled);
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enabled"), &RichTextLabel::set_context_menu_enabled);
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &RichTextLabel::is_context_menu_enabled);
ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enabled"), &RichTextLabel::set_shortcut_keys_enabled);
ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &RichTextLabel::is_shortcut_keys_enabled);
ClassDB::bind_method(D_METHOD("set_deselect_on_focus_loss_enabled", "enable"), &RichTextLabel::set_deselect_on_focus_loss_enabled);
ClassDB::bind_method(D_METHOD("is_deselect_on_focus_loss_enabled"), &RichTextLabel::is_deselect_on_focus_loss_enabled);
@ -4576,6 +4628,9 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_effects"), &RichTextLabel::get_effects);
ClassDB::bind_method(D_METHOD("install_effect", "effect"), &RichTextLabel::install_effect);
ClassDB::bind_method(D_METHOD("get_menu"), &RichTextLabel::get_menu);
ClassDB::bind_method(D_METHOD("is_menu_visible"), &RichTextLabel::is_menu_visible);
// Note: set "bbcode_enabled" first, to avoid unnecessary "text" resets.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
@ -4597,6 +4652,9 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters_behavior", PROPERTY_HINT_ENUM, "Characters Before Shaping,Characters After Shaping,Glyphs (Layout Direction),Glyphs (Left-to-Right),Glyphs (Right-to-Left)"), "set_visible_characters_behavior", "get_visible_characters_behavior");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
ADD_GROUP("Locale", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
@ -4776,6 +4834,59 @@ Size2 RichTextLabel::get_minimum_size() const {
return size;
}
// Context menu.
void RichTextLabel::_generate_context_menu() {
if (!menu) {
menu = memnew(PopupMenu);
add_child(menu, false, INTERNAL_MODE_FRONT);
menu->connect("id_pressed", callable_mp(this, &RichTextLabel::_menu_option));
}
// 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);
}
}
Key RichTextLabel::_get_menu_action_accelerator(const String &p_action) {
const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_action);
if (!events) {
return Key::NONE;
}
// Use first event in the list for the accelerator.
const List<Ref<InputEvent>>::Element *first_event = events->front();
if (!first_event) {
return Key::NONE;
}
const Ref<InputEventKey> event = first_event->get();
if (event.is_null()) {
return Key::NONE;
}
// Use physical keycode if non-zero
if (event->get_physical_keycode() != Key::NONE) {
return event->get_physical_keycode_with_modifiers();
} else {
return event->get_keycode_with_modifiers();
}
}
void RichTextLabel::_menu_option(int p_option) {
switch (p_option) {
case MENU_COPY: {
selection_copy();
} break;
case MENU_SELECT_ALL: {
select_all();
} break;
}
}
void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item *it_from, Item *it_to, int start, int end, int fbg_flag) {
Vector2i fbg_index = Vector2i(end, start);
Color last_color = Color(0, 0, 0, 0);

View file

@ -32,6 +32,7 @@
#define RICH_TEXT_LABEL_H
#include "rich_text_effect.h"
#include "scene/gui/popup_menu.h"
#include "scene/gui/scroll_bar.h"
#include "scene/resources/text_paragraph.h"
@ -91,6 +92,11 @@ public:
VC_GLYPHS_RTL,
};
enum MenuItems {
MENU_COPY,
MENU_SELECT_ALL,
};
protected:
void _notification(int p_what);
static void _bind_methods();
@ -420,6 +426,15 @@ private:
Selection selection;
bool deselect_on_focus_loss_enabled = true;
bool context_menu_enabled = false;
bool shortcut_keys_enabled = true;
// Context menu.
PopupMenu *menu = nullptr;
void _generate_context_menu();
Key _get_menu_action_accelerator(const String &p_action);
void _menu_option(int p_option);
int visible_characters = -1;
float percent_visible = 1.0;
VisibleCharactersBehavior visible_chars_behavior = VC_CHARS_BEFORE_SHAPING;
@ -555,6 +570,12 @@ public:
void set_tab_size(int p_spaces);
int get_tab_size() const;
void set_context_menu_enabled(bool p_enabled);
bool is_context_menu_enabled() const;
void set_shortcut_keys_enabled(bool p_enabled);
bool is_shortcut_keys_enabled() const;
void set_fit_content_height(bool p_enabled);
bool is_fit_content_height_enabled() const;
@ -590,6 +611,10 @@ public:
bool is_deselect_on_focus_loss_enabled() const;
void deselect();
// Context menu.
PopupMenu *get_menu() const;
bool is_menu_visible() const;
void parse_bbcode(const String &p_bbcode);
void append_text(const String &p_bbcode);