]> git.saurik.com Git - wxWidgets.git/blob - src/msw/button.cpp
Applied patch [ 851052 ] [msw] Clipboard: Allow automatic format conversions
[wxWidgets.git] / src / msw / button.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/button.cpp
3 // Purpose: wxButton
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "button.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_BUTTON
32
33 #ifndef WX_PRECOMP
34 #include "wx/app.h"
35 #include "wx/button.h"
36 #include "wx/brush.h"
37 #include "wx/panel.h"
38 #include "wx/bmpbuttn.h"
39 #include "wx/settings.h"
40 #include "wx/dcscreen.h"
41 #endif
42
43 #include "wx/msw/private.h"
44
45 // ----------------------------------------------------------------------------
46 // macros
47 // ----------------------------------------------------------------------------
48
49 #if wxUSE_EXTENDED_RTTI
50
51 WX_DEFINE_FLAGS( wxButtonStyle )
52
53 wxBEGIN_FLAGS( wxButtonStyle )
54 // new style border flags, we put them first to
55 // use them for streaming out
56 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
57 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
58 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
59 wxFLAGS_MEMBER(wxBORDER_RAISED)
60 wxFLAGS_MEMBER(wxBORDER_STATIC)
61 wxFLAGS_MEMBER(wxBORDER_NONE)
62
63 // old style border flags
64 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
65 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
66 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
67 wxFLAGS_MEMBER(wxRAISED_BORDER)
68 wxFLAGS_MEMBER(wxSTATIC_BORDER)
69 wxFLAGS_MEMBER(wxBORDER)
70
71 // standard window styles
72 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
73 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
74 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
75 wxFLAGS_MEMBER(wxWANTS_CHARS)
76 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
77 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
78 wxFLAGS_MEMBER(wxVSCROLL)
79 wxFLAGS_MEMBER(wxHSCROLL)
80
81 wxFLAGS_MEMBER(wxBU_LEFT)
82 wxFLAGS_MEMBER(wxBU_RIGHT)
83 wxFLAGS_MEMBER(wxBU_TOP)
84 wxFLAGS_MEMBER(wxBU_BOTTOM)
85 wxFLAGS_MEMBER(wxBU_EXACTFIT)
86 wxEND_FLAGS( wxButtonStyle )
87
88 IMPLEMENT_DYNAMIC_CLASS_XTI(wxButton, wxControl,"wx/button.h")
89
90 wxBEGIN_PROPERTIES_TABLE(wxButton)
91 wxEVENT_PROPERTY( Click , wxEVT_COMMAND_BUTTON_CLICKED , wxCommandEvent)
92
93 wxPROPERTY( Font , wxFont , SetFont , GetFont , , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
94 wxPROPERTY( Label, wxString , SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
95
96 wxPROPERTY_FLAGS( WindowStyle , wxButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
97
98 wxEND_PROPERTIES_TABLE()
99
100 wxBEGIN_HANDLERS_TABLE(wxButton)
101 wxEND_HANDLERS_TABLE()
102
103 wxCONSTRUCTOR_6( wxButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle )
104
105
106 #else
107 IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl)
108 #endif
109
110 // this macro tries to adjust the default button height to a reasonable value
111 // using the char height as the base
112 #define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10)
113
114 // ============================================================================
115 // implementation
116 // ============================================================================
117
118 // ----------------------------------------------------------------------------
119 // creation/destruction
120 // ----------------------------------------------------------------------------
121
122 wxButtonBase::wxButtonBase()
123 {
124 }
125
126 bool wxButton::Create(wxWindow *parent,
127 wxWindowID id,
128 const wxString& label,
129 const wxPoint& pos,
130 const wxSize& size,
131 long style,
132 const wxValidator& validator,
133 const wxString& name)
134 {
135 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
136 return FALSE;
137
138 WXDWORD exstyle;
139 WXDWORD msStyle = MSWGetStyle(style, &exstyle);
140
141 #ifdef __WIN32__
142 // if the label contains several lines we must explicitly tell the button
143 // about it or it wouldn't draw it correctly ("\n"s would just appear as
144 // black boxes)
145 //
146 // NB: we do it here and not in MSWGetStyle() because we need the label
147 // value and m_label is not set yet when MSWGetStyle() is called;
148 // besides changing BS_MULTILINE during run-time is pointless anyhow
149 if ( label.find(_T('\n')) != wxString::npos )
150 {
151 msStyle |= BS_MULTILINE;
152 }
153 #endif // __WIN32__
154
155 return MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, exstyle);
156 }
157
158 wxButton::~wxButton()
159 {
160 }
161
162 // ----------------------------------------------------------------------------
163 // flags
164 // ----------------------------------------------------------------------------
165
166 WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const
167 {
168 // buttons never have an external border, they draw their own one
169 WXDWORD msStyle = wxControl::MSWGetStyle
170 (
171 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
172 );
173
174 // we must use WS_CLIPSIBLINGS with the buttons or they would draw over
175 // each other in any resizeable dialog which has more than one button in
176 // the bottom
177 msStyle |= WS_CLIPSIBLINGS;
178
179 #ifdef __WIN32__
180 // don't use "else if" here: weird as it is, but you may combine wxBU_LEFT
181 // and wxBU_RIGHT to get BS_CENTER!
182 if ( style & wxBU_LEFT )
183 msStyle |= BS_LEFT;
184 if ( style & wxBU_RIGHT )
185 msStyle |= BS_RIGHT;
186 if ( style & wxBU_TOP )
187 msStyle |= BS_TOP;
188 if ( style & wxBU_BOTTOM )
189 msStyle |= BS_BOTTOM;
190 // flat 2d buttons
191 if ( style & wxNO_BORDER )
192 msStyle |= BS_FLAT;
193 #endif // __WIN32__
194
195 return msStyle;
196 }
197
198 // ----------------------------------------------------------------------------
199 // size management including autosizing
200 // ----------------------------------------------------------------------------
201
202 wxSize wxButton::DoGetBestSize() const
203 {
204 int wBtn;
205 GetTextExtent(wxGetWindowText(GetHWND()), &wBtn, NULL);
206
207 int wChar, hChar;
208 wxGetCharSize(GetHWND(), &wChar, &hChar, &GetFont());
209
210 // add a margin -- the button is wider than just its label
211 wBtn += 3*wChar;
212
213 // the button height is proportional to the height of the font used
214 int hBtn = BUTTON_HEIGHT_FROM_CHAR_HEIGHT(hChar);
215
216 // all buttons have at least the standard size unless the user explicitly
217 // wants them to be of smaller size and used wxBU_EXACTFIT style when
218 // creating the button
219 if ( !HasFlag(wxBU_EXACTFIT) )
220 {
221 wxSize sz = GetDefaultSize();
222 if (wBtn > sz.x)
223 sz.x = wBtn;
224 if (hBtn > sz.y)
225 sz.y = hBtn;
226
227 return sz;
228 }
229
230 return wxSize(wBtn, hBtn);
231 }
232
233 /* static */
234 wxSize wxButtonBase::GetDefaultSize()
235 {
236 static wxSize s_sizeBtn;
237
238 if ( s_sizeBtn.x == 0 )
239 {
240 wxScreenDC dc;
241 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
242
243 // the size of a standard button in the dialog units is 50x14,
244 // translate this to pixels
245 // NB1: the multipliers come from the Windows convention
246 // NB2: the extra +1/+2 were needed to get the size be the same as the
247 // size of the buttons in the standard dialog - I don't know how
248 // this happens, but on my system this size is 75x23 in pixels and
249 // 23*8 isn't even divisible by 14... Would be nice to understand
250 // why these constants are needed though!
251 s_sizeBtn.x = (50 * (dc.GetCharWidth() + 1))/4;
252 s_sizeBtn.y = ((14 * dc.GetCharHeight()) + 2)/8;
253 }
254
255 return s_sizeBtn;
256 }
257
258 // ----------------------------------------------------------------------------
259 // default button handling
260 // ----------------------------------------------------------------------------
261
262 /*
263 "Everything you ever wanted to know about the default buttons" or "Why do we
264 have to do all this?"
265
266 In MSW the default button should be activated when the user presses Enter
267 and the current control doesn't process Enter itself somehow. This is
268 handled by ::DefWindowProc() (or maybe ::DefDialogProc()) using DM_SETDEFID
269 Another aspect of "defaultness" is that the default button has different
270 appearance: this is due to BS_DEFPUSHBUTTON style which is completely
271 separate from DM_SETDEFID stuff (!). Also note that BS_DEFPUSHBUTTON should
272 be unset if our parent window is not active so it should be unset whenever
273 we lose activation and set back when we regain it.
274
275 Final complication is that when a button is active, it should be the default
276 one, i.e. pressing Enter on a button always activates it and not another
277 one.
278
279 We handle this by maintaining a permanent and a temporary default items in
280 wxControlContainer (both may be NULL). When a button becomes the current
281 control (i.e. gets focus) it sets itself as the temporary default which
282 ensures that it has the right appearance and that Enter will be redirected
283 to it. When the button loses focus, it unsets the temporary default and so
284 the default item will be the permanent default -- that is the default button
285 if any had been set or none otherwise, which is just what we want.
286
287 NB: all this is quite complicated by now and the worst is that normally
288 it shouldn't be necessary at all as for the normal Windows programs
289 DefWindowProc() and IsDialogMessage() take care of all this
290 automatically -- however in wxWindows programs this doesn't work for
291 nested hierarchies (i.e. a notebook inside a notebook) for unknown
292 reason and so we have to reproduce all this code ourselves. It would be
293 very nice if we could avoid doing it.
294 */
295
296 // set this button as the (permanently) default one in its panel
297 void wxButton::SetDefault()
298 {
299 wxWindow *parent = GetParent();
300
301 wxCHECK_RET( parent, _T("button without parent?") );
302
303 // set this one as the default button both for wxWindows ...
304 wxWindow *winOldDefault = parent->SetDefaultItem(this);
305
306 // ... and Windows
307 SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), FALSE);
308 SetDefaultStyle(this, TRUE);
309 }
310
311 // set this button as being currently default
312 void wxButton::SetTmpDefault()
313 {
314 wxWindow *parent = GetParent();
315
316 wxCHECK_RET( parent, _T("button without parent?") );
317
318 wxWindow *winOldDefault = parent->GetDefaultItem();
319 parent->SetTmpDefaultItem(this);
320
321 SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), FALSE);
322 SetDefaultStyle(this, TRUE);
323 }
324
325 // unset this button as currently default, it may still stay permanent default
326 void wxButton::UnsetTmpDefault()
327 {
328 wxWindow *parent = GetParent();
329
330 wxCHECK_RET( parent, _T("button without parent?") );
331
332 parent->SetTmpDefaultItem(NULL);
333
334 wxWindow *winOldDefault = parent->GetDefaultItem();
335
336 SetDefaultStyle(this, FALSE);
337 SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), TRUE);
338 }
339
340 /* static */
341 void
342 wxButton::SetDefaultStyle(wxButton *btn, bool on)
343 {
344 // we may be called with NULL pointer -- simpler to do the check here than
345 // in the caller which does wxDynamicCast()
346 if ( !btn )
347 return;
348
349 // first, let DefDlgProc() know about the new default button
350 if ( on )
351 {
352 // we shouldn't set BS_DEFPUSHBUTTON for any button if we don't have
353 // focus at all any more
354 if ( !wxTheApp->IsActive() )
355 return;
356
357 // look for a panel-like window
358 wxWindow *win = btn->GetParent();
359 while ( win && !win->HasFlag(wxTAB_TRAVERSAL) )
360 win = win->GetParent();
361
362 if ( win )
363 {
364 ::SendMessage(GetHwndOf(win), DM_SETDEFID, btn->GetId(), 0L);
365
366 // sending DM_SETDEFID also changes the button style to
367 // BS_DEFPUSHBUTTON so there is nothing more to do
368 }
369 }
370
371 // then also change the style as needed
372 long style = ::GetWindowLong(GetHwndOf(btn), GWL_STYLE);
373 if ( !(style & BS_DEFPUSHBUTTON) == on )
374 {
375 // don't do it with the owner drawn buttons because it will
376 // reset BS_OWNERDRAW style bit too (as BS_OWNERDRAW &
377 // BS_DEFPUSHBUTTON != 0)!
378 if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW )
379 {
380 ::SendMessage(GetHwndOf(btn), BM_SETSTYLE,
381 on ? style | BS_DEFPUSHBUTTON
382 : style & ~BS_DEFPUSHBUTTON,
383 1L /* redraw */);
384 }
385 else // owner drawn
386 {
387 // redraw the button - it will notice itself that it's
388 // [not] the default one [any longer]
389 btn->Refresh();
390 }
391 }
392 //else: already has correct style
393 }
394
395 // ----------------------------------------------------------------------------
396 // helpers
397 // ----------------------------------------------------------------------------
398
399 bool wxButton::SendClickEvent()
400 {
401 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
402 event.SetEventObject(this);
403
404 return ProcessCommand(event);
405 }
406
407 void wxButton::Command(wxCommandEvent & event)
408 {
409 ProcessCommand(event);
410 }
411
412 // ----------------------------------------------------------------------------
413 // event/message handlers
414 // ----------------------------------------------------------------------------
415
416 bool wxButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
417 {
418 bool processed = FALSE;
419 switch ( param )
420 {
421 // NOTE: Apparently older versions (NT 4?) of the common controls send
422 // BN_DOUBLECLICKED but not a second BN_CLICKED for owner-drawn
423 // buttons, so in order to send two EVET_BUTTON events we should
424 // catch both types. Currently (Feb 2003) up-to-date versions of
425 // win98, win2k and winXP all send two BN_CLICKED messages for
426 // all button types, so we don't catch BN_DOUBLECLICKED anymore
427 // in order to not get 3 EVT_BUTTON events. If this is a problem
428 // then we need to figure out which version of the comctl32 changed
429 // this behaviour and test for it.
430
431 case 1: // message came from an accelerator
432 case BN_CLICKED: // normal buttons send this
433 processed = SendClickEvent();
434 break;
435 }
436
437 return processed;
438 }
439
440 long wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
441 {
442 // when we receive focus, we want to temporary become the default button in
443 // our parent panel so that pressing "Enter" would activate us -- and when
444 // losing it we should restore the previous default button as well
445 if ( nMsg == WM_SETFOCUS )
446 {
447 SetTmpDefault();
448
449 // let the default processing take place too
450 }
451 else if ( nMsg == WM_KILLFOCUS )
452 {
453 UnsetTmpDefault();
454 }
455 else if ( nMsg == WM_LBUTTONDBLCLK )
456 {
457 // emulate a click event to force an owner-drawn button to change its
458 // appearance - without this, it won't do it
459 (void)wxControl::MSWWindowProc(WM_LBUTTONDOWN, wParam, lParam);
460
461 // and continue with processing the message normally as well
462 }
463
464 // let the base class do all real processing
465 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
466 }
467
468 // ----------------------------------------------------------------------------
469 // owner-drawn buttons support
470 // ----------------------------------------------------------------------------
471
472 #ifdef __WIN32__
473
474 // drawing helpers
475
476 static void DrawButtonText(HDC hdc,
477 RECT *pRect,
478 const wxString& text,
479 COLORREF col)
480 {
481 COLORREF colOld = SetTextColor(hdc, col);
482 int modeOld = SetBkMode(hdc, TRANSPARENT);
483
484 // Note: we must have DT_SINGLELINE for DT_VCENTER to work.
485 ::DrawText(hdc, text, text.length(), pRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
486
487 SetBkMode(hdc, modeOld);
488 SetTextColor(hdc, colOld);
489 }
490
491 static void DrawRect(HDC hdc, const RECT& r)
492 {
493 wxDrawLine(hdc, r.left, r.top, r.right, r.top);
494 wxDrawLine(hdc, r.right, r.top, r.right, r.bottom);
495 wxDrawLine(hdc, r.right, r.bottom, r.left, r.bottom);
496 wxDrawLine(hdc, r.left, r.bottom, r.left, r.top);
497 }
498
499 void wxButton::MakeOwnerDrawn()
500 {
501 long style = GetWindowLong(GetHwnd(), GWL_STYLE);
502 if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW )
503 {
504 // make it so
505 style |= BS_OWNERDRAW;
506 SetWindowLong(GetHwnd(), GWL_STYLE, style);
507 }
508 }
509
510 bool wxButton::SetBackgroundColour(const wxColour &colour)
511 {
512 if ( !wxControl::SetBackgroundColour(colour) )
513 {
514 // nothing to do
515 return FALSE;
516 }
517
518 MakeOwnerDrawn();
519
520 Refresh();
521
522 return TRUE;
523 }
524
525 bool wxButton::SetForegroundColour(const wxColour &colour)
526 {
527 if ( !wxControl::SetForegroundColour(colour) )
528 {
529 // nothing to do
530 return FALSE;
531 }
532
533 MakeOwnerDrawn();
534
535 Refresh();
536
537 return TRUE;
538 }
539
540 /*
541 The button frame looks like this normally:
542
543 WWWWWWWWWWWWWWWWWWB
544 WHHHHHHHHHHHHHHHHGB W = white (HILIGHT)
545 WH GB H = light grey (LIGHT)
546 WH GB G = dark grey (SHADOW)
547 WH GB B = black (DKSHADOW)
548 WH GB
549 WGGGGGGGGGGGGGGGGGB
550 BBBBBBBBBBBBBBBBBBB
551
552 When the button is selected, the button becomes like this (the total button
553 size doesn't change):
554
555 BBBBBBBBBBBBBBBBBBB
556 BWWWWWWWWWWWWWWWWBB
557 BWHHHHHHHHHHHHHHGBB
558 BWH GBB
559 BWH GBB
560 BWGGGGGGGGGGGGGGGBB
561 BBBBBBBBBBBBBBBBBBB
562 BBBBBBBBBBBBBBBBBBB
563
564 When the button is pushed (while selected) it is like:
565
566 BBBBBBBBBBBBBBBBBBB
567 BGGGGGGGGGGGGGGGGGB
568 BG GB
569 BG GB
570 BG GB
571 BG GB
572 BGGGGGGGGGGGGGGGGGB
573 BBBBBBBBBBBBBBBBBBB
574 */
575
576 static void DrawButtonFrame(HDC hdc, const RECT& rectBtn,
577 bool selected, bool pushed)
578 {
579 RECT r;
580 CopyRect(&r, &rectBtn);
581
582 HPEN hpenBlack = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW)),
583 hpenGrey = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)),
584 hpenLightGr = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DLIGHT)),
585 hpenWhite = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
586
587 HPEN hpenOld = (HPEN)SelectObject(hdc, hpenBlack);
588
589 r.right--;
590 r.bottom--;
591
592 if ( pushed )
593 {
594 DrawRect(hdc, r);
595
596 (void)SelectObject(hdc, hpenGrey);
597 InflateRect(&r, -1, -1);
598
599 DrawRect(hdc, r);
600 }
601 else // !pushed
602 {
603 if ( selected )
604 {
605 DrawRect(hdc, r);
606
607 InflateRect(&r, -1, -1);
608 }
609
610 wxDrawLine(hdc, r.left, r.bottom, r.right, r.bottom);
611 wxDrawLine(hdc, r.right, r.bottom, r.right, r.top - 1);
612
613 (void)SelectObject(hdc, hpenWhite);
614 wxDrawLine(hdc, r.left, r.bottom - 1, r.left, r.top);
615 wxDrawLine(hdc, r.left, r.top, r.right, r.top);
616
617 (void)SelectObject(hdc, hpenLightGr);
618 wxDrawLine(hdc, r.left + 1, r.bottom - 2, r.left + 1, r.top + 1);
619 wxDrawLine(hdc, r.left + 1, r.top + 1, r.right - 1, r.top + 1);
620
621 (void)SelectObject(hdc, hpenGrey);
622 wxDrawLine(hdc, r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1);
623 wxDrawLine(hdc, r.right - 1, r.bottom - 1, r.right - 1, r.top);
624 }
625
626 (void)SelectObject(hdc, hpenOld);
627 DeleteObject(hpenWhite);
628 DeleteObject(hpenLightGr);
629 DeleteObject(hpenGrey);
630 DeleteObject(hpenBlack);
631 }
632
633 bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
634 {
635 LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis;
636
637 RECT rectBtn;
638 CopyRect(&rectBtn, &lpDIS->rcItem);
639
640 COLORREF colBg = wxColourToRGB(GetBackgroundColour()),
641 colFg = wxColourToRGB(GetForegroundColour());
642
643 HDC hdc = lpDIS->hDC;
644 UINT state = lpDIS->itemState;
645
646 // first, draw the background
647 HBRUSH hbrushBackground = ::CreateSolidBrush(colBg);
648
649 FillRect(hdc, &rectBtn, hbrushBackground);
650
651 // draw the border for the current state
652 bool selected = (state & ODS_SELECTED) != 0;
653 if ( !selected )
654 {
655 wxPanel *panel = wxDynamicCast(GetParent(), wxPanel);
656 if ( panel )
657 {
658 selected = panel->GetDefaultItem() == this;
659 }
660 }
661 bool pushed = (SendMessage(GetHwnd(), BM_GETSTATE, 0, 0) & BST_PUSHED) != 0;
662
663 DrawButtonFrame(hdc, rectBtn, selected, pushed);
664
665 // draw the focus rect if needed
666 if ( state & ODS_FOCUS )
667 {
668 RECT rectFocus;
669 CopyRect(&rectFocus, &rectBtn);
670
671 // I don't know where does this constant come from, but this is how
672 // Windows draws them
673 InflateRect(&rectFocus, -4, -4);
674
675 DrawFocusRect(hdc, &rectFocus);
676 }
677
678 if ( pushed )
679 {
680 // the label is shifted by 1 pixel to create "pushed" effect
681 OffsetRect(&rectBtn, 1, 1);
682 }
683
684 DrawButtonText(hdc, &rectBtn, GetLabel(),
685 state & ODS_DISABLED ? GetSysColor(COLOR_GRAYTEXT)
686 : colFg);
687
688 ::DeleteObject(hbrushBackground);
689
690 return TRUE;
691 }
692
693 #endif // __WIN32__
694
695 #endif // wxUSE_BUTTON
696