Fix connecting a signal with a double click is too difficult

This commit is contained in:
Hilderin 2024-08-01 20:03:15 -04:00
parent 3978628c6c
commit f2dfa65b07
7 changed files with 87 additions and 39 deletions

View File

@ -899,9 +899,7 @@ Control *ConnectionsDockTree::make_custom_tooltip(const String &p_text) const {
return nullptr;
}
EditorHelpBit *help_bit = memnew(EditorHelpBit(p_text));
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<ConnectionsDockTree *>(this));
return memnew(Control); // Make the standard tooltip invisible.
return EditorHelpBitTooltip::show_tooltip(p_text, const_cast<ConnectionsDockTree *>(this));
}
struct _ConnectionsDockMethodInfoSort {

View File

@ -116,6 +116,8 @@ const Vector<String> packed_array_types = {
DocTools *EditorHelp::doc = nullptr;
DocTools *EditorHelp::ext_doc = nullptr;
bool EditorHelpBitTooltip::_is_tooltip_visible = false;
static bool _attempt_doc_load(const String &p_class) {
// Docgen always happens in the outer-most class: it also generates docs for inner classes.
String outer_class = p_class.get_slice(".", 0);
@ -3778,6 +3780,14 @@ void EditorHelpBitTooltip::_safe_queue_free() {
void EditorHelpBitTooltip::_target_gui_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouse> mouse_event = p_event;
if (mouse_event.is_valid()) {
// For some unknown reason, we receive mouse motion of zero when the tooltip
// is opened even if the mouse is not moving on Windows now that the toolip
// FLAG_POPUP is false.
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && mm->get_relative().is_zero_approx()) {
return;
}
_start_timer();
}
}
@ -3790,6 +3800,9 @@ void EditorHelpBitTooltip::_notification(int p_what) {
case NOTIFICATION_WM_MOUSE_EXIT:
_start_timer();
break;
case NOTIFICATION_EXIT_TREE:
_is_tooltip_visible = false;
break;
}
}
@ -3811,14 +3824,36 @@ void EditorHelpBitTooltip::_input_from_window(const Ref<InputEvent> &p_event) {
}
}
void EditorHelpBitTooltip::show_tooltip(EditorHelpBit *p_help_bit, Control *p_target) {
ERR_FAIL_NULL(p_help_bit);
Control *EditorHelpBitTooltip::show_tooltip(const String &p_symbol, Control *p_target, const String &p_description) {
// 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) {
return _make_invisible_control();
}
EditorHelpBit *help_bit = memnew(EditorHelpBit(p_symbol));
if (!p_description.is_empty()) {
help_bit->set_description(p_description);
}
EditorHelpBitTooltip *tooltip = memnew(EditorHelpBitTooltip(p_target));
p_help_bit->connect("request_hide", callable_mp(tooltip, &EditorHelpBitTooltip::_safe_queue_free));
tooltip->add_child(p_help_bit);
help_bit->connect("request_hide", callable_mp(tooltip, &EditorHelpBitTooltip::_safe_queue_free));
tooltip->add_child(help_bit);
p_target->get_viewport()->add_child(tooltip);
p_help_bit->update_content_height();
help_bit->update_content_height();
// When FLAG_POPUP is false, it prevents the editor from losing focus when displaying the tooltip.
// This way, clicks and double-clicks are still available outside the tooltip.
tooltip->set_flag(Window::FLAG_POPUP, false);
tooltip->popup_under_cursor();
_is_tooltip_visible = true;
return _make_invisible_control();
}
Control *EditorHelpBitTooltip::_make_invisible_control() {
Control *control = memnew(Control);
control->set_visible(false);
return control;
}
// Copy-paste from `Viewport::_gui_show_tooltip()`.

View File

