Skip to content

Commit

Permalink
Fix connecting a signal with a double click is too difficult
Browse files Browse the repository at this point in the history
  • Loading branch information
Hilderin committed Aug 23, 2024
1 parent 3978628 commit f2dfa65
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 39 deletions.
4 changes: 1 addition & 3 deletions editor/connections_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
45 changes: 40 additions & 5 deletions editor/editor_help.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}
}
Expand All @@ -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;
}
}

Expand All @@ -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()`.
Expand Down
4 changes: 3 additions & 1 deletion editor/editor_help.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,20 +325,22 @@ class EditorHelpBit : public VBoxContainer {
class EditorHelpBitTooltip : public PopupPanel {
GDCLASS(EditorHelpBitTooltip, PopupPanel);

static bool _is_tooltip_visible;
Timer *timer = nullptr;
int _pushing_input = 0;
bool _need_free = false;

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();

Expand Down
24 changes: 11 additions & 13 deletions editor/editor_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 1 addition & 3 deletions editor/plugins/theme_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
30 changes: 20 additions & 10 deletions platform/linuxbsd/x11/display_server_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -4970,20 +4963,37 @@ 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();

mm->set_window_id(window_id);
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());
Expand Down
15 changes: 11 additions & 4 deletions scene/main/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1457,17 +1457,24 @@ 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"));

// 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);
Expand Down

0 comments on commit f2dfa65

Please sign in to comment.