]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/bmpbuttn.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/bmpbuttn.cpp 
   3 // Purpose:     wxBitmapButton 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  21 #include "wx/bmpbuttn.h" 
  25     #include "wx/dcmemory.h" 
  29 #include "wx/msw/private.h" 
  30 #include "wx/msw/dc.h"          // for wxDCTemp 
  32 #include "wx/msw/uxtheme.h" 
  35     // no need to include tmschema.h 
  37         #define BP_PUSHBUTTON 1 
  42         #define PBS_DISABLED  4 
  43         #define PBS_DEFAULTED 5 
  45         #define TMT_CONTENTMARGINS 3602 
  47 #endif // wxUSE_UXTHEME 
  49 #ifndef ODS_NOFOCUSRECT 
  50     #define ODS_NOFOCUSRECT     0x0200 
  53 // ---------------------------------------------------------------------------- 
  55 // ---------------------------------------------------------------------------- 
  57 #if wxUSE_EXTENDED_RTTI 
  59 WX_DEFINE_FLAGS( wxBitmapButtonStyle 
) 
  61 wxBEGIN_FLAGS( wxBitmapButtonStyle 
) 
  62     // new style border flags, we put them first to 
  63     // use them for streaming out 
  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
) 
  71     // old style border flags 
  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
) 
  77     wxFLAGS_MEMBER(wxBORDER
) 
  79     // standard window styles 
  80     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
  81     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
  82     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
  83     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
  84     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
  85     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
  86     wxFLAGS_MEMBER(wxVSCROLL
) 
  87     wxFLAGS_MEMBER(wxHSCROLL
) 
  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
) 
  94 wxEND_FLAGS( wxBitmapButtonStyle 
) 
  96 IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton
, wxButton
,"wx/bmpbuttn.h") 
  98 wxBEGIN_PROPERTIES_TABLE(wxBitmapButton
) 
  99     wxPROPERTY_FLAGS( WindowStyle 
, wxBitmapButtonStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 100 wxEND_PROPERTIES_TABLE() 
 102 wxBEGIN_HANDLERS_TABLE(wxBitmapButton
) 
 103 wxEND_HANDLERS_TABLE() 
 105 wxCONSTRUCTOR_5( wxBitmapButton 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxBitmap 
, Bitmap 
, wxPoint 
, Position 
, wxSize 
, Size 
) 
 108 IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton
, wxButton
) 
 111 BEGIN_EVENT_TABLE(wxBitmapButton
, wxBitmapButtonBase
) 
 112     EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged
) 
 113     EVT_ENTER_WINDOW(wxBitmapButton::OnMouseEnterOrLeave
) 
 114     EVT_LEAVE_WINDOW(wxBitmapButton::OnMouseEnterOrLeave
) 
 120 long "style" , wxBU_AUTODRAW 
 127 bool wxBitmapButton::Create(wxWindow 
*parent
, 
 129                             const wxBitmap
& bitmap
, 
 131                             const wxSize
& size
, long style
, 
 132                             const wxValidator
& wxVALIDATOR_PARAM(validator
), 
 133                             const wxString
& name
) 
 135     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 138     SetBitmapLabel(bitmap
); 
 140     if ( style 
& wxBU_AUTODRAW 
) 
 143     return MSWCreateControl(_T("BUTTON"), wxEmptyString
, pos
, size
); 
 146 WXDWORD 
wxBitmapButton::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 148     WXDWORD msStyle 
= wxButton::MSWGetStyle(style
, exstyle
); 
 150     msStyle 
|= BS_OWNERDRAW
; 
 152     if ( style 
& wxBU_LEFT 
) 
 154     if ( style 
& wxBU_RIGHT 
) 
 156     if ( style 
& wxBU_TOP 
) 
 158     if ( style 
& wxBU_BOTTOM 
) 
 159         msStyle 