@ -325,6 +325,7 @@ public:
class EditorHelpBitTooltip : public PopupPanel {
GDCLASS(EditorHelpBitTooltip, PopupPanel);
static bool _is_tooltip_visible;
Timer *timer = nullptr;
int _pushing_input = 0;
bool _need_free = false;
@ -332,13 +333,14 @@ class EditorHelpBitTooltip : public PopupPanel {
void _start_timer();
void _safe_queue_free();
void _target_gui_input(const Ref<InputEvent> &p_event);
static Control *_make_invisible_control();
protected:
void _notification(int p_what);
virtual void _input_from_window(const Ref<InputEvent> &p_event) override;
public:
static void show_tooltip(EditorHelpBit *p_help_bit, Control *p_target);
static Control *show_tooltip(const String &p_symbol, Control *p_target, const String &p_description = String());
void popup_under_cursor();

View File

@ -991,30 +991,30 @@ Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
}
if (has_doc_tooltip || !custom_warning.is_empty()) {
EditorHelpBit *help_bit = memnew(EditorHelpBit);
String symbol;
String description;
if (has_doc_tooltip) {
help_bit->parse_symbol(p_text);
symbol = p_text;
const EditorInspector *inspector = get_parent_inspector();
if (inspector) {
const String custom_description = inspector->get_custom_property_description(p_text);
if (!custom_description.is_empty()) {
help_bit->set_description(custom_description);
description = custom_description;
}
}
}
if (!custom_warning.is_empty()) {
String description = "[b][color=" + get_theme_color(SNAME("warning_color")).to_html(false) + "]" + custom_warning + "[/color][/b]";
if (!help_bit->get_description().is_empty()) {
description += "\n" + help_bit->get_description();
const String custom_warning_description = "[b][color=" + get_theme_color(SNAME("warning_color")).to_html(false) + "]" + custom_warning + "[/color][/b]";
if (description.is_empty()) {
description = custom_warning_description;
} else {
description = custom_warning_description + "\n" + description;
}
help_bit->set_description(description);
}
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<EditorProperty *>(this));
return memnew(Control); // Make the standard tooltip invisible.
return EditorHelpBitTooltip::show_tooltip(symbol, const_cast<EditorProperty *>(this), description);
}
return nullptr;
@ -1270,9 +1270,7 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
return nullptr;
}
EditorHelpBit *help_bit = memnew(EditorHelpBit(p_text));
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<EditorInspectorCategory *>(this));
return memnew(Control); // Make the standard tooltip invisible.
return EditorHelpBitTooltip::show_tooltip(p_text, const_cast<EditorInspectorCategory *>(this));
}
Size2 EditorInspectorCategory::get_minimum_size() const {

View File

@ -2267,9 +2267,7 @@ ThemeTypeDialog::ThemeTypeDialog() {
///////////////////////
Control *ThemeItemLabel::make_custom_tooltip(const String &p_text) const {
EditorHelpBit *help_bit = memnew(EditorHelpBit(p_text));
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<ThemeItemLabel *>(this));
return memnew(Control); // Make the standard tooltip invisible.
return EditorHelpBitTooltip::show_tooltip(p_text, const_cast<ThemeItemLabel *>(this));
}
VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {

View File

@ -4840,14 +4840,7 @@ void DisplayServerX11::process_events() {
WindowID window_id_other = INVALID_WINDOW_ID;
Window wd_other_x11_window;
if (wd.focused) {
// Handle cases where an unfocused popup is open that needs to receive button-up events.
WindowID popup_id = _get_focused_window_or_popup();
if (popup_id != INVALID_WINDOW_ID && popup_id != window_id) {
window_id_other = popup_id;
wd_other_x11_window = windows[popup_id].x11_window;
}
} else {
if (!wd.focused) {
// Propagate the event to the focused window,
// because it's received only on the topmost window.
// Note: This is needed for drag & drop to work between windows,
@ -4970,6 +4963,23 @@ void DisplayServerX11::process_events() {
pos = Point2i(windows[focused_window_id].size.width / 2, windows[focused_window_id].size.height / 2);
}
BitField<MouseButtonMask> last_button_state = 0;
if (event.xmotion.state & Button1Mask) {
last_button_state.set_flag(MouseButtonMask::LEFT);
}
if (event.xmotion.state & Button2Mask) {
last_button_state.set_flag(MouseButtonMask::MIDDLE);
}
if (event.xmotion.state & Button3Mask) {
last_button_state.set_flag(MouseButtonMask::RIGHT);
}
if (event.xmotion.state & Button4Mask) {
last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
}
if (event.xmotion.state & Button5Mask) {
last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
}
Ref<InputEventMouseMotion> mm;
mm.instantiate();
@ -4977,13 +4987,13 @@ void DisplayServerX11::process_events() {
if (xi.pressure_supported) {
mm->set_pressure(xi.pressure);
} else {
mm->set_pressure(bool(mouse_get_button_state().has_flag(MouseButtonMask::LEFT)) ? 1.0f : 0.0f);
mm->set_pressure(bool(last_button_state.has_flag(MouseButtonMask::LEFT)) ? 1.0f : 0.0f);
}
mm->set_tilt(xi.tilt);
mm->set_pen_inverted(xi.pen_inverted);
_get_key_modifier_state(event.xmotion.state, mm);
mm->set_button_mask(mouse_get_button_state());
mm->set_button_mask(last_button_state);
mm->set_position(pos);
mm->set_global_position(pos);
mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());

View File

@ -1457,6 +1457,17 @@ void Viewport::_gui_show_tooltip() {
return;
}
// Controls can implement `make_custom_tooltip` to provide their own tooltip.
// This should be a Control node which will be added as child to a TooltipPanel.
Control *base_tooltip = tooltip_owner->make_custom_tooltip(gui.tooltip_text);
// When the custom control is not visible, don't show any tooltip.
// This way, the custom tooltip from ConnectionsDockTree can create
// its own tooltip without conflicting with the default one, even an empty tooltip.
if (base_tooltip && !base_tooltip->is_visible()) {
return;
}
// Popup window which houses the tooltip content.
PopupPanel *panel = memnew(PopupPanel);
panel->set_theme_type_variation(SNAME("TooltipPanel"));
@ -1464,10 +1475,6 @@ void Viewport::_gui_show_tooltip() {
// Ensure no opaque background behind the panel as its StyleBox can be partially transparent (e.g. corners).
panel->set_transparent_background(true);
// Controls can implement `make_custom_tooltip` to provide their own tooltip.
// This should be a Control node which will be added as child to a TooltipPanel.
Control *base_tooltip = tooltip_owner->make_custom_tooltip(gui.tooltip_text);
// If no custom tooltip is given, use a default implementation.
if (!base_tooltip) {
gui.tooltip_label = memnew(Label);