diff --git a/src/source.cc b/src/source.cc index e59e1d0..fd717a9 100644 --- a/src/source.cc +++ b/src/source.cc @@ -515,6 +515,13 @@ void Source::View::configure() { } void Source::View::setup_tooltip_and_dialog_events() { + type_tooltips.on_motion=[this] { + delayed_tooltips_connection.disconnect(); + }; + diagnostic_tooltips.on_motion=[this] { + delayed_tooltips_connection.disconnect(); + }; + get_buffer()->signal_changed().connect([this] { hide_tooltips(); }); @@ -526,6 +533,8 @@ void Source::View::setup_tooltip_and_dialog_events() { gdouble x=event->x; gdouble y=event->y; delayed_tooltips_connection=Glib::signal_timeout().connect([this, x, y]() { + type_tooltips.hide(); + diagnostic_tooltips.hide(); Tooltips::init(); Gdk::Rectangle rectangle(x, y, 1, 1); if(parsed) { @@ -535,8 +544,10 @@ void Source::View::setup_tooltip_and_dialog_events() { return false; }, 100); } - type_tooltips.hide(); - diagnostic_tooltips.hide(); + auto last_mouse_pos = std::make_pair(on_motion_last_x, on_motion_last_y); + auto mouse_pos = std::make_pair(event->x, event->y); + type_tooltips.hide(last_mouse_pos, mouse_pos); + diagnostic_tooltips.hide(last_mouse_pos, mouse_pos); } on_motion_last_x=event->x; on_motion_last_y=event->y; diff --git a/src/tooltips.cc b/src/tooltips.cc index 954c97e..e416cd7 100644 --- a/src/tooltips.cc +++ b/src/tooltips.cc @@ -35,7 +35,7 @@ void Tooltip::update() { } } -void Tooltip::show(bool disregard_drawn) { +void Tooltip::show(bool disregard_drawn, const std::function &on_motion) { Tooltips::shown_tooltips.emplace(this); if(!window) { @@ -55,6 +55,12 @@ void Tooltip::show(bool disregard_drawn) { window->set_skip_taskbar_hint(true); window->set_default_size(0, 0); + window->signal_motion_notify_event().connect([on_motion](GdkEventMotion *event) { + if(on_motion) + on_motion(); + return false; + }); + window->get_style_context()->add_class("juci_tooltip_window"); auto visual = window->get_screen()->get_rgba_visual(); if(visual) @@ -91,13 +97,13 @@ void Tooltip::show(bool disregard_drawn) { int root_x, root_y; dialog->get_position(root_x, root_y); root_x-=3; // -1xpadding - position.first=root_x; - position.second=root_y-size.second; - if(position.second<0) - position.second=0; + rectangle.set_x(root_x); + rectangle.set_y(root_y-size.second); + if(rectangle.get_y()<0) + rectangle.set_y(0); } } - window->move(position.first, position.second); + window->move(rectangle.get_x(), rectangle.get_y()); }); } @@ -115,7 +121,6 @@ void Tooltip::show(bool disregard_drawn) { if(root_yget_realized()) - window->move(position.first, position.second); + window->move(rectangle.get_x(), rectangle.get_y()); window->show_all(); + shown=true; } -void Tooltip::hide() { +void Tooltip::hide(const std::pair &last_mouse_pos, const std::pair &mouse_pos) { + // Keep tooltip if mouse is moving towards it + // Calculated using dot product between the mouse_pos vector and the corners of the tooltip window + if(text_view && window && shown && last_mouse_pos.first!=-1 && last_mouse_pos.second!=-1 && mouse_pos.first!=-1 && mouse_pos.second!=-1) { + static int root_x, root_y; + text_view->get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(last_mouse_pos.first, last_mouse_pos.second, root_x, root_y); + int diff_x=mouse_pos.first-last_mouse_pos.first; + int diff_y=mouse_pos.second-last_mouse_pos.second; + class Corner { + public: + Corner(int x, int y): x(x-root_x), y(y-root_y) {} + int x, y; + }; + std::vector corners; + corners.emplace_back(rectangle.get_x(), rectangle.get_y()); + corners.emplace_back(rectangle.get_x()+rectangle.get_width(), rectangle.get_y()); + corners.emplace_back(rectangle.get_x(), rectangle.get_y()+rectangle.get_height()); + corners.emplace_back(rectangle.get_x()+rectangle.get_width(), rectangle.get_y()+rectangle.get_height()); + for(auto &corner: corners) { + if(diff_x*corner.x + diff_y*corner.y >= 0) + return; + } + } Tooltips::shown_tooltips.erase(this); if(window) window->hide(); + shown=false; } void Tooltip::wrap_lines() { @@ -196,10 +224,8 @@ void Tooltip::wrap_lines() { void Tooltips::show(const Gdk::Rectangle& rectangle, bool disregard_drawn) { for(auto &tooltip : tooltip_list) { tooltip.update(); - if(rectangle.intersects(tooltip.activation_rectangle)) { - tooltip.show(disregard_drawn); - shown=true; - } + if(rectangle.intersects(tooltip.activation_rectangle)) + tooltip.show(disregard_drawn, on_motion); else tooltip.hide(); } @@ -208,13 +234,11 @@ void Tooltips::show(const Gdk::Rectangle& rectangle, bool disregard_drawn) { void Tooltips::show(bool disregard_drawn) { for(auto &tooltip : tooltip_list) { tooltip.update(); - tooltip.show(disregard_drawn); - shown=true; + tooltip.show(disregard_drawn, on_motion); } } -void Tooltips::hide() { +void Tooltips::hide(const std::pair &last_mouse_pos, const std::pair &mouse_pos) { for(auto &tooltip : tooltip_list) - tooltip.hide(); - shown=false; + tooltip.hide(last_mouse_pos, mouse_pos); } diff --git a/src/tooltips.h b/src/tooltips.h index 07d0563..a032cb2 100644 --- a/src/tooltips.h +++ b/src/tooltips.h @@ -12,8 +12,8 @@ public: ~Tooltip(); void update(); - void show(bool disregard_drawn=false); - void hide(); + void show(bool disregard_drawn=false, const std::function &on_motion=nullptr); + void hide(const std::pair &last_mouse_pos = {-1, -1}, const std::pair &mouse_pos = {-1, -1}); Gdk::Rectangle activation_rectangle; Glib::RefPtr start_mark; @@ -27,17 +27,20 @@ private: std::function()> create_tooltip_buffer; Gtk::TextView *text_view; std::pair size; - std::pair position; + Gdk::Rectangle rectangle; + + bool shown=false; }; class Tooltips { public: static std::set shown_tooltips; + static Gdk::Rectangle drawn_tooltips_rectangle; static void init() {drawn_tooltips_rectangle=Gdk::Rectangle();} + void show(const Gdk::Rectangle& rectangle, bool disregard_drawn=false); void show(bool disregard_drawn=false); - bool shown=false; - void hide(); + void hide(const std::pair &last_mouse_pos = {-1, -1}, const std::pair &mouse_pos = {-1, -1}); void clear() {tooltip_list.clear();}; template @@ -45,7 +48,7 @@ public: tooltip_list.emplace_back(std::forward(params)...); } - static Gdk::Rectangle drawn_tooltips_rectangle; + std::function on_motion; private: std::list tooltip_list; diff --git a/tests/stubs/tooltips.cc b/tests/stubs/tooltips.cc index 228fcce..53da0fc 100644 --- a/tests/stubs/tooltips.cc +++ b/tests/stubs/tooltips.cc @@ -13,4 +13,4 @@ void Tooltips::show(Gdk::Rectangle const&, bool) {} void Tooltips::show(bool) {} -void Tooltips::hide() {} +void Tooltips::hide(const std::pair &, const std::pair &) {}