|= BS_BOTTOM
; 
 164 bool wxBitmapButton::SetBackgroundColour(const wxColour
& colour
) 
 166     if ( !wxBitmapButtonBase::SetBackgroundColour(colour
) ) 
 172     // invalidate the brush, it will be recreated the next time it's needed 
 173     m_brushDisabled 
= wxNullBrush
; 
 178 void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
 180     m_brushDisabled 
= wxNullBrush
; 
 184         // this change affects our current state 
 191 void wxBitmapButton::OnMouseEnterOrLeave(wxMouseEvent
& event
) 
 193     if ( IsEnabled() && m_bmpHover
.Ok() ) 
 199 void wxBitmapButton::SetBitmapLabel(const wxBitmap
& bitmap
) 
 202     if ( !HasFlag(wxBU_AUTODRAW
) && !m_disabledSetByUser 
&& bitmap
.IsOk() ) 
 204         m_bmpDisabled 
= wxBitmap(bitmap
.ConvertToImage().ConvertToGreyscale()); 
 206 #endif // wxUSE_IMAGE 
 208     wxBitmapButtonBase::SetBitmapLabel(bitmap
); 
 211 void wxBitmapButton::SetBitmapFocus(const wxBitmap
& focus
) 
 213     // if the focus bitmap is specified but hover one isn't, use the focus 
 214     // bitmap for hovering as well if this is consistent with the current 
 215     // Windows version look and feel 
 217     // rationale: this is compatible with the old wxGTK behaviour and also 
 218     // makes it much easier to do "the right thing" for all platforms (some of 
 219     // them, such as Windows XP, have "hot" buttons while others don't) 
 220     if ( focus
.Ok() && !m_hoverSetByUser 
) 
 221         m_bmpHover 
= m_bmpFocus
; 
 223     wxBitmapButtonBase::SetBitmapFocus(focus
); 
 226 void wxBitmapButton::SetBitmapDisabled(const wxBitmap
& disabled
) 
 228     if ( disabled
.IsOk() ) 
 229         m_disabledSetByUser 
= true; 
 231     wxBitmapButtonBase::SetBitmapDisabled(disabled
); 
 234 void wxBitmapButton::SetBitmapHover(const wxBitmap
& hover
) 
 237         m_hoverSetByUser 
= true; 
 239     wxBitmapButtonBase::SetBitmapHover(hover
); 
 244 void MSWDrawXPBackground(wxButton 
*button
, WXDRAWITEMSTRUCT 
*wxdis
) 
 246     LPDRAWITEMSTRUCT lpDIS 
= (LPDRAWITEMSTRUCT
)wxdis
; 
 247     HDC hdc 
= lpDIS
->hDC
; 
 248     UINT state 
= lpDIS
->itemState
; 
 250     CopyRect(&rectBtn
, &lpDIS
->rcItem
); 
 252     wxUxThemeHandle 
theme(button
, L
"BUTTON"); 
 255     if ( state 
& ODS_SELECTED 
) 
 257         iState 
= PBS_PRESSED
; 
 259     else if ( button
->HasCapture() || button
->IsMouseInWindow() ) 
 263     else if ( state 
& ODS_FOCUS 
) 
 265         iState 
= PBS_DEFAULTED
; 
 267     else if ( state 
& ODS_DISABLED 
) 
 269         iState 
= PBS_DISABLED
; 
 276     // draw parent background if needed 
 277     if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme
