]> git.saurik.com Git - wxWidgets.git/blame - src/msw/bmpbuttn.cpp
fix crash which happened if you called SetAttr(NULL) followed by SetAttr(attr) (...
[wxWidgets.git] / src / msw / bmpbuttn.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
1e6feb95 2// Name: src/msw/bmpbuttn.cpp
2bda0e17
KB
3// Purpose: wxBitmapButton
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
2bda0e17
KB
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
1e6feb95 16 #pragma hdrstop
2bda0e17
KB
17#endif
18
1e6feb95
VZ
19#if wxUSE_BMPBUTTON
20
910b0053
WS
21#include "wx/bmpbuttn.h"
22
2bda0e17 23#ifndef WX_PRECOMP
84f19880 24 #include "wx/log.h"
47e92c41 25 #include "wx/dcmemory.h"
155ecd4c 26 #include "wx/image.h"
2bda0e17
KB
27#endif
28
29#include "wx/msw/private.h"
025f7d77 30#include "wx/msw/dc.h" // for wxDCTemp
4e9da8b7 31
37005692 32#include "wx/msw/uxtheme.h"
4e9da8b7 33
37005692 34#if wxUSE_UXTHEME
4e9da8b7
RD
35 // no need to include tmschema.h
36 #ifndef BP_PUSHBUTTON
37 #define BP_PUSHBUTTON 1
38
39 #define PBS_NORMAL 1
40 #define PBS_HOT 2
41 #define PBS_PRESSED 3
42 #define PBS_DISABLED 4
43 #define PBS_DEFAULTED 5
44
45 #define TMT_CONTENTMARGINS 3602
46 #endif
47#endif // wxUSE_UXTHEME
48
49#ifndef ODS_NOFOCUSRECT
50 #define ODS_NOFOCUSRECT 0x0200
51#endif
2bda0e17 52
bc9fb572
JS
53// ----------------------------------------------------------------------------
54// macros
55// ----------------------------------------------------------------------------
56
57#if wxUSE_EXTENDED_RTTI
58
59WX_DEFINE_FLAGS( wxBitmapButtonStyle )
60
3ff066a4 61wxBEGIN_FLAGS( wxBitmapButtonStyle )
bc9fb572
JS
62 // new style border flags, we put them first to
63 // use them for streaming out
3ff066a4
SC
64 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
65 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
66 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
67 wxFLAGS_MEMBER(wxBORDER_RAISED)
68 wxFLAGS_MEMBER(wxBORDER_STATIC)
69 wxFLAGS_MEMBER(wxBORDER_NONE)
fcf90ee1 70
bc9fb572 71 // old style border flags
3ff066a4
SC
72 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
73 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
74 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
75 wxFLAGS_MEMBER(wxRAISED_BORDER)
76 wxFLAGS_MEMBER(wxSTATIC_BORDER)
cb0afb26 77 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
78
79 // standard window styles
3ff066a4
SC
80 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
81 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
82 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
83 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 84 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
85 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
86 wxFLAGS_MEMBER(wxVSCROLL)
87 wxFLAGS_MEMBER(wxHSCROLL)
88
89 wxFLAGS_MEMBER(wxBU_AUTODRAW)
90 wxFLAGS_MEMBER(wxBU_LEFT)
91 wxFLAGS_MEMBER(wxBU_RIGHT)
92 wxFLAGS_MEMBER(wxBU_TOP)
93 wxFLAGS_MEMBER(wxBU_BOTTOM)
94wxEND_FLAGS( wxBitmapButtonStyle )
bc9fb572
JS
95
96IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton, wxButton,"wx/bmpbuttn.h")
97
3ff066a4 98wxBEGIN_PROPERTIES_TABLE(wxBitmapButton)
af498247 99 wxPROPERTY_FLAGS( WindowStyle , wxBitmapButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 100wxEND_PROPERTIES_TABLE()
bc9fb572 101
3ff066a4
SC
102wxBEGIN_HANDLERS_TABLE(wxBitmapButton)
103wxEND_HANDLERS_TABLE()
bc9fb572 104
3ff066a4 105wxCONSTRUCTOR_5( wxBitmapButton , wxWindow* , Parent , wxWindowID , Id , wxBitmap , Bitmap , wxPoint , Position , wxSize , Size )
bc9fb572
JS
106
107#else
2bda0e17 108IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton)
bc9fb572 109#endif
2bda0e17 110
a6fd0fde
VZ
111BEGIN_EVENT_TABLE(wxBitmapButton, wxBitmapButtonBase)
112 EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged)
1fdc16ad
VZ
113 EVT_ENTER_WINDOW(wxBitmapButton::OnMouseEnterOrLeave)
114 EVT_LEAVE_WINDOW(wxBitmapButton::OnMouseEnterOrLeave)
a6fd0fde
VZ
115END_EVENT_TABLE()
116
066f1b7a
SC
117/*
118TODO PROPERTIES :
119
120long "style" , wxBU_AUTODRAW
121bool "default" , 0
122bitmap "selected" ,
123bitmap "focus" ,
124bitmap "disabled" ,
125*/
126
a265d21a
DS
127bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id,
128 const wxBitmap& bitmap,
129 const wxPoint& pos,
130 const wxSize& size, long style,
131 const wxValidator& wxVALIDATOR_PARAM(validator),
132 const wxString& name)
2bda0e17 133{
5f1f21d2 134 SetBitmapLabel(bitmap);
a265d21a 135 SetName(name);
11b6a93b
VZ
136
137#if wxUSE_VALIDATORS
a265d21a 138 SetValidator(validator);
11b6a93b 139#endif // wxUSE_VALIDATORS
2bda0e17 140
a265d21a 141 parent->AddChild(this);
2bda0e17 142
a265d21a 143 m_windowStyle = style;
2bda0e17 144
a265d21a
DS
145 if ( style & wxBU_AUTODRAW )
146 {
1fdc16ad
VZ
147 m_marginX =
148 m_marginY = 4;
a265d21a 149 }
2bda0e17 150
fcf90ee1 151 if (id == wxID_ANY)
a265d21a
DS
152 m_windowId = NewControlId();
153 else
154 m_windowId = id;
2bda0e17 155
a265d21a 156 long msStyle = WS_VISIBLE | WS_TABSTOP | WS_CHILD | BS_OWNERDRAW ;
f6bcfd97 157
b0766406
JS
158 if ( m_windowStyle & wxCLIP_SIBLINGS )
159 msStyle |= WS_CLIPSIBLINGS;
160
f6bcfd97
BP
161#ifdef __WIN32__
162 if(m_windowStyle & wxBU_LEFT)
163 msStyle |= BS_LEFT;
164 if(m_windowStyle & wxBU_RIGHT)
165 msStyle |= BS_RIGHT;
166 if(m_windowStyle & wxBU_TOP)
167 msStyle |= BS_TOP;
168 if(m_windowStyle & wxBU_BOTTOM)
169 msStyle |= BS_BOTTOM;
170#endif
171
a265d21a 172 m_hWnd = (WXHWND) CreateWindowEx(
42e69d6b 173 0,
223d09f6 174 wxT("BUTTON"),
fda7962d 175 wxEmptyString,
f6bcfd97 176 msStyle,
33ac7e6f 177 0, 0, 0, 0,
42e69d6b 178 GetWinHwnd(parent),
dca0f651 179 (HMENU)wxUIntToPtr(m_windowId.GetValue()),
42e69d6b
VZ
180 wxGetInstance(),
181 NULL
182 );
2bda0e17 183
a265d21a
DS
184 // Subclass again for purposes of dialog editing mode
185 SubclassWin(m_hWnd);
2bda0e17 186
9f884528 187 SetPosition(pos);
170acdc9 188 SetInitialSize(size);
2bda0e17 189
a265d21a 190 return true;
2bda0e17
KB
191}
192
d50dbf7c
VZ
193bool wxBitmapButton::SetBackgroundColour(const wxColour& colour)
194{
195 if ( !wxBitmapButtonBase::SetBackgroundColour(colour) )
196 {
197 // didn't change
198 return false;
199 }
200
201 // invalidate the brush, it will be recreated the next time it's needed
202 m_brushDisabled = wxNullBrush;
203
204 return true;
205}
206
a6fd0fde
VZ
207void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent& event)
208{
209 m_brushDisabled = wxNullBrush;
210
211 if ( !IsEnabled() )
212 {
213 // this change affects our current state
214 Refresh();
215 }
216
217 event.Skip();
218}
219
1fdc16ad
VZ
220void wxBitmapButton::OnMouseEnterOrLeave(wxMouseEvent& event)
221{
222 if ( IsEnabled() && m_bmpHover.Ok() )
223 Refresh();
224
225 event.Skip();
226}
227
5f1f21d2
VZ
228void wxBitmapButton::SetBitmapLabel(const wxBitmap& bitmap)
229{
230#if wxUSE_IMAGE
e040a4ff 231 if ( !HasFlag(wxBU_AUTODRAW) && !m_disabledSetByUser && bitmap.IsOk() )
5f1f21d2
VZ
232 {
233 m_bmpDisabled = wxBitmap(bitmap.ConvertToImage().ConvertToGreyscale());
234 }
235#endif // wxUSE_IMAGE
236
237 wxBitmapButtonBase::SetBitmapLabel(bitmap);
238}
239
240void wxBitmapButton::SetBitmapFocus(const wxBitmap& focus)
7996ff80
VZ
241{
242 // if the focus bitmap is specified but hover one isn't, use the focus
243 // bitmap for hovering as well if this is consistent with the current
244 // Windows version look and feel
245 //
246 // rationale: this is compatible with the old wxGTK behaviour and also
247 // makes it much easier to do "the right thing" for all platforms (some of
248 // them, such as Windows XP, have "hot" buttons while others don't)
5f1f21d2 249 if ( focus.Ok() && !m_hoverSetByUser )
7996ff80 250 m_bmpHover = m_bmpFocus;
7996ff80 251
5f1f21d2
VZ
252 wxBitmapButtonBase::SetBitmapFocus(focus);
253}
254
255void wxBitmapButton::SetBitmapDisabled(const wxBitmap& disabled)
256{
257 if ( disabled.IsOk() )
258 m_disabledSetByUser = true;
259
260 wxBitmapButtonBase::SetBitmapDisabled(disabled);
261}
262
263void wxBitmapButton::SetBitmapHover(const wxBitmap& hover)
264{
265 if ( hover.IsOk() )
266 m_hoverSetByUser = true;
267
268 wxBitmapButtonBase::SetBitmapHover(hover);
7996ff80
VZ
269}
270
4e9da8b7
RD
271#if wxUSE_UXTHEME
272static
273void MSWDrawXPBackground(wxButton *button, WXDRAWITEMSTRUCT *wxdis)
274{
275 LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis;
276 HDC hdc = lpDIS->hDC;
277 UINT state = lpDIS->itemState;
278 RECT rectBtn;
279 CopyRect(&rectBtn, &lpDIS->rcItem);
280
281 wxUxThemeHandle theme(button, L"BUTTON");
282 int iState;
283
284 if ( state & ODS_SELECTED )
285 {
286 iState = PBS_PRESSED;
287 }
288 else if ( button->HasCapture() || button->IsMouseInWindow() )
289 {
290 iState = PBS_HOT;
291 }
292 else if ( state & ODS_FOCUS )
293 {
294 iState = PBS_DEFAULTED;
295 }
296 else if ( state & ODS_DISABLED )
297 {
298 iState = PBS_DISABLED;
299 }
300 else
301 {
302 iState = PBS_NORMAL;
303 }
304
305 // draw parent background if needed
306 if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme,
307 BP_PUSHBUTTON,
308 iState) )
309 {
310 wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn);
311 }
312
313 // draw background
314 wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState,
315 &rectBtn, NULL);
316
317 // calculate content area margins
318 MARGINS margins;
319 wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState,
320 TMT_CONTENTMARGINS, &rectBtn, &margins);
321 RECT rectClient;
322 ::CopyRect(&rectClient, &rectBtn);
323 ::InflateRect(&rectClient, -margins.cxLeftWidth, -margins.cyTopHeight);
324
325 // if focused and !nofocus rect
326 if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) )
327 {
328 DrawFocusRect(hdc, &rectClient);
329 }
330
331 if ( button->UseBgCol() )
332 {
333 COLORREF colBg = wxColourToRGB(button->GetBackgroundColour());
334 HBRUSH hbrushBackground = ::CreateSolidBrush(colBg);
335
336 // don't overwrite the focus rect
337 ::InflateRect(&rectClient, -1, -1);
338 FillRect(hdc, &rectClient, hbrushBackground);
339 ::DeleteObject(hbrushBackground);
340 }
341}
342#endif // wxUSE_UXTHEME
343
f6bcfd97
BP
344// VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN
345#define FOCUS_MARGIN 3
346
2bda0e17
KB
347bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT *item)
348{
4676948b 349#ifndef __WXWINCE__
ba681060 350 long style = GetWindowLong((HWND) GetHWND(), GWL_STYLE);
fd3f686c
VZ
351 if (style & BS_BITMAP)
352 {
fd3f686c
VZ
353 // Let default procedure draw the bitmap, which is defined
354 // in the Windows resource.
a265d21a 355 return false;
fd3f686c 356 }
2bda0e17
KB
357#endif
358
359 LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) item;
47e92c41
GRG
360 HDC hDC = lpDIS->hDC;
361 UINT state = lpDIS->itemState;
362 bool isSelected = (state & ODS_SELECTED) != 0;
363 bool autoDraw = (GetWindowStyleFlag() & wxBU_AUTODRAW) != 0;
2bda0e17 364
47e92c41
GRG
365
366 // choose the bitmap to use depending on the button state
1fdc16ad 367 wxBitmap *bitmap;
2bda0e17 368
1e6feb95
VZ
369 if ( isSelected && m_bmpSelected.Ok() )
370 bitmap = &m_bmpSelected;
1fdc16ad
VZ
371 else if ( m_bmpHover.Ok() && IsMouseInWindow() )
372 bitmap = &m_bmpHover;
1e6feb95
VZ
373 else if ((state & ODS_FOCUS) && m_bmpFocus.Ok())
374 bitmap = &m_bmpFocus;
375 else if ((state & ODS_DISABLED) && m_bmpDisabled.Ok())
376 bitmap = &m_bmpDisabled;
d9c8e68e 377 else
1e6feb95 378 bitmap = &m_bmpNormal;
2bda0e17 379
42e69d6b 380 if ( !bitmap->Ok() )
a265d21a 381 return false;
2bda0e17 382
47e92c41
GRG
383 // centre the bitmap in the control area
384 int x = lpDIS->rcItem.left;
385 int y = lpDIS->rcItem.top;
386 int width = lpDIS->rcItem.right - x;
387 int height = lpDIS->rcItem.bottom - y;
388 int wBmp = bitmap->GetWidth();
389 int hBmp = bitmap->GetHeight();
f6bcfd97 390
4e9da8b7
RD
391#if wxUSE_UXTHEME
392 if ( autoDraw && wxUxThemeEngine::GetIfActive() )
393 {
394 MSWDrawXPBackground(this, item);
395 wxUxThemeHandle theme(this, L"BUTTON");
396
397 // calculate content area margins
398 // assuming here that each state is the same size
399 MARGINS margins;
400 wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL,
401 BP_PUSHBUTTON, PBS_NORMAL,
402 TMT_CONTENTMARGINS, NULL,
403 &margins);
404 int marginX = margins.cxLeftWidth + 1;
405 int marginY = margins.cyTopHeight + 1;
406 int x1,y1;
407
408 if ( m_windowStyle & wxBU_LEFT )
409 {
410 x1 = x + marginX;
411 }
412 else if ( m_windowStyle & wxBU_RIGHT )
413 {
414 x1 = x + (width - wBmp) - marginX;
415 }
416 else
417 {
418 x1 = x + (width - wBmp) / 2;
419 }
420
421 if ( m_windowStyle & wxBU_TOP )
422 {
423 y1 = y + marginY;
424 }
425 else if ( m_windowStyle & wxBU_BOTTOM )
426 {
427 y1 = y + (height - hBmp) - marginY;
428 }
429 else
430 {
431 y1 = y + (height - hBmp) / 2;
432 }
433
434 // draw the bitmap
71c1dbbd 435 wxDCTemp dst((WXHDC)hDC);
4e9da8b7
RD
436 dst.DrawBitmap(*bitmap, x1, y1, true);
437
438 return true;
439 }
440#endif // wxUSE_UXTHEME
441
a265d21a
DS
442 int x1,y1;
443
f6bcfd97
BP
444 if(m_windowStyle & wxBU_LEFT)
445 x1 = x + (FOCUS_MARGIN+1);
446 else if(m_windowStyle & wxBU_RIGHT)
447 x1 = x + (width - wBmp) - (FOCUS_MARGIN+1);
448 else
449 x1 = x + (width - wBmp) / 2;
450
451 if(m_windowStyle & wxBU_TOP)
452 y1 = y + (FOCUS_MARGIN+1);
453 else if(m_windowStyle & wxBU_BOTTOM)
454 y1 = y + (height - hBmp) - (FOCUS_MARGIN+1);
455 else
456 y1 = y + (height - hBmp) / 2;
2bda0e17 457
47e92c41 458 if ( isSelected && autoDraw )
d9c8e68e 459 {
47e92c41
GRG
460 x1++;
461 y1++;
d9c8e68e 462 }
2bda0e17 463
47e92c41 464 // draw the face, if auto-drawing
d9c8e68e
VZ
465 if ( autoDraw )
466 {
467 DrawFace((WXHDC) hDC,
468 lpDIS->rcItem.left, lpDIS->rcItem.top,
469 lpDIS->rcItem.right, lpDIS->rcItem.bottom,
470 isSelected);
471 }
2bda0e17 472
47e92c41 473 // draw the bitmap
7d09b97f 474 wxDCTemp dst((WXHDC)hDC);
a265d21a 475 dst.DrawBitmap(*bitmap, x1, y1, true);
33ac7e6f 476
47e92c41 477 // draw focus / disabled state, if auto-drawing
d9c8e68e
VZ
478 if ( (state & ODS_DISABLED) && autoDraw )
479 {
480 DrawButtonDisable((WXHDC) hDC,
481 lpDIS->rcItem.left, lpDIS->rcItem.top,
482 lpDIS->rcItem.right, lpDIS->rcItem.bottom,
a265d21a 483 true);
d9c8e68e
VZ
484 }
485 else if ( (state & ODS_FOCUS) && autoDraw )
486 {
487 DrawButtonFocus((WXHDC) hDC,
488 lpDIS->rcItem.left,
489 lpDIS->rcItem.top,
490 lpDIS->rcItem.right,
491 lpDIS->rcItem.bottom,
492 isSelected);
493 }
2bda0e17 494
a265d21a 495 return true;
2bda0e17
KB
496}
497
5ab1fa8e
GRG
498// GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF
499
a265d21a
DS
500void wxBitmapButton::DrawFace( WXHDC dc, int left, int top,
501 int right, int bottom, bool sel )
2bda0e17 502{
d9c8e68e 503 HPEN oldp;
5ab1fa8e 504 HPEN penHiLight;
d9c8e68e
VZ
505 HPEN penLight;
506 HPEN penShadow;
5ab1fa8e 507 HPEN penDkShadow;
d9c8e68e 508 HBRUSH brushFace;
2bda0e17 509
5ab1fa8e
GRG
510 // create needed pens and brush
511 penHiLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DHILIGHT));
512 penLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT));
513 penShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DSHADOW));
514 penDkShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW));
4e9da8b7 515 brushFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
5ab1fa8e
GRG
516
517 // draw the rectangle
518 RECT rect;
519 rect.left = left;
520 rect.right = right;
521 rect.top = top;
522 rect.bottom = bottom;
523 FillRect((HDC) dc, &rect, brushFace);
524
525 // draw the border
526 oldp = (HPEN) SelectObject( (HDC) dc, sel? penDkShadow : penHiLight);
4676948b
JS
527
528 wxDrawLine((HDC) dc, left, top, right-1, top);
529 wxDrawLine((HDC) dc, left, top+1, left, bottom-1);
5ab1fa8e
GRG
530
531 SelectObject( (HDC) dc, sel? penShadow : penLight);
4676948b
JS
532 wxDrawLine((HDC) dc, left+1, top+1, right-2, top+1);
533 wxDrawLine((HDC) dc, left+1, top+2, left+1, bottom-2);
5ab1fa8e
GRG
534
535 SelectObject( (HDC) dc, sel? penLight : penShadow);
4676948b
JS
536 wxDrawLine((HDC) dc, left+1, bottom-2, right-1, bottom-2);
537 wxDrawLine((HDC) dc, right-2, bottom-3, right-2, top);
5ab1fa8e
GRG
538
539 SelectObject( (HDC) dc, sel? penHiLight : penDkShadow);
4676948b
JS
540 wxDrawLine((HDC) dc, left, bottom-1, right+2, bottom-1);
541 wxDrawLine((HDC) dc, right-1, bottom-2, right-1, top-1);
5ab1fa8e
GRG
542
543 // delete allocated resources
544 SelectObject((HDC) dc,oldp);
545 DeleteObject(penHiLight);
546 DeleteObject(penLight);
547 DeleteObject(penShadow);
548 DeleteObject(penDkShadow);
549 DeleteObject(brushFace);
550}
551
a265d21a
DS
552void wxBitmapButton::DrawButtonFocus( WXHDC dc, int left, int top, int right,
553 int bottom, bool WXUNUSED(sel) )
2bda0e17 554{
fd3f686c
VZ
555 RECT rect;
556 rect.left = left;
557 rect.top = top;
558 rect.right = right;
559 rect.bottom = bottom;
5ab1fa8e
GRG
560 InflateRect( &rect, - FOCUS_MARGIN, - FOCUS_MARGIN );
561
562 // GRG: the focus rectangle should not move when the button is pushed!
563/*
fd3f686c 564 if ( sel )
5ab1fa8e
GRG
565 OffsetRect( &rect, 1, 1 );
566*/
a265d21a 567
5ab1fa8e 568 DrawFocusRect( (HDC) dc, &rect );
2bda0e17
KB
569}
570
d50dbf7c
VZ
571void
572wxBitmapButton::DrawButtonDisable( WXHDC dc,
573 int left, int top, int right, int bottom,
574 bool with_marg )
2bda0e17 575{
d50dbf7c
VZ
576 if ( !m_brushDisabled.Ok() )
577 {
578 // draw a bitmap with two black and two background colour pixels
579 wxBitmap bmp(2, 2);
580 wxMemoryDC dc;
581 dc.SelectObject(bmp);
582 dc.SetPen(*wxBLACK_PEN);
583 dc.DrawPoint(0, 0);
584 dc.DrawPoint(1, 1);
585 dc.SetPen(GetBackgroundColour());
586 dc.DrawPoint(0, 1);
587 dc.DrawPoint(1, 0);
588
589 m_brushDisabled = wxBrush(bmp);
590 }
591
592 SelectInHDC selectBrush((HDC)dc, GetHbrushOf(m_brushDisabled));
2bda0e17 593
2b268535
VZ
594 // ROP for "dest |= pattern" operation -- as it doesn't have a standard
595 // name, give it our own
a265d21a 596 static const DWORD PATTERNPAINT = 0xFA0089UL;
d9c8e68e
VZ
597
598 if ( with_marg )
599 {
600 left += m_marginX;
601 top += m_marginY;
602 right -= 2 * m_marginX;
603 bottom -= 2 * m_marginY;
604 }
605
a265d21a 606 ::PatBlt( (HDC) dc, left, top, right, bottom, PATTERNPAINT);
2bda0e17
KB
607}
608
c046274e
RD
609wxSize wxBitmapButton::DoGetBestSize() const
610{
9266e0ec 611 if ( m_bmpNormal.Ok() )
c046274e 612 {
d381e983
VZ
613 int width = m_bmpNormal.GetWidth(),
614 height = m_bmpNormal.GetHeight();
615 int marginH = 0,
616 marginV = 0;
617
4e9da8b7 618#if wxUSE_UXTHEME
0d1c8f39 619 if ( wxUxThemeEngine::GetIfActive() )
4e9da8b7
RD
620 {
621 wxUxThemeHandle theme((wxBitmapButton *)this, L"BUTTON");
622
4e9da8b7
RD
623 MARGINS margins;
624 wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL,
625 BP_PUSHBUTTON, PBS_NORMAL,
626 TMT_CONTENTMARGINS, NULL,
627 &margins);
0d1c8f39 628
9d1b7527
JG
629 // XP doesn't draw themed buttons correctly when the client area is
630 // smaller than 8x8 - enforce this minimum size for small bitmaps
d381e983
VZ
631 if ( width < 8 )
632 width = 8;
633 if ( height < 8 )
634 height = 8;
635
636 // don't add margins for the borderless buttons, they don't need
637 // them and it just makes them appear larger than needed
638 if ( !HasFlag(wxBORDER_NONE) )
639 {
aceeebce
VZ
640 // we need 2 extra pixels for the focus rectangle, without them
641 // it's overwritten by the bitmap itself
642 marginH = margins.cxLeftWidth + margins.cxRightWidth + 2;
643 marginV = margins.cyTopHeight + margins.cyBottomHeight + 2;
d381e983 644 }
4e9da8b7 645 }
d381e983 646 else
4e9da8b7 647#endif // wxUSE_UXTHEME
d381e983
VZ
648 {
649 if ( !HasFlag(wxBORDER_NONE) )
650 {
651 marginH = 2*m_marginX;
652 marginV = 2*m_marginY;
653 }
654 }
4e9da8b7 655
d381e983 656 wxSize best(width + marginH, height + marginV);
31582e4e
RD
657 CacheBestSize(best);
658 return best;
c046274e 659 }
e8153940 660
9266e0ec
VZ
661 // no idea what our best size should be, defer to the base class
662 return wxBitmapButtonBase::DoGetBestSize();
c046274e
RD
663}
664
1e6feb95 665#endif // wxUSE_BMPBUTTON