#if wxUSE_BUTTON
#ifndef WX_PRECOMP
+ #include "wx/app.h"
#include "wx/button.h"
#include "wx/brush.h"
#include "wx/panel.h"
wxSize wxButton::DoGetBestSize() const
{
- wxString label = wxGetWindowText(GetHWND());
int wBtn;
- GetTextExtent(label, &wBtn, NULL);
+ GetTextExtent(wxGetWindowText(GetHWND()), &wBtn, NULL);
int wChar, hChar;
wxGetCharSize(GetHWND(), &wChar, &hChar, &GetFont());
- // add a margin - the button is wider than just its label
+ // add a margin -- the button is wider than just its label
wBtn += 3*wChar;
// the button height is proportional to the height of the font used
int hBtn = BUTTON_HEIGHT_FROM_CHAR_HEIGHT(hChar);
- if (!HasFlag(wxBU_EXACTFIT))
+ // 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;
+ if (wBtn > sz.x)
+ sz.x = wBtn;
+ if (hBtn > sz.y)
+ sz.y = hBtn;
+
return sz;
}
- else
- return wxSize(wBtn, hBtn);
+ return wxSize(wBtn, hBtn);
}
/* static */
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 (!).
+ separate from DM_SETDEFID stuff (!). Also note that BS_DEFPUSHBUTTON should
+ be unset if our parent window is not active so it should be unset whenever
+ we lose activation and set back when we regain it.
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
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.
+ NB: all this is quite complicated by now and the worst is that normally
+ it shouldn't be necessary at all as for the normal Windows programs
+ DefWindowProc() and IsDialogMessage() take care of all this
+ automatically -- however in wxWindows programs this doesn't work for
+ nested hierarchies (i.e. a notebook inside a notebook) for unknown
+ reason and so we have to reproduce all this code ourselves. It would be
+ very nice if we could avoid doing it.
*/
// set this button as the (permanently) default one in its panel
wxCHECK_RET( parent, _T("button without parent?") );
- // set this one as the default button both for wxWindows and Windows
+ // set this one as the default button both for wxWindows ...
wxWindow *winOldDefault = parent->SetDefaultItem(this);
- ::SendMessage(GetWinHwnd(parent), DM_SETDEFID, m_windowId, 0L);
- UpdateDefaultStyle(this, winOldDefault);
+ // ... and Windows
+ SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), FALSE);
+ SetDefaultStyle(this, TRUE);
}
+// set this button as being currently default
void wxButton::SetTmpDefault()
{
wxWindow *parent = GetParent();
wxWindow *winOldDefault = parent->GetDefaultItem();
parent->SetTmpDefaultItem(this);
- if ( winOldDefault != this )
- {
- UpdateDefaultStyle(this, winOldDefault);
- }
- //else: no styles to update
+
+ SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), FALSE);
+ SetDefaultStyle(this, TRUE);
}
+// unset this button as currently default, it may still stay permanent default
void wxButton::UnsetTmpDefault()
{
wxWindow *parent = GetParent();
parent->SetTmpDefaultItem(NULL);
wxWindow *winOldDefault = parent->GetDefaultItem();
- if ( winOldDefault != this )
- {
- UpdateDefaultStyle(winOldDefault, this);
- }
- //else: we had been default before anyhow
+
+ SetDefaultStyle(this, FALSE);
+ SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), TRUE);
}
/* static */
void
-wxButton::UpdateDefaultStyle(wxWindow *winDefault, wxWindow *winOldDefault)
+wxButton::SetDefaultStyle(wxButton *btn, bool on)
{
- // clear the BS_DEFPUSHBUTTON for the old default button
- wxButton *btnOldDefault = wxDynamicCast(winOldDefault, wxButton);
- if ( btnOldDefault && btnOldDefault != winDefault )
+ // we may be called with NULL pointer -- simpler to do the check here than
+ // in the caller which does wxDynamicCast()
+ if ( !btn )
+ return;
+
+ // first, let DefDlgProc() know about the new default button
+ if ( on )
{
- // remove the BS_DEFPUSHBUTTON style from the other button
- long style = ::GetWindowLong(GetHwndOf(btnOldDefault), GWL_STYLE);
+ // we shouldn't set BS_DEFPUSHBUTTON for any button if we don't have
+ // focus at all any more
+ if ( !wxTheApp->IsActive() )
+ return;
- // 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);
- }
- else
+ // look for a panel-like window
+ wxWindow *win = btn->GetParent();
+ while ( win && !win->HasFlag(wxTAB_TRAVERSAL) )
+ win = win->GetParent();
+
+ if ( win )
{
- // redraw the button - it will notice itself that it's not the
- // default one any longer
- btnOldDefault->Refresh();
+ ::SendMessage(GetHwndOf(win), DM_SETDEFID, btn->GetId(), 0L);
+
+ // sending DM_SETDEFID also changes the button style to
+ // BS_DEFPUSHBUTTON so there is nothing more to do
}
}
- // and set BS_DEFPUSHBUTTON for this button
- wxButton *btnDefault = wxDynamicCast(winDefault, wxButton);
- if ( btnDefault )
+ // then also change the style as needed
+ long style = ::GetWindowLong(GetHwndOf(btn), GWL_STYLE);
+ if ( !(style & BS_DEFPUSHBUTTON) == on )
{
- long style = ::GetWindowLong(GetHwndOf(btnDefault), GWL_STYLE);
+ // don't do it with the owner drawn buttons because it will
+ // reset BS_OWNERDRAW style bit too (as BS_OWNERDRAW &
+ // BS_DEFPUSHBUTTON != 0)!
if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW )
{
- style |= BS_DEFPUSHBUTTON;
- ::SendMessage(GetHwndOf(btnDefault), BM_SETSTYLE, style, 1L);
+ ::SendMessage(GetHwndOf(btn), BM_SETSTYLE,
+ on ? style | BS_DEFPUSHBUTTON
+ : style & ~BS_DEFPUSHBUTTON,
+ 1L /* redraw */);
}
- else
+ else // owner drawn
{
- btnDefault->Refresh();
+ // redraw the button - it will notice itself that it's
+ // [not] the default one [any longer]
+ btn->Refresh();
}
}
+ //else: already has correct style
}
// ----------------------------------------------------------------------------