#endif
#include "wx/stockitem.h"
-#include "wx/tokenzr.h"
#include "wx/msw/private.h"
+#include "wx/msw/private/button.h"
#if wxUSE_UXTHEME
#include "wx/msw/uxtheme.h"
#define ODS_NOFOCUSRECT 0x0200
#endif
+#ifndef DT_HIDEPREFIX
+ #define DT_HIDEPREFIX 0x00100000
+#endif
+
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl)
#endif
-// this macro tries to adjust the default button height to a reasonable value
-// using the char height as the base
-#define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10)
-
// ============================================================================
// implementation
// ============================================================================
+// ----------------------------------------------------------------------------
+// helper functions from wx/msw/private/button.h
+// ----------------------------------------------------------------------------
+
+void wxMSWButton::UpdateMultilineStyle(HWND hwnd, const wxString& label)
+{
+ // update BS_MULTILINE style depending on the new label (resetting it
+ // doesn't seem to do anything very useful but it shouldn't hurt and we do
+ // have to set it whenever the label becomes multi line as otherwise it
+ // wouldn't be shown correctly as we don't use BS_MULTILINE when creating
+ // the control unless it already has new lines in its label)
+ long styleOld = ::GetWindowLong(hwnd, GWL_STYLE),
+ styleNew;
+ if ( label.find(_T('\n')) != wxString::npos )
+ styleNew = styleOld | BS_MULTILINE;
+ else
+ styleNew = styleOld & ~BS_MULTILINE;
+
+ if ( styleNew != styleOld )
+ ::SetWindowLong(hwnd, GWL_STYLE, styleNew);
+}
+
+wxSize wxMSWButton::GetFittingSize(wxWindow *win, const wxSize& sizeLabel)
+{
+ // FIXME: this is pure guesswork, need to retrieve the real button margins
+ wxSize sizeBtn = sizeLabel;
+
+ sizeBtn.x += 3*win->GetCharWidth();
+ sizeBtn.y = 11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(sizeLabel.y)/10;
+
+ return sizeBtn;
+}
+
+wxSize wxMSWButton::ComputeBestSize(wxControl *btn)
+{
+ wxClientDC dc(btn);
+
+ wxSize sizeBtn;
+ dc.GetMultiLineTextExtent(btn->GetLabelText(), &sizeBtn.x, &sizeBtn.y);
+
+ sizeBtn = GetFittingSize(btn, sizeBtn);
+
+ // all buttons have at least the standard size unless the user explicitly
+ // wants them to be of smaller size and used wxBU_EXACTFIT style when
+ // creating the button
+ if ( !btn->HasFlag(wxBU_EXACTFIT) )
+ {
+ wxSize sizeDef = wxButton::GetDefaultSize();
+ if ( sizeBtn.x < sizeDef.x )
+ sizeBtn.x = sizeDef.x;
+ if ( sizeBtn.y < sizeDef.y )
+ sizeBtn.y = sizeDef.y;
+ }
+
+ btn->CacheBestSize(sizeBtn);
+
+ return sizeBtn;
+}
+
// ----------------------------------------------------------------------------
// creation/destruction
// ----------------------------------------------------------------------------
//
// NB: we do it here and not in MSWGetStyle() because we need the label
// value and the label is not set yet when MSWGetStyle() is called
- if ( label.find(_T('\n')) != wxString::npos )
- {
- msStyle |= BS_MULTILINE;
- }
+ msStyle |= wxMSWButton::GetMultilineStyle(label);
return MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, exstyle);
}
void wxButton::SetLabel(const wxString& label)
{
- // update BS_MULTILINE style depending on the new label (resetting it
- // doesn't seem to do anything very useful but it shouldn't hurt and we do
- // have to set it whenever the label becomes multi line as otherwise it
- // wouldn't be shown correctly)
- long styleOld = ::GetWindowLong(GetHwnd(), GWL_STYLE),
- styleNew;
- if ( label.find(_T('\n')) != wxString::npos )
- styleNew = styleOld | BS_MULTILINE;
- else
- styleNew = styleOld & ~BS_MULTILINE;
-
- if ( styleNew != styleOld )
- ::SetWindowLong(GetHwnd(), GWL_STYLE, styleNew);
+ wxMSWButton::UpdateMultilineStyle(GetHwnd(), label);
wxButtonBase::SetLabel(label);
}
wxSize wxButton::DoGetBestSize() const
{
- wxClientDC dc(wx_const_cast(wxButton *, this));
- dc.SetFont(GetFont());
-
- wxCoord wBtn,
- hBtn;
- dc.GetMultiLineTextExtent(GetLabelText(), &wBtn, &hBtn);
-
- // add a margin -- the button is wider than just its label
- wBtn += 3*GetCharWidth();
- hBtn = BUTTON_HEIGHT_FROM_CHAR_HEIGHT(hBtn);
-
- // all buttons have at least the standard size unless the user explicitly
- // wants them to be of smaller size and used wxBU_EXACTFIT style when
- // creating the button
- if ( !HasFlag(wxBU_EXACTFIT) )
- {
- wxSize sz = GetDefaultSize();
- if (wBtn > sz.x)
- sz.x = wBtn;
- if (hBtn > sz.y)
- sz.y = hBtn;
-
- return sz;
- }
-
- wxSize best(wBtn, hBtn);
- CacheBestSize(best);
- return best;
+ return wxMSWButton::ComputeBestSize(wx_const_cast(wxButton *, this));
}
/* static */
return winOldDefault;
}
-// special version of wxGetTopLevelParent() which is safe to call when the
-// parent is being destroyed: wxGetTopLevelParent() would just return NULL in
-// this case because wxWindow version of IsTopLevel() is used when it's called
-// during window destruction instead of wxTLW one, but we want to distinguish
-// between these cases
+// return the top level parent window if it's not being deleted yet, otherwise
+// return NULL
static wxTopLevelWindow *GetTLWParentIfNotBeingDeleted(wxWindow *win)
{
- for ( ; win; win = win->GetParent() )
+ for ( ;; )
{
- if ( win->IsBeingDeleted() )
- return NULL;
+ // IsTopLevel() will return false for a wxTLW being deleted, so we also
+ // need the parent test for this case
+ wxWindow * const parent = win->GetParent();
+ if ( !parent || win->IsTopLevel() )
+ {
+ if ( win->IsBeingDeleted() )
+ return NULL;
- if ( win->IsTopLevel() )
break;
+ }
+
+ win = parent;
}
wxASSERT_MSG( win, _T("button without top level parent?") );
- return wxDynamicCast(win, wxTopLevelWindow);
+ wxTopLevelWindow * const tlw = wxDynamicCast(win, wxTopLevelWindow);
+ wxASSERT_MSG( tlw, _T("logic error in GetTLWParentIfNotBeingDeleted()") );
+
+ return tlw;
}
// set this button as being currently default
static void DrawButtonText(HDC hdc,
RECT *pRect,
const wxString& text,
- COLORREF col)
+ COLORREF col,
+ int flags)
{
COLORREF colOld = SetTextColor(hdc, col);
int modeOld = SetBkMode(hdc, TRANSPARENT);
+ // center text horizontally in any case
+ flags |= DT_CENTER;
+
if ( text.find(_T('\n')) != wxString::npos )
{
// draw multiline label
rc.top = (pRect->bottom - pRect->top)/2 - h/2;
rc.bottom = rc.top+h;
- ::DrawText(hdc, text.wx_str(), text.length(), &rc, DT_CENTER);
+ ::DrawText(hdc, text.wx_str(), text.length(), &rc, flags);
}
else // single line label
{
- // Note: we must have DT_SINGLELINE for DT_VCENTER to work.
+ // centre text vertically too (notice that we must have DT_SINGLELINE
+ // for DT_VCENTER to work)
::DrawText(hdc, text.wx_str(), text.length(), pRect,
- DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+ flags | DT_SINGLELINE | DT_VCENTER);
}
SetBkMode(hdc, modeOld);
}
}
- COLORREF colFg = wxColourToRGB(GetForegroundColour());
- if ( state & ODS_DISABLED ) colFg = GetSysColor(COLOR_GRAYTEXT) ;
- wxString label = GetLabel();
- if ( state & ODS_NOACCEL ) label = GetLabelText() ;
- DrawButtonText(hdc, &rectBtn, label, colFg);
+ COLORREF colFg = state & ODS_DISABLED
+ ? ::GetSysColor(COLOR_GRAYTEXT)
+ : wxColourToRGB(GetForegroundColour());
+
+ // notice that DT_HIDEPREFIX doesn't work on old (pre-Windows 2000) systems
+ // but by happy coincidence ODS_NOACCEL is not used under them neither so
+ // DT_HIDEPREFIX should never be used there
+ DrawButtonText(hdc, &rectBtn, GetLabel(), colFg,
+ state & ODS_NOACCEL ? DT_HIDEPREFIX : 0);
return true;
}
#endif // wxUSE_BUTTON
+