, 
 281         wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button
), hdc
, &rectBtn
); 
 285     wxUxThemeEngine::Get()->DrawThemeBackground(theme
, hdc
, BP_PUSHBUTTON
, iState
, 
 288     // calculate content area margins 
 290     wxUxThemeEngine::Get()->GetThemeMargins(theme
, hdc
, BP_PUSHBUTTON
, iState
, 
 291                                             TMT_CONTENTMARGINS
, &rectBtn
, &margins
); 
 293     ::CopyRect(&rectClient
, &rectBtn
); 
 294     ::InflateRect(&rectClient
, -margins
.cxLeftWidth
, -margins
.cyTopHeight
); 
 296     // if focused and !nofocus rect 
 297     if ( (state 
& ODS_FOCUS
) && !(state 
& ODS_NOFOCUSRECT
) ) 
 299         DrawFocusRect(hdc
, &rectClient
); 
 302     if ( button
->UseBgCol() ) 
 304         COLORREF colBg 
= wxColourToRGB(button
->GetBackgroundColour()); 
 305         HBRUSH hbrushBackground 
= ::CreateSolidBrush(colBg
); 
 307         // don't overwrite the focus rect 
 308         ::InflateRect(&rectClient
, -1, -1); 
 309         FillRect(hdc
, &rectClient
, hbrushBackground
); 
 310         ::DeleteObject(hbrushBackground
); 
 313 #endif // wxUSE_UXTHEME 
 315 // VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN 
 316 #define FOCUS_MARGIN 3 
 318 bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT 
*item
) 
 321     long style 
= GetWindowLong((HWND
) GetHWND(), GWL_STYLE
); 
 322     if (style 
& BS_BITMAP
) 
 324         // Let default procedure draw the bitmap, which is defined 
 325         // in the Windows resource. 
 330     LPDRAWITEMSTRUCT lpDIS 
= (LPDRAWITEMSTRUCT
) item
; 
 331     HDC hDC                
= lpDIS
->hDC
; 
 332     UINT state             
= lpDIS
->itemState
; 
 333     bool isSelected        
= (state 
& ODS_SELECTED
) != 0; 
 334     bool autoDraw          
= (GetWindowStyleFlag() & wxBU_AUTODRAW
) != 0; 
 337     // choose the bitmap to use depending on the button state 
 340     if ( isSelected 
&& m_bmpSelected
.Ok() ) 
 341         bitmap 
= &m_bmpSelected
; 
 342     else if ( m_bmpHover
.Ok() && IsMouseInWindow() ) 
 343         bitmap 
= &m_bmpHover
; 
 344     else if ((state 
& ODS_FOCUS
) && m_bmpFocus
.Ok()) 
 345         bitmap 
= &m_bmpFocus
; 
 346     else if ((state 
& ODS_DISABLED
) && m_bmpDisabled
.Ok()) 
 347         bitmap 
= &m_bmpDisabled
; 
 349         bitmap 
= &m_bmpNormal
; 
 354     // centre the bitmap in the control area 
 355     int x      
= lpDIS
->rcItem
.left
; 
 356     int y      
= lpDIS
->rcItem
.top
; 
 357     int width  
= lpDIS
->rcItem
.right 
- x
; 
 358     int height 
= lpDIS
->rcItem
.bottom 
- y
; 
 359     int wBmp   
= bitmap
->GetWidth(); 
 360     int hBmp   
= bitmap
->GetHeight(); 
 363     if ( autoDraw 
&& wxUxThemeEngine::GetIfActive() ) 
 365         MSWDrawXPBackground(this, item
); 
 366         wxUxThemeHandle 
theme(this, L
"BUTTON"); 
 368         // calculate content area margins 
 369         // assuming here that each state is the same size 
 371         wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
, 
 372                                                 BP_PUSHBUTTON
, PBS_NORMAL
, 
 373                                                 TMT_CONTENTMARGINS
, NULL
, 
 375         int marginX 
= margins
.cxLeftWidth 
+ 1; 
 376         int marginY 
= margins
.cyTopHeight 
+ 1; 
 379         if ( m_windowStyle 
& wxBU_LEFT 
) 
 383         else if ( m_windowStyle 
& wxBU_RIGHT 
) 
 385             x1 
= x 
+ (width 
- wBmp
) - marginX
; 
 389             x1 
= x 
+ (width 
- wBmp
) / 2; 
 392         if ( m_windowStyle 
& wxBU_TOP 
) 
 396         else if ( m_windowStyle 
& wxBU_BOTTOM 
) 
 398             y1 
