From: Vadim Zeitlin Date: Fri, 23 Jan 2009 13:26:20 +0000 (+0000) Subject: added (wxMSW-only) wxToolTip::SetMaxWidth() and improve its default behaviour (#2817) X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/be8b43858c480325553a66a43c9fcd92d036b885?ds=inline added (wxMSW-only) wxToolTip::SetMaxWidth() and improve its default behaviour (#2817) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58329 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/msw/tooltip.h b/include/wx/msw/tooltip.h index 0e7bafe04a..e8a0867981 100644 --- a/include/wx/msw/tooltip.h +++ b/include/wx/msw/tooltip.h @@ -37,10 +37,14 @@ public: static void Enable(bool flag); // set the delay after which the tooltip appears static void SetDelay(long milliseconds); - // set the delay after which the tooltip disappears or how long the tooltip remains visible + // set the delay after which the tooltip disappears or how long the + // tooltip remains visible static void SetAutoPop(long milliseconds); // set the delay between subsequent tooltips to appear static void SetReshow(long milliseconds); + // set maximum width for the new tooltips: -1 disables wrapping + // entirely, 0 restores the default behaviour + static void SetMaxWidth(int width); // implementation only from now on // ------------------------------- @@ -62,6 +66,9 @@ private: // create the tooltip ctrl if it doesn't exist yet and return its HWND static WXHWND GetToolTipCtrl(); + // new tooltip maximum width, defaults to min(display width, 400) + static int ms_maxWidth; + // remove this tooltip from the tooltip control void Remove(); diff --git a/interface/wx/tooltip.h b/interface/wx/tooltip.h index 4dc2a448fc..cb4abd73ae 100644 --- a/interface/wx/tooltip.h +++ b/interface/wx/tooltip.h @@ -59,6 +59,21 @@ public: */ static void SetDelay(long msecs); + /** + Set tooltip maximal width in pixels. + + By default, tooltips are wrapped at a suitably chosen width. You can + pass -1 as @a width to disable wrapping them completely, 0 to restore + the default behaviour or an arbitrary positive value to wrap them at + the given width. + + Notice that this function does not change the width of the tooltips + created before calling it. + + @note Currently this function is wxMSW-only. + */ + static void SetMaxWidth(int width) { ms_maxWidth = width; } + /** Set the delay between subsequent tooltips to appear. diff --git a/samples/controls/controls.cpp b/samples/controls/controls.cpp index ab41f78dc8..9b08f4cb6e 100644 --- a/samples/controls/controls.cpp +++ b/samples/controls/controls.cpp @@ -28,7 +28,10 @@ #if wxUSE_TOOLTIPS #include "wx/tooltip.h" -#endif +#ifdef __WXMSW__ + #include "wx/numdlg.h" +#endif // __WXMSW__ +#endif // wxUSE_TOOLTIPS #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__) #define USE_XPM @@ -75,6 +78,10 @@ public: MyPanel(wxFrame *frame, int x, int y, int w, int h); virtual ~MyPanel(); +#if wxUSE_TOOLTIPS + void SetAllToolTips(); +#endif // wxUSE_TOOLTIPS + void OnIdle( wxIdleEvent &event ); void OnListBox( wxCommandEvent &event ); void OnListBoxDoubleClick( wxCommandEvent &event ); @@ -187,6 +194,9 @@ public: #if wxUSE_TOOLTIPS void OnSetTooltipDelay(wxCommandEvent& event); void OnToggleTooltips(wxCommandEvent& event); +#ifdef __WXMSW__ + void OnSetMaxTooltipWidth(wxCommandEvent& event); +#endif // __WXMSW__ #endif // wxUSE_TOOLTIPS void OnEnableAll(wxCommandEvent& event); @@ -380,6 +390,7 @@ enum // tooltip menu CONTROLS_SET_TOOLTIP_DELAY = 200, CONTROLS_ENABLE_TOOLTIPS, + CONTROLS_SET_TOOLTIPS_MAX_WIDTH, // panel menu CONTROLS_ENABLE_ALL, @@ -455,7 +466,7 @@ const int ID_RADIOBOX_SEL_NUM = 161; const int ID_RADIOBOX_SEL_STR = 162; const int ID_RADIOBOX_FONT = 163; const int ID_RADIOBOX_ENABLE = 164; - +const int ID_RADIOBOX2 = 165; const int ID_RADIOBUTTON_1 = 166; const int ID_RADIOBUTTON_2 = 167; @@ -530,6 +541,7 @@ EVT_BUTTON (ID_COMBO_FONT, MyPanel::OnComboButtons) EVT_BUTTON (ID_COMBO_SET_TEXT, MyPanel::OnComboButtons) EVT_CHECKBOX (ID_COMBO_ENABLE, MyPanel::OnComboButtons) EVT_RADIOBOX (ID_RADIOBOX, MyPanel::OnRadio) +EVT_RADIOBOX (ID_RADIOBOX2, MyPanel::OnRadio) EVT_BUTTON (ID_RADIOBOX_SEL_NUM, MyPanel::OnRadioButtons) EVT_BUTTON (ID_RADIOBOX_SEL_STR, MyPanel::OnRadioButtons) EVT_BUTTON (ID_RADIOBOX_FONT, MyPanel::OnRadioButtons) @@ -745,9 +757,6 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) SetListboxClientData(wxT("listbox"), m_listboxSorted); m_listbox->SetCursor(*wxCROSS_CURSOR); -#if wxUSE_TOOLTIPS - m_listbox->SetToolTip( _T("This is a list box") ); -#endif // wxUSE_TOOLTIPS m_lbSelectNum = new wxButton( panel, ID_LISTBOX_SEL_NUM, _T("Select #&2"), wxPoint(180,30), wxSize(140,30) ); m_lbSelectThis = new wxButton( panel, ID_LISTBOX_SEL_STR, _T("&Select 'This'"), wxPoint(340,30), wxSize(140,30) ); @@ -758,16 +767,9 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) button->SetDefault(); -#if wxUSE_TOOLTIPS - button->SetToolTip( _T("Press here to set italic font") ); -#endif // wxUSE_TOOLTIPS - m_checkbox = new wxCheckBox( panel, ID_LISTBOX_ENABLE, _T("&Disable"), wxPoint(20,170) ); m_checkbox->SetValue(false); button->MoveAfterInTabOrder(m_checkbox); -#if wxUSE_TOOLTIPS - m_checkbox->SetToolTip( _T("Click here to disable the listbox") ); -#endif // wxUSE_TOOLTIPS (void)new wxCheckBox( panel, ID_CHANGE_COLOUR, _T("&Toggle colour"), wxPoint(110,170) ); panel->SetCursor(wxCursor(wxCURSOR_HAND)); @@ -821,25 +823,14 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) }; panel = new wxPanel(m_book); -#if wxUSE_TOOLTIPS - wxRadioBox *radio2 = -#endif // wxUSE_TOOLTIPS - new MyRadioBox( panel, ID_RADIOBOX, _T("&That"), wxPoint(10,160), wxDefaultSize, WXSIZEOF(choices2), choices2, 1, wxRA_SPECIFY_ROWS ); - m_radio = new wxRadioBox( panel, ID_RADIOBOX, _T("T&his"), wxPoint(10,10), wxDefaultSize, WXSIZEOF(choices), choices, 1, wxRA_SPECIFY_COLS ); - -#if wxUSE_TOOLTIPS - m_combo->SetToolTip(_T("This is a natural\ncombobox - can you believe me?")); - radio2->SetToolTip(_T("Ever seen a radiobox?")); - - //m_radio->SetToolTip(_T("Tooltip for the entire radiobox")); - for ( unsigned int nb = 0; nb < WXSIZEOF(choices); nb++ ) - { - m_radio->SetItemToolTip(nb, _T("tooltip for\n") + choices[nb]); - } - - // remove the tooltip for one of the items - m_radio->SetItemToolTip(2, _T("")); -#endif // wxUSE_TOOLTIPS + new MyRadioBox(panel, ID_RADIOBOX2, _T("&That"), + wxPoint(10,160), wxDefaultSize, + WXSIZEOF(choices2), choices2, + 1, wxRA_SPECIFY_ROWS ); + m_radio = new wxRadioBox(panel, ID_RADIOBOX, _T("T&his"), + wxPoint(10,10), wxDefaultSize, + WXSIZEOF(choices), choices, + 1, wxRA_SPECIFY_COLS ); #if wxUSE_HELP for( unsigned int item = 0; item < WXSIZEOF(choices); ++item ) @@ -879,9 +870,6 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) wxDefaultPosition, wxSize(155,wxDefaultCoord), wxSL_AUTOTICKS | wxSL_LABELS); m_slider->SetTickFreq(40, 0); -#if wxUSE_TOOLTIPS - m_slider->SetToolTip(_T("This is a sliding slider")); -#endif // wxUSE_TOOLTIPS sz->Add( m_slider, 0, wxALL, 10 ); m_gaugeVert = new wxGauge( panel, wxID_ANY, 100, @@ -1074,8 +1062,48 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) sizer->Add(m_book, wxSizerFlags().Border().Expand()); sizer->Add(m_text, wxSizerFlags(1).Border().Expand()); SetSizer(sizer); + +#if wxUSE_TOOLTIPS + SetAllToolTips(); +#endif // wxUSE_TOOLTIPS } +#if wxUSE_TOOLTIPS + +namespace +{ + +void ResetToolTip(wxWindow *win, const char *tip) +{ + wxCHECK_RET( win, "NULL window?" ); + + win->UnsetToolTip(); + win->SetToolTip(tip); +} + +} + +void MyPanel::SetAllToolTips() +{ + ResetToolTip(FindWindow(ID_LISTBOX_FONT), "Press here to set italic font"); + ResetToolTip(m_checkbox, "Click here to disable the listbox"); + ResetToolTip(m_listbox, "This is a list box"); + ResetToolTip(m_combo, "This is a natural\ncombobox - can you believe me?"); + ResetToolTip(m_slider, "This is a sliding slider"); + ResetToolTip(FindWindow(ID_RADIOBOX2), "Ever seen a radiobox?"); + + //ResetToolTip(m_radio, "Tooltip for the entire radiobox"); + for ( unsigned int nb = 0; nb < m_radio->GetCount(); nb++ ) + { + m_radio->SetItemToolTip(nb, ""); + m_radio->SetItemToolTip(nb, "tooltip for\n" + m_radio->GetString(nb)); + } + + // remove the tooltip for one of the items + m_radio->SetItemToolTip(2, ""); +} +#endif // wxUSE_TOOLTIPS + void MyPanel::OnIdle(wxIdleEvent& event) { static const int INVALID_SELECTION = -2; @@ -1741,6 +1769,9 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) #if wxUSE_TOOLTIPS EVT_MENU(CONTROLS_SET_TOOLTIP_DELAY, MyFrame::OnSetTooltipDelay) EVT_MENU(CONTROLS_ENABLE_TOOLTIPS, MyFrame::OnToggleTooltips) +#ifdef __WXMSW__ + EVT_MENU(CONTROLS_SET_TOOLTIPS_MAX_WIDTH, MyFrame::OnSetMaxTooltipWidth) +#endif // __WXMSW__ #endif // wxUSE_TOOLTIPS EVT_MENU(CONTROLS_ENABLE_ALL, MyFrame::OnEnableAll) @@ -1787,6 +1818,9 @@ MyFrame::MyFrame(const wxChar *title, int x, int y) tooltip_menu->Append(CONTROLS_ENABLE_TOOLTIPS, _T("&Toggle tooltips\tCtrl-T"), _T("enable/disable tooltips"), true); tooltip_menu->Check(CONTROLS_ENABLE_TOOLTIPS, true); +#ifdef __WXMSW__ + tooltip_menu->Append(CONTROLS_SET_TOOLTIPS_MAX_WIDTH, "Set maximal &width"); +#endif // __WXMSW__ menu_bar->Append(tooltip_menu, _T("&Tooltips")); #endif // wxUSE_TOOLTIPS @@ -1860,7 +1894,36 @@ void MyFrame::OnToggleTooltips(wxCommandEvent& WXUNUSED(event)) wxLogStatus(this, _T("Tooltips %sabled"), s_enabled ? _T("en") : _T("dis") ); } -#endif // tooltips + +#ifdef __WXMSW__ + +void MyFrame::OnSetMaxTooltipWidth(wxCommandEvent& WXUNUSED(event)) +{ + static int s_maxWidth = 0; + + wxNumberEntryDialog dlg + ( + this, + "Change maximal tooltip width", + "&Width in pixels:", + GetTitle(), + s_maxWidth, + -1, + 600 + ); + if ( dlg.ShowModal() == wxID_CANCEL ) + return; + + s_maxWidth = dlg.GetValue(); + wxToolTip::SetMaxWidth(s_maxWidth); + + // we need to set the tooltip again to test the new width + m_panel->SetAllToolTips(); +} + +#endif // __WXMSW__ + +#endif // wxUSE_TOOLTIPS void MyFrame::OnEnableAll(wxCommandEvent& WXUNUSED(event)) { diff --git a/src/msw/tooltip.cpp b/src/msw/tooltip.cpp index dd3fdd076b..31ef19fac0 100644 --- a/src/msw/tooltip.cpp +++ b/src/msw/tooltip.cpp @@ -61,6 +61,9 @@ // the tooltip parent window WXHWND wxToolTip::ms_hwndTT = (WXHWND)NULL; +// new tooltip maximum width, default value is set on first call to wxToolTip::Add() +int wxToolTip::ms_maxWidth = 0; + #if wxUSE_TTM_WINDOWFROMPOINT // the tooltip window proc @@ -215,6 +218,13 @@ void wxToolTip::SetReshow(long milliseconds) TTDT_RESHOW, milliseconds); } +void wxToolTip::SetMaxWidth(int width) +{ + wxASSERT_MSG( width == -1 || width >= 0, _T("invalid width value") ); + + ms_maxWidth = width; +} + // --------------------------------------------------------------------------- // implementation helpers // --------------------------------------------------------------------------- @@ -323,76 +333,82 @@ void wxToolTip::Add(WXHWND hWnd) } else { - // check for multiline toopltip - int index = m_text.Find(_T('\n')); - - if ( index != wxNOT_FOUND ) - { #ifdef TTM_SETMAXTIPWIDTH - if ( wxApp::GetComCtl32Version() >= 470 ) - { - // use TTM_SETMAXTIPWIDTH to make tooltip multiline using the - // extent of its first line as max value - HFONT hfont = (HFONT) - SendTooltipMessage(GetToolTipCtrl(), WM_GETFONT, 0); + if ( wxApp::GetComCtl32Version() >= 470 ) + { + // use TTM_SETMAXTIPWIDTH to make tooltip multiline using the + // extent of its first line as max value + HFONT hfont = (HFONT) + SendTooltipMessage(GetToolTipCtrl(), WM_GETFONT, 0); + if ( !hfont ) + { + hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); if ( !hfont ) { - hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - if ( !hfont ) - { - wxLogLastError(wxT("GetStockObject(DEFAULT_GUI_FONT)")); - } + wxLogLastError(wxT("GetStockObject(DEFAULT_GUI_FONT)")); } + } - MemoryHDC hdc; - if ( !hdc ) - { - wxLogLastError(wxT("CreateCompatibleDC(NULL)")); - } + MemoryHDC hdc; + if ( !hdc ) + { + wxLogLastError(wxT("CreateCompatibleDC(NULL)")); + } - if ( !SelectObject(hdc, hfont) ) - { - wxLogLastError(wxT("SelectObject(hfont)")); - } + if ( !SelectObject(hdc, hfont) ) + { + wxLogLastError(wxT("SelectObject(hfont)")); + } - // find the width of the widest line - int max = 0; - wxStringTokenizer tokenizer(m_text, _T("\n")); - wxString token = tokenizer.GetNextToken(); - while (token.length()) - { - SIZE sz; - if ( !::GetTextExtentPoint32(hdc, token.wx_str(), token.length(), &sz) ) - { - wxLogLastError(wxT("GetTextExtentPoint32")); - } - if ( sz.cx > max ) - max = sz.cx; - - token = tokenizer.GetNextToken(); - } + // find the width of the widest line + int maxWidth = 0; + wxStringTokenizer tokenizer(m_text, _T("\n")); + while ( tokenizer.HasMoreTokens() ) + { + const wxString token = tokenizer.GetNextToken(); - // only set a new width if it is bigger than the current setting - if ( max > SendTooltipMessage(GetToolTipCtrl(), - TTM_GETMAXTIPWIDTH, 0) ) + SIZE sz; + if ( !::GetTextExtentPoint32(hdc, token.wx_str(), + token.length(), &sz) ) { - SendTooltipMessage(GetToolTipCtrl(), TTM_SETMAXTIPWIDTH, - wxUIntToPtr(max)); + wxLogLastError(wxT("GetTextExtentPoint32")); } + + if ( sz.cx > maxWidth ) + maxWidth = sz.cx; } - else -#endif // comctl32.dll >= 4.70 + + // limit size to ms_maxWidth, if set + if ( ms_maxWidth == 0 ) { - // replace the '\n's with spaces because otherwise they appear as - // unprintable characters in the tooltip string - m_text.Replace(_T("\n"), _T(" ")); - ti.lpszText = (wxChar *)m_text.wx_str(); // const_cast + // this is more or less arbitrary but seems to work well + static const int DEFAULT_MAX_WIDTH = 400; - if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, &ti) ) - { - wxLogDebug(_T("Failed to create the tooltip '%s'"), m_text.c_str()); - } + ms_maxWidth = wxGetClientDisplayRect().width / 2; + + if ( ms_maxWidth > DEFAULT_MAX_WIDTH ) + ms_maxWidth = DEFAULT_MAX_WIDTH; + } + + if ( ms_maxWidth != -1 && maxWidth > ms_maxWidth ) + maxWidth = ms_maxWidth; + + // only set a new width if it is bigger than the current setting + SendTooltipMessage(GetToolTipCtrl(), TTM_SETMAXTIPWIDTH, + wxUIntToPtr(maxWidth)); + } + else +#endif // TTM_SETMAXTIPWIDTH + { + // replace the '\n's with spaces because otherwise they appear as + // unprintable characters in the tooltip string + m_text.Replace(_T("\n"), _T(" ")); + ti.lpszText = (wxChar *)m_text.wx_str(); // const_cast + + if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, &ti) ) + { + wxLogDebug(_T("Failed to create the tooltip '%s'"), m_text.c_str()); } } }