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
This commit is contained in:
Vadim Zeitlin 2009-01-23 13:26:20 +00:00
parent 6063039441
commit be8b43858c
4 changed files with 198 additions and 97 deletions

View File

@ -37,10 +37,14 @@ public:
static void Enable(bool flag); static void Enable(bool flag);
// set the delay after which the tooltip appears // set the delay after which the tooltip appears
static void SetDelay(long milliseconds); 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); static void SetAutoPop(long milliseconds);
// set the delay between subsequent tooltips to appear // set the delay between subsequent tooltips to appear
static void SetReshow(long milliseconds); 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 // implementation only from now on
// ------------------------------- // -------------------------------
@ -62,6 +66,9 @@ private:
// create the tooltip ctrl if it doesn't exist yet and return its HWND // create the tooltip ctrl if it doesn't exist yet and return its HWND
static WXHWND GetToolTipCtrl(); static WXHWND GetToolTipCtrl();
// new tooltip maximum width, defaults to min(display width, 400)
static int ms_maxWidth;
// remove this tooltip from the tooltip control // remove this tooltip from the tooltip control
void Remove(); void Remove();

View File

@ -59,6 +59,21 @@ public:
*/ */
static void SetDelay(long msecs); 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. Set the delay between subsequent tooltips to appear.

View File

