note description: "[ A window to display tooltip with a timeout. Detective of the mouse position to decide the hiding timing. ]" author: "" date: "$Date$" revision: "$Revision$" class ES_SMART_TOOLTIP_WINDOW inherit ES_POPUP_WINDOW rename make as make_popup_button_window redefine on_before_show, active_border_color, border_color, is_pointer_sensitive, on_pointer_enter, on_pointer_leave, on_cancel_popup, hide, ensure_popup_window_visible_on_screen end create make feature {NONE} -- Initialization make -- Init with nothing do make_popup_button_window (False) -- Default timeout hide_timeout := 8_000 end build_window_interface (a_container: EV_VERTICAL_BOX) -- Builds the popup window's user interface. local l_box: EV_HORIZONTAL_BOX do widget_container := a_container create l_box -- Padding l_box.extend (create {EV_CELL}) a_container.extend (l_box) a_container.disable_item_expand (l_box) -- Propagate background color to set widget structure. propagate_colors (a_container, Void, background_color, Void) ensure then widget_container_set: widget_container = a_container end feature {NONE} -- Access background_color: EV_COLOR -- Pop up window background color, as well as the token background color do Result := normal_text_token.background_color ensure result_attached: Result /= Void end border_color: EV_COLOR -- once create Result.make_with_8_bit_rgb (58, 123, 252) end active_border_color: EV_COLOR -- once create Result.make_with_8_bit_rgb (58, 123, 252) end normal_text_token: EDITOR_TOKEN_TEXT -- Token used for getting foreground and background colors. once create Result.make ("") end feature -- Access popup_widget: EV_WIDGET -- Widget displayed when the popup button is pressed do Result := internal_popup_widget ensure not_result_is_destroyed: Result /= Void implies not Result.is_destroyed end feature -- Element change reset_pop_widget -- Reset `popup_widget`. do internal_popup_widget := Void end set_popup_widget (a_widget: like popup_widget) -- Assign popup widget to be displayed when the popup button is select -- Note: Already displayed widgets will have the UI replaced and reshown. -- -- `a_widget': The widget to display in the popup window, when the popup up widget is requested to be shown. -- Use Void to remove the widget. require a_widget_not_void: a_widget /= Void do internal_popup_widget := a_widget on_popup_widget_show_requested -- Restart the timer if is_shown and popup_widget_activate_timer /= Void then setup_hide_timer end end set_hide_timeout (a_timeout: INTEGER) -- Set time to hide the window. require a_timeout_not_negative: a_timeout >= 0 do hide_timeout := a_timeout ensure hide_timeout_set: hide_timeout = a_timeout end feature -- Status report is_recycled_on_close: BOOLEAN -- do Result := False end is_pointer_sensitive: BOOLEAN -- do Result := True end hide -- Hides the popup window. do Precursor destroy_hide_timer end feature {NONE} -- Action handlers on_popup_widget_show_requested -- Called when a show of the popup widget is requested. local l_widget: like popup_widget do l_widget := popup_widget if l_widget.has_parent then l_widget.show else -- If `widget_container' has no widget, we extend it with -- `l_widget' (the `popup_widget'). If it already has one -- and it is already the same, we do nothing to avoid flickering, -- otherwise we remove and add the widget (which might cause some -- flickering). if not widget_container.is_empty then if widget_container.first /= l_widget then widget_container.wipe_out widget_container.extend (l_widget) end else widget_container.extend (l_widget) end if not widget_container.is_displayed then widget_container.show end end end on_before_show -- do Precursor {ES_POPUP_WINDOW} setup_hide_timer end on_pointer_leave -- Called when the mouse cursor leave the pop up window. do Precursor {ES_POPUP_WINDOW} setup_hide_timer end on_pointer_enter -- Called when the mouse cursor enter the pop up window. do Precursor {ES_POPUP_WINDOW} destroy_hide_timer end on_cancel_popup -- do end feature {NONE} -- User interface elements widget_container: EV_VERTICAL_BOX -- The container to extend a popup widget with. hide_timeout: INTEGER -- Timeout to hide the tooltip feature {NONE} -- Basic operations setup_hide_timer -- Set up the timer to hide do destroy_hide_timer create popup_widget_activate_timer popup_widget_activate_timer.set_interval (hide_timeout) popup_widget_activate_timer.actions.extend (agent hide_timer_action) end hide_timer_action -- On hide timer called local l_screen: EV_SCREEN l_p: EV_COORDINATE l_w: like popup_window do if is_interface_usable and then is_shown then create l_screen l_p := l_screen.pointer_position l_w := popup_window if l_p.x >= l_w.screen_x and then l_p.x <= l_w.screen_x + l_w.width and then l_p.y >= l_w.screen_y and then l_p.y <= l_w.screen_y + l_w.height then else -- Hide the window on timeout if mouse cursor is not in the window. popup_window.hide destroy_hide_timer end else destroy_hide_timer end end destroy_hide_timer -- Destroy the hide timer do if popup_widget_activate_timer /= Void and then not popup_widget_activate_timer.is_destroyed then popup_widget_activate_timer.destroy popup_widget_activate_timer := Void end end feature {NONE} -- Implementation ensure_popup_window_visible_on_screen -- Ensures the popup window is visible on screen, given the bounding edges do -- Let the window be smallest possible and grow to fit new widget's size. popup_window.resize_actions.block popup_window.set_size (popup_window.minimum_width, popup_window.minimum_height) popup_window.resize_actions.resume Precursor end popup_widget_activate_timer: EV_TIMEOUT -- Timer to hide the window internal_popup_widget: like popup_widget -- Cached version of `popup_widget' ;note copyright: "Copyright (c) 1984-2019, Eiffel Software" license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)" licensing_options: "http://www.eiffel.com/licensing" copying: "[ This file is part of Eiffel Software's Eiffel Development Environment. Eiffel Software's Eiffel Development Environment is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2 of the License (available at the URL listed under "license" above). Eiffel Software's Eiffel Development Environment is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Eiffel Software's Eiffel Development Environment; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ]" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end