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