X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8292017ce0c67bc3c759d7c681a690b6c493150e..7e25f59e48c3ee93fcb54aa7fca1fd51628c2fac:/src/msw/button.cpp diff --git a/src/msw/button.cpp b/src/msw/button.cpp index 2cafeca17e..cb5cce446f 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -180,36 +180,99 @@ wxSize wxButtonBase::GetDefaultSize() } // ---------------------------------------------------------------------------- -// set this button as the default one in its panel +// default button handling // ---------------------------------------------------------------------------- +/* + "Everything you ever wanted to know about the default buttons" or "Why do we + have to do all this?" + + In MSW the default button should be activated when the user presses Enter + and the current control doesn't process Enter itself somehow. This is + handled by ::DefWindowProc() (or maybe ::DefDialogProc()) using DM_SETDEFID + Another aspect of "defaultness" is that the default button has different + appearance: this is due to BS_DEFPUSHBUTTON style which is completely + separate from DM_SETDEFID stuff (!). + + Final complication is that when a button is active, it should be the default + one, i.e. pressing Enter on a button always activates it and not another + one. + + We handle this by maintaining a permanent and a temporary default items in + wxControlContainer (both may be NULL). When a button becomes the current + control (i.e. gets focus) it sets itself as the temporary default which + ensures that it has the right appearance and that Enter will be redirected + to it. When the button loses focus, it unsets the temporary default and so + the default item will be the permanent default -- that is the default button + if any had been set or none otherwise, which is just what we want. + + Remark that we probably don't need to send DM_SETDEFID as we don't use + ::IsDialogMessage() (which relies on it) any longer but OTOH it probably + doesn't hurt neither. + */ + +// set this button as the (permanently) default one in its panel void wxButton::SetDefault() { wxWindow *parent = GetParent(); - wxButton *btnOldDefault; - if ( parent ) - { - wxWindow *winOldDefault = parent->SetDefaultItem(this); - btnOldDefault = wxDynamicCast(winOldDefault, wxButton); - ::SendMessage(GetWinHwnd(parent), DM_SETDEFID, m_windowId, 0L); + wxCHECK_RET( parent, _T("button without parent?") ); + + // set this one as the default button both for wxWindows and Windows + wxWindow *winOldDefault = parent->SetDefaultItem(this); + ::SendMessage(GetWinHwnd(parent), DM_SETDEFID, m_windowId, 0L); + + UpdateDefaultStyle(this, winOldDefault); +} + +void wxButton::SetTmpDefault() +{ + wxWindow *parent = GetParent(); + + wxCHECK_RET( parent, _T("button without parent?") ); + + wxWindow *winOldDefault = parent->GetDefaultItem(); + parent->SetTmpDefaultItem(this); + if ( winOldDefault != this ) + { + UpdateDefaultStyle(this, winOldDefault); } - else // is a button without parent really normal? + //else: no styles to update +} + +void wxButton::UnsetTmpDefault() +{ + wxWindow *parent = GetParent(); + + wxCHECK_RET( parent, _T("button without parent?") ); + + parent->SetTmpDefaultItem(NULL); + + wxWindow *winOldDefault = parent->GetDefaultItem(); + if ( winOldDefault != this ) { - btnOldDefault = NULL; + UpdateDefaultStyle(winOldDefault, this); } + //else: we had been default before anyhow +} - if ( btnOldDefault && btnOldDefault != this ) +/* static */ +void +wxButton::UpdateDefaultStyle(wxWindow *winDefault, wxWindow *winOldDefault) +{ + // clear the BS_DEFPUSHBUTTON for the old default button + wxButton *btnOldDefault = wxDynamicCast(winOldDefault, wxButton); + if ( btnOldDefault && btnOldDefault != winDefault ) { // remove the BS_DEFPUSHBUTTON style from the other button - long style = GetWindowLong(GetHwndOf(btnOldDefault), GWL_STYLE); + long style = ::GetWindowLong(GetHwndOf(btnOldDefault), GWL_STYLE); // don't do it with the owner drawn buttons because it will reset // BS_OWNERDRAW style bit too (BS_OWNERDRAW & BS_DEFPUSHBUTTON != 0)! if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW ) { style &= ~BS_DEFPUSHBUTTON; - SendMessage(GetHwndOf(btnOldDefault), BM_SETSTYLE, style, 1L); + ::SendMessage(GetHwndOf(btnOldDefault), BM_SETSTYLE, style, 1L); } else { @@ -219,12 +282,20 @@ void wxButton::SetDefault() } } - // set this button as the default - long style = GetWindowLong(GetHwnd(), GWL_STYLE); - if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW ) + // and set BS_DEFPUSHBUTTON for this button + wxButton *btnDefault = wxDynamicCast(winDefault, wxButton); + if ( btnDefault ) { - style |= BS_DEFPUSHBUTTON; - SendMessage(GetHwnd(), BM_SETSTYLE, style, 1L); + long style = ::GetWindowLong(GetHwndOf(btnDefault), GWL_STYLE); + if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW ) + { + style |= BS_DEFPUSHBUTTON; + ::SendMessage(GetHwndOf(btnDefault), BM_SETSTYLE, style, 1L); + } + else + { + btnDefault->Refresh(); + } } } @@ -266,13 +337,18 @@ bool wxButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) long wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - // when we receive focus, we want to become the default button in our - // parent panel + // when we receive focus, we want to temporary become the default button in + // our parent panel so that pressing "Enter" would activate us -- and when + // losing it we should restore the previous default button as well if ( nMsg == WM_SETFOCUS ) { - SetDefault(); + SetTmpDefault(); - // let the default processign take place too + // let the default processing take place too + } + else if ( nMsg == WM_KILLFOCUS ) + { + UnsetTmpDefault(); } else if ( nMsg == WM_LBUTTONDBLCLK ) { @@ -280,7 +356,7 @@ long wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // appearance - without this, it won't do it (void)wxControl::MSWWindowProc(WM_LBUTTONDOWN, wParam, lParam); - // and conitnue with processing the message normally as well + // and continue with processing the message normally as well } // let the base class do all real processing