1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxNewBitmapButton enhanced bitmap button class.
4 // Author: Aleksandras Gluchovas
8 // Copyright: (c) Aleksandras Gluchovas
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "newbmpbtn.h"
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/fl/newbmpbtn.h"
28 #include "wx/utils.h" // import wxMin,wxMax macros
31 #include "wx/msw/private.h"
34 ///////////// button-label rendering helpers //////////////////
36 static int* create_array( int width
, int height
, int fill
= 0 )
38 int* array
= new int[width
*height
];
40 int len
= width
*height
;
42 for ( i
= 0; i
!= len
; ++i
)
48 #define GET_ELEM(array,x,y) (array[width*(y)+(x)])
50 #define MIN_COLOR_DIFF 10
52 #define IS_IN_ARRAY(x,y) ( (x) < width && (y) < height && (x) >= 0 && (y) >= 0 )
54 #define GET_RED(col) col & 0xFF
55 #define GET_GREEN(col) (col >> 8) & 0xFF
56 #define GET_BLUE(col) (col >> 16) & 0xFF
58 #define MAKE_INT_COLOR(red,green,blue) ( (red) | \
59 ( ( (green) << 8 ) & 0xFF00 ) | \
60 ( ( (blue) << 16) & 0xFF0000) \
63 #define IS_GREATER(col1,col2) ( ( (GET_RED(col1) ) > (GET_RED(col2) ) + MIN_COLOR_DIFF ) && \
64 ( (GET_GREEN(col1)) > (GET_GREEN(col2)) + MIN_COLOR_DIFF ) && \
65 ( (GET_BLUE(col1) ) > (GET_BLUE(col2) ) + MIN_COLOR_DIFF ) \
72 // helper function, used internally
74 static void gray_out_pixmap( int* src
, int* dest
, int width
, int height
)
76 // assuming the pixels along the edges are of the background color
83 int cur
= GET_ELEM(src
,x
,y
);
86 if ( IS_IN_ARRAY(x
-1,y
-1) )
88 int upperElem
= GET_ELEM(src
,x
-1,y
-1);
90 // if the upper element is lighter than current
91 if ( IS_GREATER(upperElem
,cur
) )
93 GET_ELEM(dest
,x
,y
) = MASK_DARK
;
96 // if the current element is ligher than the upper
97 if ( IS_GREATER(cur
,upperElem
) )
99 GET_ELEM(dest
,x
,y
) = MASK_LIGHT
;
103 if ( GET_ELEM(dest
,x
-1,y
-1) == MASK_LIGHT
)
105 GET_ELEM(dest
,x
,y
) = MASK_BG
;
107 if ( GET_ELEM(dest
,x
-1,y
-1 ) == MASK_DARK
)
109 GET_ELEM(dest
,x
,y
) = MASK_DARK
;
111 GET_ELEM(dest
,x
,y
) = MASK_BG
;
117 if ( IS_IN_ARRAY(x
+1,y
-1) )
124 while ( IS_IN_ARRAY(x
-1,y
+1) )
130 if ( IS_IN_ARRAY(x
,y
+1) )
137 if ( IS_IN_ARRAY(x
+1,y
) )
149 // algorithm for making the image look "grayed" (e.g. disabled button)
150 // NOTE:: used GetPixel(), which is Windows-Only!
152 void gray_out_image_on_dc( wxDC
& dc
, int width
, int height
)
154 // assuming the pixels along the edges are of the background color
156 dc
.GetPixel( 0, 0, &bgCol
);
158 wxPen
darkPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
),1, wxSOLID
);
159 wxPen
lightPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
),1, wxSOLID
);
160 wxPen
bgPen ( bgCol
, 1, wxSOLID
);
162 int* src
= create_array( width
, height
, MASK_BG
);
163 int* dest
= create_array( width
, height
, MASK_BG
);
166 for ( y
= 0; y
!= height
; ++y
)
168 for ( x
= 0; x
!= width
; ++x
)
171 dc
.GetPixel( x
,y
, &col
);
173 GET_ELEM(src
,x
,y
) = MAKE_INT_COLOR( col
.Red(), col
.Green(), col
.Blue() );
176 gray_out_pixmap( src
, dest
, width
, height
);
178 for ( y
= 0; y
!= height
; ++y
)
180 for ( x
= 0; x
!= width
; ++x
)
182 int mask
= GET_ELEM(dest
,x
,y
);
186 case MASK_BG
: { dc
.SetPen( bgPen
);
187 dc
.DrawPoint( x
,y
); break;
189 case MASK_DARK
: { dc
.SetPen( darkPen
);
190 dc
.DrawPoint( x
,y
); break;
192 case MASK_LIGHT
: { dc
.SetPen( lightPen
);
193 dc
.DrawPoint( x
,y
); break;
203 ///////////////////////////////
205 /***** Implementation for class wxNewBitmapButton *****/
207 IMPLEMENT_DYNAMIC_CLASS(wxNewBitmapButton
, wxPanel
)
209 BEGIN_EVENT_TABLE( wxNewBitmapButton
, wxPanel
)
211 EVT_LEFT_DOWN ( wxNewBitmapButton::OnLButtonDown
)
212 EVT_LEFT_UP ( wxNewBitmapButton::OnLButtonUp
)
213 EVT_LEFT_DCLICK ( wxNewBitmapButton::OnLButtonDClick
)
214 EVT_ENTER_WINDOW( wxNewBitmapButton::OnMouseEnter
)
215 EVT_LEAVE_WINDOW( wxNewBitmapButton::OnMouseLeave
)
217 EVT_SIZE ( wxNewBitmapButton::OnSize
)
218 EVT_PAINT( wxNewBitmapButton::OnPaint
)
220 //EVT_KILL_FOCUS( wxNewBitmapButton::OnKillFocus )
222 EVT_ERASE_BACKGROUND( wxNewBitmapButton::OnEraseBackground
)
226 wxNewBitmapButton::wxNewBitmapButton( const wxBitmap
& labelBitmap
,
227 const wxString
& labelText
,
235 : mTextToLabelGap ( textToLabelGap
),
238 mTextAlignment( alignText
),
239 mIsSticky( isSticky
),
241 mLabelText( labelText
),
242 mImageFileType( wxBITMAP_TYPE_INVALID
),
243 mDepressedBmp( labelBitmap
),
245 mpDepressedImg( NULL
),
246 mpPressedImg ( NULL
),
247 mpDisabledImg ( NULL
),
248 mpFocusedImg ( NULL
),
251 mDragStarted ( FALSE
),
252 mIsPressed ( FALSE
),
254 mHasFocusedBmp( FALSE
),
255 mFiredEventType( firedEventType
),
257 mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID
),
258 mDarkPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
), 1, wxSOLID
),
259 mGrayPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
), 1, wxSOLID
),
260 mLightPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
), 1, wxSOLID
),
268 wxNewBitmapButton::wxNewBitmapButton( const wxString
& bitmapFileName
,
269 const wxBitmapType bitmapFileType
,
270 const wxString
& labelText
,
279 : mTextToLabelGap ( 2 ),
282 mTextAlignment( alignText
),
285 mLabelText( labelText
),
286 mImageFileName( bitmapFileName
),
287 mImageFileType( bitmapFileType
),
289 mpDepressedImg( NULL
),
290 mpPressedImg ( NULL
),
291 mpDisabledImg ( NULL
),
292 mpFocusedImg ( NULL
),
294 mDragStarted ( FALSE
),
295 mIsPressed ( FALSE
),
296 mIsInFocus ( FALSE
),
297 mHasFocusedBmp( FALSE
),
298 mFiredEventType( wxEVT_COMMAND_MENU_SELECTED
),
300 mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID
),
301 mDarkPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
), 1, wxSOLID
),
302 mGrayPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
), 1, wxSOLID
),
303 mLightPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
), 1, wxSOLID
),
311 wxNewBitmapButton::~wxNewBitmapButton(void)
316 void wxNewBitmapButton::DrawShade( int outerLevel
,
318 wxPen
& upperLeftSidePen
,
319 wxPen
& lowerRightSidePen
)
321 wxBitmap
* pBmp
= GetStateLabel();
323 int x
= mMarginX
- (outerLevel
+ 1);
324 int y
= mMarginY
- (outerLevel
+ 1);
326 int height
= pBmp
->GetHeight() + (outerLevel
+ 1)*2 - 1;
327 int width
= pBmp
->GetWidth() + (outerLevel
+ 1)*2 - 1;
329 dc
.SetPen( upperLeftSidePen
);
330 dc
.DrawLine( x
,y
, x
+ width
, y
);
331 dc
.DrawLine( x
,y
, x
, y
+ height
);
333 dc
.SetPen( lowerRightSidePen
);
334 dc
.DrawLine( x
+ width
, y
, x
+ width
, y
+ height
+ 1 );
335 dc
.DrawLine( x
, y
+ height
, x
+ width
, y
+ height
);
338 void wxNewBitmapButton::DestroyLabels()
340 if ( mpDepressedImg
) delete mpDepressedImg
;
341 if ( mpPressedImg
) delete mpPressedImg
;
342 if ( mpDisabledImg
) delete mpDisabledImg
;
343 if ( mpFocusedImg
) delete mpFocusedImg
;
345 mpDepressedImg
= NULL
;
347 mpDisabledImg
= NULL
;
351 wxBitmap
* wxNewBitmapButton::GetStateLabel()
363 if ( mHasFocusedBmp
)
367 return mpDepressedImg
;
370 return mpDepressedImg
;
374 return mpDisabledImg
;
377 static const unsigned char _gDisableImage
[] = { 0x55,0xAA,0x55,0xAA,
382 void wxNewBitmapButton::RenderLabelImage( wxBitmap
*& destBmp
, wxBitmap
* srcBmp
,
383 bool isEnabled
, bool isPressed
)
385 if ( destBmp
!= 0 ) return;
387 // render labels on-demand
390 srcDc
.SelectObject( *srcBmp
);
392 bool hasText
= ( mTextAlignment
!= NB_NO_TEXT
) &&
393 ( mLabelText
.length() != 0 );
395 bool hasImage
= (mTextAlignment
!= NB_NO_IMAGE
);
403 long txtWidth
, txtHeight
;
405 srcDc
.SetFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
) );
406 srcDc
.GetTextExtent( mLabelText
, &txtWidth
, &txtHeight
);
408 if ( mTextAlignment
== NB_ALIGN_TEXT_RIGHT
)
410 destDim
.x
= srcBmp
->GetWidth() + 2*mTextToLabelGap
+ txtWidth
;
413 wxMax( srcBmp
->GetHeight(), txtHeight
);
415 txtPos
.x
= srcBmp
->GetWidth() + mTextToLabelGap
;
416 txtPos
.y
= (destDim
.y
- txtHeight
)/2;
418 imgPos
.y
= (destDim
.y
- srcBmp
->GetHeight())/2;
421 if ( mTextAlignment
== NB_ALIGN_TEXT_BOTTOM
)
424 wxMax( srcBmp
->GetWidth(), txtWidth
);
426 destDim
.y
= srcBmp
->GetHeight() + mTextToLabelGap
+ txtHeight
;
428 txtPos
.x
= (destDim
.x
- txtWidth
)/2;
429 txtPos
.y
= srcBmp
->GetHeight() + mTextToLabelGap
;
430 imgPos
.x
= (destDim
.x
- srcBmp
->GetWidth())/2;
435 wxFAIL_MSG("Unsupported FL alignment type detected in wxNewBitmapButton::RenderLabelImage()");
442 destDim
.x
= srcBmp
->GetWidth();
443 destDim
.y
= srcBmp
->GetHeight();
446 destBmp
= new wxBitmap( int(destDim
.x
), int(destDim
.y
) );
449 destDc
.SelectObject( *destBmp
);
451 wxBrush
grayBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_3DFACE
), wxSOLID
);
452 wxPen
nullPen( wxColour(0,0,0), 1, wxTRANSPARENT
);
454 destDc
.SetBrush( grayBrush
);
455 destDc
.SetPen( nullPen
);
457 destDc
.DrawRectangle( 0,0, destDim
.x
+1, destDim
.y
+1 );
461 ++imgPos
.x
; ++imgPos
.y
;
462 ++txtPos
.x
; ++txtPos
.y
;
468 destDc
.Blit( imgPos
.x
, imgPos
.y
,
469 srcBmp
->GetWidth()+1,
470 srcBmp
->GetHeight()+1,
471 &srcDc
, 0,0, wxCOPY
,TRUE
);
476 wxWindow
* pTopWnd
= this;
480 wxWindow
* pParent
= pTopWnd
->GetParent();
488 destDc
.SetFont( wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
) );
492 destDc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
) );
496 destDc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
) );
498 destDc
.SetTextBackground( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
) );
500 destDc
.DrawText( mLabelText
, txtPos
.x
, txtPos
.y
);
505 #ifdef __WXMSW__ // This is currently MSW specific
506 gray_out_image_on_dc( destDc
, destDim
.x
, destDim
.y
);
508 wxBrush
checkerBrush( wxBitmap( (const char*)_gDisableImage
,8,8) );
509 checkerBrush
.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
) );
510 destDc
.SetBrush( checkerBrush
);
511 destDc
.DrawRectangle( imgPos
.x
, imgPos
.y
, srcBmp
->GetWidth()+1, srcBmp
->GetHeight()+1);
514 // adjust button size to fit the new dimensions of the label
515 if ( !mSizeIsSet
&& 0 )
519 destBmp
->GetWidth() + mMarginX
*2,
520 destBmp
->GetHeight() + mMarginY
*2, 0
523 destDc
.SelectObject( wxNullBitmap
);
526 // Map to system colours
527 (void) MapBitmap(destBmp
->GetHBITMAP(), destBmp
->GetWidth(), destBmp
->GetHeight());
531 void wxNewBitmapButton::RenderAllLabelImages()
535 RenderLabelImage( mpDisabledImg
, &mDepressedBmp
, FALSE
);
536 RenderLabelImage( mpPressedImg
, &mDepressedBmp
, TRUE
, TRUE
);
537 RenderLabelImage( mpDepressedImg
, &mDepressedBmp
, TRUE
, FALSE
);
538 if ( mHasFocusedBmp
)
540 RenderLabelImage( mpFocusedImg
, &mFocusedBmp
, TRUE
, FALSE
);
545 void wxNewBitmapButton::RenderLabelImages()
552 RenderLabelImage( mpDisabledImg
, &mDepressedBmp
, FALSE
);
558 RenderLabelImage( mpPressedImg
, &mDepressedBmp
, TRUE
, TRUE
);
563 if ( mHasFocusedBmp
)
564 RenderLabelImage( mpFocusedImg
, &mFocusedBmp
, TRUE
, FALSE
);
566 RenderLabelImage( mpDepressedImg
, &mDepressedBmp
, TRUE
, FALSE
);
569 RenderLabelImage( mpDepressedImg
, &mDepressedBmp
, TRUE
, FALSE
);
573 bool wxNewBitmapButton::Enable(bool enable
)
575 if ( enable
!= m_isEnabled
)
590 return wxPanel::Enable( enable
);
593 void wxNewBitmapButton::DrawDecorations( wxDC
& dc
)
597 DrawShade( 1, dc
, mGrayPen
, mGrayPen
);
602 DrawShade( 0, dc
, mDarkPen
, mLightPen
);
604 DrawShade( 0, dc
, mLightPen
, mDarkPen
);
607 DrawShade( 0, dc
, mGrayPen
, mGrayPen
);
613 DrawShade( 0, dc
, mDarkPen
, mGrayPen
);
614 DrawShade( 1, dc
, mBlackPen
, mLightPen
);
618 DrawShade( 0, dc
, mGrayPen
, mDarkPen
);
619 DrawShade( 1, dc
, mLightPen
, mBlackPen
);
624 void wxNewBitmapButton::SetLabel(const wxBitmap
& labelBitmap
,
625 const wxString
& labelText
)
629 mLabelText
= labelText
;
630 mDepressedBmp
= labelBitmap
;
632 //RenderLabelImages();
633 RenderAllLabelImages();
636 void wxNewBitmapButton::SetAlignments( int alignText
,
645 mTextAlignment
= alignText
;
646 mTextToLabelGap
= textToLabelGap
;
648 //RenderLabelImages();
649 RenderAllLabelImages();
654 void wxNewBitmapButton::OnLButtonDown( wxMouseEvent
& event
)
661 void wxNewBitmapButton::OnLButtonUp( wxMouseEvent
& event
)
666 mDragStarted
= FALSE
;
670 if ( IsInWindow( event
.m_x
, event
.m_y
) )
672 // fire event, if mouse was released
673 // within the bounds of button
674 wxCommandEvent
cmd( mFiredEventType
, GetId() );
675 GetParent()->ProcessEvent( cmd
);
679 void wxNewBitmapButton::OnLButtonDClick( wxMouseEvent
& event
)
681 if ( IsInWindow( event
.m_x
, event
.m_y
) )
683 // fire event, if mouse was released
684 // within the bounds of button
685 wxCommandEvent
cmd( mFiredEventType
, GetId() );
686 GetParent()->ProcessEvent( cmd
);
688 mDragStarted
= FALSE
;
694 bool wxNewBitmapButton::IsInWindow( int x
, int y
)
697 GetSize( &width
, &height
);
699 return ( x
>= 0 && y
>= 0 &&
704 void wxNewBitmapButton::OnMouseEnter( wxMouseEvent
& event
)
706 bool prevIsInFocus
= mIsInFocus
;
712 if ( prevIsInFocus
!= mIsInFocus
)
718 void wxNewBitmapButton::OnMouseLeave( wxMouseEvent
& event
)
720 bool prevIsInFocus
= mIsInFocus
;
721 bool prevIsPressed
= mIsPressed
;
727 if ( prevIsInFocus
!= mIsInFocus
|| prevIsPressed
!= mIsPressed
)
733 void wxNewBitmapButton::OnSize( wxSizeEvent
& event
)
738 void wxNewBitmapButton::Reshape( )
740 bool wasCreated
= mIsCreated
;
745 // in the case of loading button from stream, check if we
746 // have non-empty image-file name, load if possible
748 if ( mImageFileName
!= "" )
750 mDepressedBmp
.LoadFile( mImageFileName
, mImageFileType
);
752 //wxMessageBox("Image Loaded!!!");
755 //RenderLabelImages();
756 RenderAllLabelImages();
758 wxBitmap
* pCurImg
= GetStateLabel();
760 int w
= pCurImg
->GetWidth(),
761 h
= pCurImg
->GetHeight();
763 SetSize( 0,0, w
+ mMarginX
*2, h
+ mMarginY
*2 , 0 );
767 void wxNewBitmapButton::DrawLabel( wxDC
& dc
)
769 wxBitmap
* pCurBmp
= GetStateLabel();
771 if ( pCurBmp
== NULL
)
774 OnSize( evt
); // fake it up!
776 //RenderLabelImages();
777 pCurBmp
= GetStateLabel();
781 mdc
.SelectObject( *pCurBmp
);
783 dc
.Blit( mMarginX
, mMarginY
,
785 pCurBmp
->GetHeight(),
789 mdc
.SelectObject( wxNullBitmap
);
792 void wxNewBitmapButton::OnPaint( wxPaintEvent
& event
)
796 // first, make sure images for current state are prepared
797 //RenderLabelImages();
801 DrawDecorations( dc
);
804 void wxNewBitmapButton::OnEraseBackground( wxEraseEvent
& event
)
809 void wxNewBitmapButton::OnKillFocus( wxFocusEvent
& event
)
813 wxMessageBox("kill-focus for button!");
817 WXHBITMAP
wxNewBitmapButton::MapBitmap(WXHBITMAP bitmap
, int width
, int height
)
823 wxLogLastError(_T("CreateCompatibleDC"));
828 SelectInHDC
bmpInHDC(hdcMem
, (HBITMAP
)bitmap
);
832 wxLogLastError(_T("SelectObject"));
837 wxCOLORMAP
*cmap
= wxGetStdColourMap();
839 for ( int i
= 0; i
< width
; i
++ )
841 for ( int j
= 0; j
< height
; j
++ )
843 COLORREF pixel
= ::GetPixel(hdcMem
, i
, j
);
845 for ( size_t k
= 0; k
< wxSTD_COL_MAX
; k
++ )
847 COLORREF col
= cmap
[k
].from
;
848 if ( abs(GetRValue(pixel
) - GetRValue(col
)) < 10 &&
849 abs(GetGValue(pixel
) - GetGValue(col
)) < 10 &&
850 abs(GetBValue(pixel
) - GetBValue(col
)) < 10 )
852 ::SetPixel(hdcMem
, i
, j
, cmap
[k
].to
);