From dafbe8c0af90db9f79931ef1bbec9ceab4c40503 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 19 Jan 2002 21:49:39 +0000 Subject: [PATCH] added the possibility to hide the tip window automatically when the mouse leave the specified rectangle; fixed a few bugs with the window not disappearing automatically git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13664 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/tipwin.tex | 54 ++++++++++--- include/wx/tipwin.h | 57 ++++++++++--- src/generic/tipwin.cpp | 167 +++++++++++++++++++++++++++------------ 3 files changed, 206 insertions(+), 72 deletions(-) diff --git a/docs/latex/wx/tipwin.tex b/docs/latex/wx/tipwin.tex index 9983b59c77..0999633f10 100644 --- a/docs/latex/wx/tipwin.tex +++ b/docs/latex/wx/tipwin.tex @@ -1,11 +1,12 @@ \section{\class{wxTipWindow}}\label{wxtipwindow} -Shows simple text in a popup tip window on creation. This is used by \helpref{wxSimpleHelpProvider}{wxsimplehelpprovider} to -show popup help. The window automatically destroys itself when the user clicks on it or it loses -the focus. +Shows simple text in a popup tip window on creation. This is used by +\helpref{wxSimpleHelpProvider}{wxsimplehelpprovider} to show popup help. The +window automatically destroys itself when the user clicks on it or it loses the +focus. -You should not normally need to use it explicitly in your application since a help provider class -will create it when required. +You may also use this class to emulate the tooltips when you need finer +control over them than what the standard tooltips provide. \wxheading{Derived from} @@ -23,13 +24,48 @@ wxPopupWindow\\ \membersection{wxTipWindow::wxTipWindow}\label{wxtipwindowwxtipwindow} -\func{}{wxTipWindow}{\param{wxWindow* }{parent}, \param{const wxString\& }{text}, \param{wxCoord }{maxLength = 100}} +\func{}{wxTipWindow}{\param{wxWindow* }{parent}, \param{const wxString\& }{text}, \param{wxCoord }{maxLength = 100}, \param{wxTipWindow** }{windowPtr}} Constructor. The tip is shown immediately the window is constructed. -\membersection{wxTipWindow::Adjust}\label{wxtipwindowadjust} +\wxheading{Parameters} -\func{void}{Adjust}{\param{const wxString\& }{text}, \param{wxCoord }{maxLength}} +\docparam{parent}{The parent window, must be non {\tt NULL}} -Calculates the client rect we need to display the text. +\docparam{text}{The text to show, may contain the new line characters} + +\docparam{windowPtr}{Simply passed to +\helpref{SetTipWindowPtr}{wxtipwindowsettipwindowptr} below, please see its +documentation for the description of this parameter} + +\docparam{rectBounds}{If non {\tt NULL}, passed to +\helpref{SetBoundingRect}{wxtipwindowsetboundingrect} below, please see its +documentation for the description of this parameter} + + +\membersection{wxTipWindow::SetTipWindowPtr}\label{wxtipwindowsettipwindowptr} + +\func{void}{SetTipWindowPtr}{\param{wxTipWindow** }{windowPtr}} + +When the tip window closes itself (which may happen at any moment and +unexpectedly to the caller) it may {\tt NULL} out the pointer pointed to by +{\it windowPtr}. This is helpful to avoid dereferencing the tip window which +had been already closed and deleted. + + +\membersection{wxTipWindow::SetBoundingRect}{wxtipwindowsetboundingrect} + +\func{void}{SetBoundingRect}{\param{const wxRect\& }{rectBound}} + +By default, the tip window disappears when the user clicks the mouse or presses +a keyboard key or if it loses focus in any other way - for example because the +user switched to another application window. + +Additionally, if a non empty {\it rectBound} is provided, the tip window will +also automatically close if the mouse leaves this area. This is useful to +dismiss the tip mouse when the mouse leaves the object it is associated with. + +\wxheading{Parameters} + +\docparam{rectBound}{The bounding rectangle for the mouse in the screen coordinates} diff --git a/include/wx/tipwin.h b/include/wx/tipwin.h index 3a82a5c064..ceab97f7fe 100644 --- a/include/wx/tipwin.h +++ b/include/wx/tipwin.h @@ -20,49 +20,80 @@ #if wxUSE_TIPWINDOW #if wxUSE_POPUPWIN -#include "wx/popupwin.h" + #include "wx/popupwin.h" + + #define wxTipWindowBase wxPopupTransientWindow #else -#include "wx/frame.h" + #include "wx/frame.h" + + #define wxTipWindowBase wxFrame #endif +class WXDLLEXPORT wxTipWindowView; + // ---------------------------------------------------------------------------- // wxTipWindow // ---------------------------------------------------------------------------- -#if wxUSE_POPUPWIN -class WXDLLEXPORT wxTipWindow : public wxPopupTransientWindow -#else -class WXDLLEXPORT wxTipWindow : public wxFrame -#endif +class WXDLLEXPORT wxTipWindow : public wxTipWindowBase { - friend class wxTipWindowView; public: - // Supply windowPtr for it to null the given address - // when the window has closed. + // the mandatory ctor parameters are: the parent window and the text to + // show + // + // optionally you may also specify the length at which the lines are going + // to be broken in rows (100 pixels by default) + // + // windowPtr and rectBound are just passed to SetTipWindowPtr() and + // SetBoundingRect() - see below wxTipWindow(wxWindow *parent, const wxString& text, - wxCoord maxLength = 100, wxTipWindow** windowPtr = NULL); - ~wxTipWindow(); + wxCoord maxLength = 100, + wxTipWindow** windowPtr = NULL, + wxRect *rectBound = NULL); + virtual ~wxTipWindow(); + + // If windowPtr is not NULL the given address will be NULLed when the + // window has closed void SetTipWindowPtr(wxTipWindow** windowPtr) { m_windowPtr = windowPtr; } + // If rectBound is not NULL, the window will disappear automatically when + // the mouse leave the specified rect: note that rectBound should be in the + // screen coordinates! + void SetBoundingRect(const wxRect& rectBound); + + // Hide and destroy the window void Close(); protected: + // called by wxTipWindowView only + bool CheckMouseInBounds(const wxPoint& pos); + // event handlers void OnMouseClick(wxMouseEvent& event); + #if !wxUSE_POPUPWIN void OnActivate(wxActivateEvent& event); void OnKillFocus(wxFocusEvent& event); -#endif +#else // wxUSE_POPUPWIN + virtual void OnDismiss(); +#endif // wxUSE_POPUPWIN/!wxUSE_POPUPWIN private: wxArrayString m_textLines; wxCoord m_heightLine; + + wxTipWindowView *m_view; + wxTipWindow** m_windowPtr; + wxRect m_rectBound; DECLARE_EVENT_TABLE() + + friend class wxTipWindowView; }; #endif // wxUSE_TIPWINDOW + #endif // _WX_TIPWIN_H_ diff --git a/src/generic/tipwin.cpp b/src/generic/tipwin.cpp index 01c0e5151e..30d3b8cda9 100644 --- a/src/generic/tipwin.cpp +++ b/src/generic/tipwin.cpp @@ -46,31 +46,12 @@ static const wxCoord TEXT_MARGIN_X = 3; static const wxCoord TEXT_MARGIN_Y = 3; -// ============================================================================ -// implementation -// ============================================================================ - // ---------------------------------------------------------------------------- -// event tables +// wxTipWindowView // ---------------------------------------------------------------------------- -#if wxUSE_POPUPWIN -BEGIN_EVENT_TABLE(wxTipWindow, wxPopupTransientWindow) -#else -BEGIN_EVENT_TABLE(wxTipWindow, wxFrame) -#endif - EVT_LEFT_DOWN(wxTipWindow::OnMouseClick) - EVT_RIGHT_DOWN(wxTipWindow::OnMouseClick) - EVT_MIDDLE_DOWN(wxTipWindow::OnMouseClick) -#if !wxUSE_POPUPWIN - EVT_KILL_FOCUS(wxTipWindow::OnKillFocus) - EVT_ACTIVATE(wxTipWindow::OnActivate) -#endif -END_EVENT_TABLE() - - // Viewer window to put in the frame -class wxTipWindowView: public wxWindow +class WXDLLEXPORT wxTipWindowView : public wxWindow { public: wxTipWindowView(wxWindow *parent); @@ -78,27 +59,56 @@ public: // event handlers void OnPaint(wxPaintEvent& event); void OnMouseClick(wxMouseEvent& event); + void OnMouseMove(wxMouseEvent& event); + #if !wxUSE_POPUPWIN void OnKillFocus(wxFocusEvent& event); -#endif +#endif // wxUSE_POPUPWIN + // calculate the client rect we need to display the text void Adjust(const wxString& text, wxCoord maxLength); private: - long m_creationTime; wxTipWindow* m_parent; - DECLARE_EVENT_TABLE() +#if !wxUSE_POPUPWIN + long m_creationTime; +#endif // !wxUSE_POPUPWIN + + DECLARE_EVENT_TABLE() }; +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTipWindow, wxTipWindowBase) + EVT_LEFT_DOWN(wxTipWindow::OnMouseClick) + EVT_RIGHT_DOWN(wxTipWindow::OnMouseClick) + EVT_MIDDLE_DOWN(wxTipWindow::OnMouseClick) + +#if !wxUSE_POPUPWIN + EVT_KILL_FOCUS(wxTipWindow::OnKillFocus) + EVT_ACTIVATE(wxTipWindow::OnActivate) +#endif // !wxUSE_POPUPWIN +END_EVENT_TABLE() + BEGIN_EVENT_TABLE(wxTipWindowView, wxWindow) EVT_PAINT(wxTipWindowView::OnPaint) + EVT_LEFT_DOWN(wxTipWindowView::OnMouseClick) EVT_RIGHT_DOWN(wxTipWindowView::OnMouseClick) EVT_MIDDLE_DOWN(wxTipWindowView::OnMouseClick) + + EVT_MOTION(wxTipWindowView::OnMouseMove) + #if !wxUSE_POPUPWIN EVT_KILL_FOCUS(wxTipWindowView::OnKillFocus) -#endif +#endif // !wxUSE_POPUPWIN END_EVENT_TABLE() // ---------------------------------------------------------------------------- @@ -107,7 +117,9 @@ END_EVENT_TABLE() wxTipWindow::wxTipWindow(wxWindow *parent, const wxString& text, - wxCoord maxLength, wxTipWindow** windowPtr) + wxCoord maxLength, + wxTipWindow** windowPtr, + wxRect *rectBounds) #if wxUSE_POPUPWIN : wxPopupTransientWindow(parent) #else @@ -116,36 +128,50 @@ wxTipWindow::wxTipWindow(wxWindow *parent, wxNO_BORDER | wxFRAME_NO_TASKBAR ) #endif { - m_windowPtr = windowPtr; + SetTipWindowPtr(windowPtr); + if ( rectBounds ) + { + SetBoundingRect(*rectBounds); + } // set colours - SetForegroundColour(*wxBLACK); - + // + // VZ: why don't we use wxSystemSettings for !MSW? (FIXME) #ifdef __WXMSW__ - wxColour bkCol(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); + SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); #else - wxColour bkCol(wxColour(255, 255, 225)); + SetForegroundColour(*wxBLACK); + SetBackgroundColour(*wxWHITE); #endif - SetBackgroundColour(bkCol); // set size, position and show it - wxTipWindowView* tipWindowView = new wxTipWindowView(this); - tipWindowView->Adjust(text, maxLength); - tipWindowView->SetFocus(); + m_view = new wxTipWindowView(this); + m_view->Adjust(text, maxLength); + m_view->SetFocus(); + int x, y; wxGetMousePosition(&x, &y); + + // we want to show the tip below the mouse, not over it + // + // NB: the reason we use "/ 2" here is that we don't know where the current + // cursors hot spot is... it would be nice if we could find this out + // though + y += wxSystemSettings::GetMetric(wxSYS_CURSOR_Y) / 2; + #if wxUSE_POPUPWIN - Position(wxPoint(x, y+10), wxSize(0,0)); - Popup(tipWindowView); + Position(wxPoint(x, y), wxSize(0, 0)); + Popup(m_view); #else - Move(x, y + 10); + Move(x, y); Show(TRUE); #endif } wxTipWindow::~wxTipWindow() { - if (m_windowPtr) + if ( m_windowPtr ) { *m_windowPtr = NULL; } @@ -156,7 +182,15 @@ void wxTipWindow::OnMouseClick(wxMouseEvent& WXUNUSED(event)) Close(); } -#if !wxUSE_POPUPWIN +#if wxUSE_POPUPWIN + +void wxTipWindow::OnDismiss() +{ + Close(); +} + +#else // !wxUSE_POPUPWIN + void wxTipWindow::OnActivate(wxActivateEvent& event) { if (!event.GetActive()) @@ -172,11 +206,22 @@ void wxTipWindow::OnKillFocus(wxFocusEvent& WXUNUSED(event)) Close(); #endif } -#endif +#endif // wxUSE_POPUPWIN // !wxUSE_POPUPWIN + +void wxTipWindow::SetBoundingRect(const wxRect& rectBound) +{ + m_rectBound = rectBound; +} void wxTipWindow::Close() { + if ( m_windowPtr ) + { + *m_windowPtr = NULL; + m_windowPtr = NULL; + } + #if wxUSE_POPUPWIN Show(FALSE); Destroy(); @@ -190,19 +235,25 @@ void wxTipWindow::Close() // ---------------------------------------------------------------------------- wxTipWindowView::wxTipWindowView(wxWindow *parent) - : wxWindow(parent, -1, - wxDefaultPosition, wxDefaultSize, - wxNO_BORDER) + : wxWindow(parent, -1, + wxDefaultPosition, wxDefaultSize, + wxNO_BORDER) { // set colours - SetForegroundColour(*wxBLACK); + // + // VZ: why don't we use wxSystemSettings for !MSW? (FIXME) #ifdef __WXMSW__ - wxColour bkCol(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); + SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); #else - wxColour bkCol(wxColour(255, 255, 225)); + SetForegroundColour(*wxBLACK); + SetBackgroundColour(*wxWHITE); #endif - SetBackgroundColour(bkCol); + +#if !wxUSE_POPUPWIN m_creationTime = wxGetLocalTime(); +#endif // !wxUSE_POPUPWIN + m_parent = (wxTipWindow*)parent; } @@ -306,6 +357,22 @@ void wxTipWindowView::OnMouseClick(wxMouseEvent& WXUNUSED(event)) m_parent->Close(); } +void wxTipWindowView::OnMouseMove(wxMouseEvent& event) +{ + const wxRect& rectBound = m_parent->m_rectBound; + + if ( rectBound.width && + !rectBound.Inside(ClientToScreen(event.GetPosition())) ) + { + // mouse left the bounding rect, disappear + m_parent->Close(); + } + else + { + event.Skip(); + } +} + #if !wxUSE_POPUPWIN void wxTipWindowView::OnKillFocus(wxFocusEvent& WXUNUSED(event)) { @@ -313,6 +380,6 @@ void wxTipWindowView::OnKillFocus(wxFocusEvent& WXUNUSED(event)) if (wxGetLocalTime() > m_creationTime + 1) m_parent->Close(); } -#endif +#endif // !wxUSE_POPUPWIN -#endif +#endif // wxUSE_TIPWINDOW -- 2.45.2