= y 
+ (height 
- hBmp
) - marginY
; 
 402             y1 
= y 
+ (height 
- hBmp
) / 2; 
 406         wxDCTemp 
dst((WXHDC
)hDC
); 
 407         dst
.DrawBitmap(*bitmap
, x1
, y1
, true); 
 411 #endif // wxUSE_UXTHEME 
 415     if(m_windowStyle 
& wxBU_LEFT
) 
 416         x1 
= x 
+ (FOCUS_MARGIN
+1); 
 417     else if(m_windowStyle 
& wxBU_RIGHT
) 
 418         x1 
= x 
+ (width 
- wBmp
) - (FOCUS_MARGIN
+1); 
 420         x1 
= x 
+ (width 
- wBmp
) / 2; 
 422     if(m_windowStyle 
& wxBU_TOP
) 
 423         y1 
= y 
+ (FOCUS_MARGIN
+1); 
 424     else if(m_windowStyle 
& wxBU_BOTTOM
) 
 425         y1 
= y 
+ (height 
- hBmp
) - (FOCUS_MARGIN
+1); 
 427         y1 
= y 
+ (height 
- hBmp
) / 2; 
 429     if ( isSelected 
&& autoDraw 
) 
 435     // draw the face, if auto-drawing 
 438         DrawFace((WXHDC
) hDC
, 
 439                  lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
, 
 440                  lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
, 
 445     wxDCTemp 
dst((WXHDC
)hDC
); 
 446     dst
.DrawBitmap(*bitmap
, x1
, y1
, true); 
 448     // draw focus / disabled state, if auto-drawing 
 449     if ( (state 
& ODS_DISABLED
) && autoDraw 
) 
 451         DrawButtonDisable((WXHDC
) hDC
, 
 452                           lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
, 
 453                           lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
, 
 456     else if ( (state 
& ODS_FOCUS
) && autoDraw 
) 
 458         DrawButtonFocus((WXHDC
) hDC
, 
 462                         lpDIS
->rcItem
.bottom
, 
 469 // GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF 
 471 void wxBitmapButton::DrawFace( WXHDC dc
, int left
, int top
, 
 472     int right
, int bottom
, bool sel 
) 
 481     // create needed pens and brush 
 482     penHiLight  
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DHILIGHT
)); 
 483     penLight    
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DLIGHT
)); 
 484     penShadow   
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DSHADOW
)); 
 485     penDkShadow 
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DDKSHADOW
)); 
 486     brushFace   
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
)); 
 488     // draw the rectangle 
 493     rect
.bottom 
= bottom
; 
 494     FillRect((HDC
) dc
, &rect
, brushFace
); 
 497     oldp 
= (HPEN
) SelectObject( (HDC
) dc
, sel
? penDkShadow 
: penHiLight
); 
 499     wxDrawLine((HDC
) dc
, left
, top
, right
-1, top
); 
 500     wxDrawLine((HDC
) dc
, left
, top
+1, left
, bottom
-1); 
 502     SelectObject( (HDC
) dc
, sel
? penShadow 
: penLight
); 
 503     wxDrawLine((HDC
) dc
, left
+1, top
+1, right
-2, top
+1); 
 504     wxDrawLine((HDC
) dc
, left
+1, top
+2, left
+1, bottom
-2); 
 506     SelectObject( (HDC
) dc
, sel
? penLight 
: penShadow
); 
 507     wxDrawLine((HDC
) dc
, left
+1, bottom
-2, right
-1, bottom
-2); 
 508     wxDrawLine((HDC
) dc
, right
-2, bottom
-3, right
-2, top
); 
 510     SelectObject( (HDC
) dc
, sel
? penHiLight 
: penDkShadow
); 
 511     wxDrawLine((HDC
) dc
, left
, bottom
-1, right
+2, bottom
-1); 
 512     wxDrawLine((HDC
) dc
, right
-1, bottom
-2, right
-1, top
-1); 
 514     // delete allocated resources 
 515     SelectObject((HDC
) dc
,oldp
); 
 516     DeleteObject(penHiLight
); 
 517     DeleteObject(penLight
); 
 518     DeleteObject(penShadow
); 
 519     DeleteObject(penDkShadow
); 
 520     DeleteObject(brushFace
); 
 523 void wxBitmapButton::DrawButtonFocus( WXHDC dc
, int left
, int top
, int right
, 
 524     int bottom
, bool WXUNUSED(sel
) ) 
 530     rect
