X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6c20e8f816b21b911e3a8ed8197c21df6ce726d6..79b7b95aed76eb742deef93d046886c20452fb36:/src/msw/button.cpp?ds=sidebyside diff --git a/src/msw/button.cpp b/src/msw/button.cpp index 0729c9eea0..64e4790923 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -36,6 +36,7 @@ #include "wx/settings.h" #include "wx/dcscreen.h" #include "wx/dcclient.h" + #include "wx/toplevel.h" #endif #include "wx/stockitem.h" @@ -160,16 +161,14 @@ bool wxButton::Create(wxWindow *parent, wxString label(lbl); if (label.empty() && wxIsStockID(id)) { - // On Windows, some buttons aren't supposed to have - // mnemonics, so strip them out. - - label = wxGetStockLabel(id -#if defined(__WXMSW__) || defined(__WXWINCE__) - , ( id != wxID_OK && - id != wxID_CANCEL && - id != wxID_CLOSE ) -#endif - ); + // On Windows, some buttons aren't supposed to have mnemonics + label = wxGetStockLabel + ( + id, + id == wxID_OK || id == wxID_CANCEL || id == wxID_CLOSE + ? wxSTOCK_NOFLAGS + : wxSTOCK_WITH_MNEMONIC + ); } if ( !CreateControl(parent, id, pos, size, style, validator, name) ) @@ -178,19 +177,16 @@ bool wxButton::Create(wxWindow *parent, WXDWORD exstyle; WXDWORD msStyle = MSWGetStyle(style, &exstyle); -#ifdef __WIN32__ // if the label contains several lines we must explicitly tell the button // about it or it wouldn't draw it correctly ("\n"s would just appear as // black boxes) // // NB: we do it here and not in MSWGetStyle() because we need the label - // value and m_label is not set yet when MSWGetStyle() is called; - // besides changing BS_MULTILINE during run-time is pointless anyhow + // value and the label is not set yet when MSWGetStyle() is called if ( label.find(_T('\n')) != wxString::npos ) { msStyle |= BS_MULTILINE; } -#endif // __WIN32__ return MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, exstyle); } @@ -221,7 +217,6 @@ WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const // the bottom msStyle |= WS_CLIPSIBLINGS; -#ifdef __WIN32__ // don't use "else if" here: weird as it is, but you may combine wxBU_LEFT // and wxBU_RIGHT to get BS_CENTER! if ( style & wxBU_LEFT ) @@ -237,11 +232,29 @@ WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const if ( style & wxNO_BORDER ) msStyle |= BS_FLAT; #endif // __WXWINCE__ -#endif // __WIN32__ return msStyle; } +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); + + wxButtonBase::SetLabel(label); +} + // ---------------------------------------------------------------------------- // size management including autosizing // ---------------------------------------------------------------------------- @@ -253,7 +266,7 @@ wxSize wxButton::DoGetBestSize() const wxCoord wBtn, hBtn; - dc.GetMultiLineTextExtent(wxStripMenuCodes(GetLabel()), &wBtn, &hBtn); + dc.GetMultiLineTextExtent(GetLabelText(), &wBtn, &hBtn); // add a margin -- the button is wider than just its label wBtn += 3*GetCharWidth(); @@ -342,26 +355,45 @@ wxSize wxButtonBase::GetDefaultSize() */ // set this button as the (permanently) default one in its panel -void wxButton::SetDefault() +wxWindow *wxButton::SetDefault() { - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); - - wxCHECK_RET( tlw, _T("button without top level window?") ); - // set this one as the default button both for wxWidgets ... - wxWindow *winOldDefault = tlw->SetDefaultItem(this); + wxWindow *winOldDefault = wxButtonBase::SetDefault(); // ... and Windows SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), false); SetDefaultStyle(this, true); + + 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 +static wxTopLevelWindow *GetTLWParentIfNotBeingDeleted(wxWindow *win) +{ + for ( ; win; win = win->GetParent() ) + { + if ( win->IsBeingDeleted() ) + return NULL; + + if ( win->IsTopLevel() ) + break; + } + + wxASSERT_MSG( win, _T("button without top level parent?") ); + + return wxDynamicCast(win, wxTopLevelWindow); } // set this button as being currently default void wxButton::SetTmpDefault() { - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); - - wxCHECK_RET( tlw, _T("button without top level window?") ); + wxTopLevelWindow * const tlw = GetTLWParentIfNotBeingDeleted(GetParent()); + if ( !tlw ) + return; wxWindow *winOldDefault = tlw->GetDefaultItem(); tlw->SetTmpDefaultItem(this); @@ -373,9 +405,9 @@ void wxButton::SetTmpDefault() // unset this button as currently default, it may still stay permanent default void wxButton::UnsetTmpDefault() { - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); - - wxCHECK_RET( tlw, _T("button without top level window?") ); + wxTopLevelWindow * const tlw = GetTLWParentIfNotBeingDeleted(GetParent()); + if ( !tlw ) + return; tlw->SetTmpDefaultItem(NULL); @@ -533,8 +565,6 @@ WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // owner-drawn buttons support // ---------------------------------------------------------------------------- -#ifdef __WIN32__ - // drawing helpers static void DrawButtonText(HDC hdc, @@ -552,7 +582,8 @@ static void DrawButtonText(HDC hdc, // first we need to compute its bounding rect RECT rc; ::CopyRect(&rc, pRect); - ::DrawText(hdc, text, text.length(), &rc, DT_CENTER | DT_CALCRECT); + ::DrawText(hdc, text.wx_str(), text.length(), &rc, + DT_CENTER | DT_CALCRECT); // now center this rect inside the entire button area const LONG w = rc.right - rc.left; @@ -562,12 +593,12 @@ static void DrawButtonText(HDC hdc, rc.top = (pRect->bottom - pRect->top)/2 - h/2; rc.bottom = rc.top+h; - ::DrawText(hdc, text, text.length(), &rc, DT_CENTER); + ::DrawText(hdc, text.wx_str(), text.length(), &rc, DT_CENTER); } else // single line label { // Note: we must have DT_SINGLELINE for DT_VCENTER to work. - ::DrawText(hdc, text, text.length(), pRect, + ::DrawText(hdc, text.wx_str(), text.length(), pRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); } @@ -848,15 +879,12 @@ bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) } COLORREF colFg = wxColourToRGB(GetForegroundColour()); - DrawButtonText(hdc, &rectBtn, - (state & ODS_NOACCEL ? wxStripMenuCodes(GetLabel()) - : GetLabel()), - state & ODS_DISABLED ? GetSysColor(COLOR_GRAYTEXT) - : colFg); + if ( state & ODS_DISABLED ) colFg = GetSysColor(COLOR_GRAYTEXT) ; + wxString label = GetLabel(); + if ( state & ODS_NOACCEL ) label = GetLabelText() ; + DrawButtonText(hdc, &rectBtn, label, colFg); return true; } -#endif // __WIN32__ - #endif // wxUSE_BUTTON