@ -28,7 +28,10 @@
#if wxUSE_TOOLTIPS #if wxUSE_TOOLTIPS
#include "wx/tooltip.h" #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__) #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__)
#define USE_XPM #define USE_XPM
@ -75,6 +78,10 @@ public:
MyPanel(wxFrame *frame, int x, int y, int w, int h); MyPanel(wxFrame *frame, int x, int y, int w, int h);
virtual ~MyPanel(); virtual ~MyPanel();
#if wxUSE_TOOLTIPS
void SetAllToolTips();
#endif // wxUSE_TOOLTIPS
void OnIdle( wxIdleEvent &event ); void OnIdle( wxIdleEvent &event );
void OnListBox( wxCommandEvent &event ); void OnListBox( wxCommandEvent &event );
void OnListBoxDoubleClick( wxCommandEvent &event ); void OnListBoxDoubleClick( wxCommandEvent &event );
@ -187,6 +194,9 @@ public:
#if wxUSE_TOOLTIPS #if wxUSE_TOOLTIPS
void OnSetTooltipDelay(wxCommandEvent& event); void OnSetTooltipDelay(wxCommandEvent& event);
void OnToggleTooltips(wxCommandEvent& event); void OnToggleTooltips(wxCommandEvent& event);
#ifdef __WXMSW__
void OnSetMaxTooltipWidth(wxCommandEvent& event);
#endif // __WXMSW__
#endif // wxUSE_TOOLTIPS #endif // wxUSE_TOOLTIPS
void OnEnableAll(wxCommandEvent& event); void OnEnableAll(wxCommandEvent& event);
@ -380,6 +390,7 @@ enum
// tooltip menu // tooltip menu
CONTROLS_SET_TOOLTIP_DELAY = 200, CONTROLS_SET_TOOLTIP_DELAY = 200,
CONTROLS_ENABLE_TOOLTIPS, CONTROLS_ENABLE_TOOLTIPS,
CONTROLS_SET_TOOLTIPS_MAX_WIDTH,
// panel menu // panel menu
CONTROLS_ENABLE_ALL, 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_SEL_STR = 162;
const int ID_RADIOBOX_FONT = 163; const int ID_RADIOBOX_FONT = 163;
const int ID_RADIOBOX_ENABLE = 164; const int ID_RADIOBOX_ENABLE = 164;
const int ID_RADIOBOX2 = 165;
const int ID_RADIOBUTTON_1 = 166; const int ID_RADIOBUTTON_1 = 166;
const int ID_RADIOBUTTON_2 = 167; 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_BUTTON (ID_COMBO_SET_TEXT, MyPanel::OnComboButtons)
EVT_CHECKBOX (ID_COMBO_ENABLE, MyPanel::OnComboButtons) EVT_CHECKBOX (ID_COMBO_ENABLE, MyPanel::OnComboButtons)
EVT_RADIOBOX (ID_RADIOBOX, MyPanel::OnRadio) 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_NUM, MyPanel::OnRadioButtons)
EVT_BUTTON (ID_RADIOBOX_SEL_STR, MyPanel::OnRadioButtons) EVT_BUTTON (ID_RADIOBOX_SEL_STR, MyPanel::OnRadioButtons)
EVT_BUTTON (ID_RADIOBOX_FONT, 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); SetListboxClientData(wxT("listbox"), m_listboxSorted);
m_listbox->SetCursor(*wxCROSS_CURSOR); 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_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) ); 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(); 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 = new wxCheckBox( panel, ID_LISTBOX_ENABLE, _T("&Disable"), wxPoint(20,170) );
m_checkbox->SetValue(false); m_checkbox->SetValue(false);
button->MoveAfterInTabOrder(m_checkbox); 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"), (void)new wxCheckBox( panel, ID_CHANGE_COLOUR, _T("&Toggle colour"),
wxPoint(110,170) ); wxPoint(110,170) );
panel->SetCursor(wxCursor(wxCURSOR_HAND)); 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); panel = new wxPanel(m_book);
#if wxUSE_TOOLTIPS new MyRadioBox(panel, ID_RADIOBOX2, _T("&That"),
wxRadioBox *radio2 = wxPoint(10,160), wxDefaultSize,
#endif // wxUSE_TOOLTIPS WXSIZEOF(choices2), choices2,
new MyRadioBox( panel, ID_RADIOBOX, _T("&That"), wxPoint(10,160), wxDefaultSize, WXSIZEOF(choices2), choices2, 1, wxRA_SPECIFY_ROWS ); 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 ); m_radio = new wxRadioBox(panel, ID_RADIOBOX, _T("T&his"),
wxPoint(10,10), wxDefaultSize,
#if wxUSE_TOOLTIPS WXSIZEOF(choices), choices,
m_combo->SetToolTip(_T("This is a natural\ncombobox - can you believe me?")); 1, wxRA_SPECIFY_COLS );
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
#if wxUSE_HELP #if wxUSE_HELP
for( unsigned int item = 0; item < WXSIZEOF(choices); ++item ) 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), wxDefaultPosition, wxSize(155,wxDefaultCoord),
wxSL_AUTOTICKS | wxSL_LABELS); wxSL_AUTOTICKS | wxSL_LABELS);
m_slider->SetTickFreq(40, 0); 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 ); sz->Add( m_slider, 0, wxALL, 10 );
m_gaugeVert = new wxGauge( panel, wxID_ANY, 100, 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_book, wxSizerFlags().Border().Expand());
sizer->Add(m_text, wxSizerFlags(1).Border().Expand()); sizer->Add(m_text, wxSizerFlags(1).Border().Expand());
SetSizer(sizer); 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) void MyPanel::OnIdle(wxIdleEvent& event)
{ {
static const int INVALID_SELECTION = -2; static const int INVALID_SELECTION = -2;
@ -1741,6 +1769,9 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
#if wxUSE_TOOLTIPS #if wxUSE_TOOLTIPS
EVT_MENU(CONTROLS_SET_TOOLTIP_DELAY, MyFrame::OnSetTooltipDelay) EVT_MENU(CONTROLS_SET_TOOLTIP_DELAY, MyFrame::OnSetTooltipDelay)
EVT_MENU(CONTROLS_ENABLE_TOOLTIPS, MyFrame::OnToggleTooltips) EVT_MENU(CONTROLS_ENABLE_TOOLTIPS, MyFrame::OnToggleTooltips)
#ifdef __WXMSW__
EVT_MENU(CONTROLS_SET_TOOLTIPS_MAX_WIDTH, MyFrame::OnSetMaxTooltipWidth)
#endif // __WXMSW__
#endif // wxUSE_TOOLTIPS #endif // wxUSE_TOOLTIPS
EVT_MENU(CONTROLS_ENABLE_ALL, MyFrame::OnEnableAll) 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"), tooltip_menu->Append(CONTROLS_ENABLE_TOOLTIPS, _T("&Toggle tooltips\tCtrl-T"),
_T("enable/disable tooltips"), true); _T("enable/disable tooltips"), true);
tooltip_menu->Check(CONTROLS_ENABLE_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")); menu_bar->Append(tooltip_menu, _T("&Tooltips"));
#endif // wxUSE_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") ); 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)) void MyFrame::OnEnableAll(wxCommandEvent& WXUNUSED(event))
{ {

View File

@ -61,6 +61,9 @@
// the tooltip parent window // the tooltip parent window
WXHWND wxToolTip::ms_hwndTT = (WXHWND)NULL; 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 #if wxUSE_TTM_WINDOWFROMPOINT
// the tooltip window proc // the tooltip window proc
@ -215,6 +218,13 @@ void wxToolTip::SetReshow(long milliseconds)
TTDT_RESHOW, milliseconds); TTDT_RESHOW, milliseconds);
} }
void wxToolTip::SetMaxWidth(int width)
{
wxASSERT_MSG( width == -1 || width >= 0, _T("invalid width value") );
ms_maxWidth = width;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// implementation helpers // implementation helpers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -323,76 +333,82 @@ void wxToolTip::Add(WXHWND hWnd)
} }
else else
{ {
// check for multiline toopltip
int index = m_text.Find(_T('\n'));
if ( index != wxNOT_FOUND )
{
#ifdef TTM_SETMAXTIPWIDTH #ifdef TTM_SETMAXTIPWIDTH
if ( wxApp::GetComCtl32Version() >= 470 ) if ( wxApp::GetComCtl32Version() >= 470 )
{ {
// use TTM_SETMAXTIPWIDTH to make tooltip multiline using the // use TTM_SETMAXTIPWIDTH to make tooltip multiline using the
// extent of its first line as max value // extent of its first line as max value
HFONT hfont = (HFONT) HFONT hfont = (HFONT)
SendTooltipMessage(GetToolTipCtrl(), WM_GETFONT, 0); SendTooltipMessage(GetToolTipCtrl(), WM_GETFONT, 0);
if ( !hfont )
{
hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
if ( !hfont ) if ( !hfont )
{ {
hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); wxLogLastError(wxT("GetStockObject(DEFAULT_GUI_FONT)"));
if ( !hfont )
{
wxLogLastError(wxT("GetStockObject(DEFAULT_GUI_FONT)"));
}
}
MemoryHDC hdc;
if ( !hdc )
{
wxLogLastError(wxT("CreateCompatibleDC(NULL)"));
}
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();
}
// only set a new width if it is bigger than the current setting
if ( max > SendTooltipMessage(GetToolTipCtrl(),
TTM_GETMAXTIPWIDTH, 0) )
{
SendTooltipMessage(GetToolTipCtrl(), TTM_SETMAXTIPWIDTH,
wxUIntToPtr(max));
} }
} }
else
#endif // comctl32.dll >= 4.70
{
// 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) ) MemoryHDC hdc;
if ( !hdc )
{
wxLogLastError(wxT("CreateCompatibleDC(NULL)"));
}
if ( !SelectObject(hdc, hfont) )
{
wxLogLastError(wxT("SelectObject(hfont)"));
}
// find the width of the widest line
int maxWidth = 0;
wxStringTokenizer tokenizer(m_text, _T("\n"));
while ( tokenizer.HasMoreTokens() )
{
const wxString token = tokenizer.GetNextToken();
SIZE sz;
if ( !::GetTextExtentPoint32(hdc, token.wx_str(),
token.length(), &sz) )
{ {
wxLogDebug(_T("Failed to create the tooltip '%s'"), m_text.c_str()); wxLogLastError(wxT("GetTextExtentPoint32"));
} }
if ( sz.cx > maxWidth )
maxWidth = sz.cx;
}
// limit size to ms_maxWidth, if set
if ( ms_maxWidth == 0 )
{
// this is more or less arbitrary but seems to work well
static const int DEFAULT_MAX_WIDTH = 400;
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());
} }
} }
} }