.bottom 
= bottom
; 
 531     InflateRect( &rect
, - FOCUS_MARGIN
, - FOCUS_MARGIN 
); 
 533     // GRG: the focus rectangle should not move when the button is pushed! 
 536         OffsetRect( &rect, 1, 1 ); 
 539     DrawFocusRect( (HDC
) dc
, &rect 
); 
 543 wxBitmapButton::DrawButtonDisable( WXHDC dc
, 
 544                                    int left
, int top
, int right
, int bottom
, 
 547     if ( !m_brushDisabled
.Ok() ) 
 549         // draw a bitmap with two black and two background colour pixels 
 552         dc
.SelectObject(bmp
); 
 553         dc
.SetPen(*wxBLACK_PEN
); 
 556         dc
.SetPen(GetBackgroundColour()); 
 560         m_brushDisabled 
= wxBrush(bmp
); 
 563     SelectInHDC 
selectBrush((HDC
)dc
, GetHbrushOf(m_brushDisabled
)); 
 565     // ROP for "dest |= pattern" operation -- as it doesn't have a standard 
 566     // name, give it our own 
 567     static const DWORD PATTERNPAINT 
= 0xFA0089UL
; 
 573         right 
-= 2 * m_marginX
; 
 574         bottom 
-= 2 * m_marginY
; 
 577     ::PatBlt( (HDC
) dc
, left
, top
, right
, bottom
, PATTERNPAINT
); 
 580 wxSize 
wxBitmapButton::DoGetBestSize() const 
 582     if ( m_bmpNormal
.Ok() ) 
 584         int width 
= m_bmpNormal
.GetWidth(), 
 585             height 
= m_bmpNormal
.GetHeight(); 
 590         if ( wxUxThemeEngine::GetIfActive() ) 
 592             wxUxThemeHandle 
theme((wxBitmapButton 
*)this, L
"BUTTON"); 
 595             wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
, 
 596                                                     BP_PUSHBUTTON
, PBS_NORMAL
, 
 597                                                     TMT_CONTENTMARGINS
, NULL
, 
 600             // XP doesn't draw themed buttons correctly when the client area is 
 601             // smaller than 8x8 - enforce this minimum size for small bitmaps 
 607             // don't add margins for the borderless buttons, they don't need 
 608             // them and it just makes them appear larger than needed 
 609             if ( !HasFlag(wxBORDER_NONE
) ) 
 611                 // we need 2 extra pixels for the focus rectangle, without them 
 612                 // it's overwritten by the bitmap itself 
 613                 marginH 
= margins
.cxLeftWidth 
+ margins
.cxRightWidth 
+ 2; 
 614                 marginV 
= margins
.cyTopHeight 
+ margins
.cyBottomHeight 
+ 2; 
 618 #endif // wxUSE_UXTHEME 
 620             if ( !HasFlag(wxBORDER_NONE
) ) 
 622                 marginH 
= 2*m_marginX
; 
 623                 marginV 
= 2*m_marginY
; 
 627         wxSize 
best(width 
+ marginH
, height 
+ marginV
); 
 632     // no idea what our best size should be, defer to the base class 
 633     return wxBitmapButtonBase::DoGetBestSize(); 
 636 #endif // wxUSE_BMPBUTTON