1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxNewBitmapButton enhanced bitmap button class.
4 // Author: Aleksandras Gluchovas
8 // Copyright: (c) Aleksandras Gluchovas
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
23 #include "wx/fl/newbmpbtn.h"
24 #include "wx/utils.h" // import wxMin,wxMax macros
27 #include "wx/msw/private.h"
30 ///////////// button-label rendering helpers //////////////////
32 static int* create_array( int width
, int height
, int fill
= 0 )
34 int* array
= new int[width
*height
];
36 int len
= width
*height
;
38 for ( i
= 0; i
!= len
; ++i
)
44 #define GET_ELEM(array,x,y) (array[width*(y)+(x)])
46 #define MIN_COLOR_DIFF 10
48 #define IS_IN_ARRAY(x,y) ( (x) < width && (y) < height && (x) >= 0 && (y) >= 0 )
50 #define GET_RED(col) col & 0xFF
51 #define GET_GREEN(col) (col >> 8) & 0xFF
52 #define GET_BLUE(col) (col >> 16) & 0xFF
54 #define MAKE_INT_COLOR(red,green,blue) ( (red) | \
55 ( ( (green) << 8 ) & 0xFF00 ) | \
56 ( ( (blue) << 16) & 0xFF0000) \
59 #define IS_GREATER(col1,col2) ( ( (GET_RED(col1) ) > (GET_RED(col2) ) + MIN_COLOR_DIFF ) && \
60 ( (GET_GREEN(col1)) > (GET_GREEN(col2)) + MIN_COLOR_DIFF ) && \
61 ( (GET_BLUE(col1) ) > (GET_BLUE(col2) ) + MIN_COLOR_DIFF ) \
68 // helper function, used internally
70 static void gray_out_pixmap( int* src
, int* dest
, int width
, int height
)
72 // assuming the pixels along the edges are of the background color
79 int cur
= GET_ELEM(src
,x
,y
);
82 if ( IS_IN_ARRAY(x
-1,y
-1) )
84 int upperElem
= GET_ELEM(src
,x
-1,y
-1);
86 // if the upper element is lighter than current
87 if ( IS_GREATER(upperElem
,cur
) )
89 GET_ELEM(dest
,x
,y
) = MASK_DARK
;
92 // if the current element is ligher than the upper
93 if ( IS_GREATER(cur
,upperElem
) )
95 GET_ELEM(dest
,x
,y
) = MASK_LIGHT
;
99 if ( GET_ELEM(dest
,x
-1,y
-1) == MASK_LIGHT
)
101 GET_ELEM(dest
,x
,y
) = MASK_BG
;
103 if ( GET_ELEM(dest
,x
-1,y
-1 ) == MASK_DARK
)
105 GET_ELEM(dest
,x
,y
) = MASK_DARK
;
107 GET_ELEM(dest
,x
,y
) = MASK_BG
;
113 if ( IS_IN_ARRAY(x
+1,y
-1) )
120 while ( IS_IN_ARRAY(x
-1,y
+1) )
126 if ( IS_IN_ARRAY(x
,y
+1) )
133 if ( IS_IN_ARRAY(x
+1,y
) )
145 // algorithm for making the image look "grayed" (e.g. disabled button)
146 // NOTE:: used GetPixel(), which is Windows-Only!
148 void gray_out_image_on_dc( wxDC
& dc
, int width
, int height
)
150 // assuming the pixels along the edges are of the background color
152 dc
.GetPixel( 0, 0, &bgCol
);
154 wxPen
darkPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
),1, wxSOLID
);
155 wxPen
lightPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
),1, wxSOLID
);
156 wxPen
bgPen ( bgCol
, 1, wxSOLID
);
158 int* src
= create_array( width
, height
, MASK_BG
);
159 int* dest
= create_array( width
, height
, MASK_BG
);
162 for ( y
= 0; y
!= height
; ++y
)
164 for ( x
= 0; x
!= width
; ++x
)
167 dc
.GetPixel( x
,y
, &col
);
169 GET_ELEM(src
,x
,y
) = MAKE_INT_COLOR( col
.Red(), col
.Green(), col
.Blue() );
172 gray_out_pixmap( src
, dest
, width
, height
);
174 for ( y
= 0; y
!= height
; ++y
)
176 for ( x
= 0; x
!= width
; ++x
)
178 int mask
= GET_ELEM(dest
,x
,y
);
182 case MASK_BG
: { dc
.SetPen( bgPen
);
183 dc
.DrawPoint( x
,y
); break;
185 case MASK_DARK
: { dc
.SetPen( darkPen
);
186 dc
.DrawPoint( x
,y
); break;
188 case MASK_LIGHT
: { dc
.SetPen( lightPen
);
189 dc
.DrawPoint( x
,y
); break;
199 ///////////////////////////////
201 /***** Implementation for class wxNewBitmapButton *****/
203 IMPLEMENT_DYNAMIC_CLASS(wxNewBitmapButton
, wxPanel
)
205 BEGIN_EVENT_TABLE( wxNewBitmapButton
, wxPanel
)
207 EVT_LEFT_DOWN ( wxNewBitmapButton::OnLButtonDown
)
208 EVT_LEFT_UP ( wxNewBitmapButton::OnLButtonUp
)
209 // EVT_LEFT_DCLICK ( wxNewBitmapButton::OnLButtonDClick )
210 EVT_LEFT_DCLICK ( wxNewBitmapButton::OnLButtonDown
)
211 EVT_ENTER_WINDOW( wxNewBitmapButton::OnMouseEnter
)
212 EVT_LEAVE_WINDOW( wxNewBitmapButton::OnMouseLeave
)
214 EVT_SIZE ( wxNewBitmapButton::OnSize
)
215 EVT_PAINT( wxNewBitmapButton::OnPaint
)
217 //EVT_KILL_FOCUS( wxNewBitmapButton::OnKillFocus )
219 EVT_ERASE_BACKGROUND( wxNewBitmapButton::OnEraseBackground
)
221 EVT_IDLE(wxNewBitmapButton::OnIdle
)
225 wxNewBitmapButton::wxNewBitmapButton( const wxBitmap
& labelBitmap
,
226 const wxString
& labelText
,
234 : mTextToLabelGap ( textToLabelGap
),
237 mTextAlignment( alignText
),
238 mIsSticky( isSticky
),
240 mLabelText( labelText
),
241 mImageFileType( wxBITMAP_TYPE_INVALID
),
242 mDepressedBmp( labelBitmap
),
244 mpDepressedImg( NULL
),
245 mpPressedImg ( NULL
),
246 mpDisabledImg ( NULL
),
247 mpFocusedImg ( NULL
),
250 mDragStarted ( false ),
251 mIsPressed ( false ),
252 mIsInFocus ( false ),
253 mIsToggled ( 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
,
273 int WXUNUSED(firedEventType
),
274 int WXUNUSED(marginX
),
275 int WXUNUSED(marginY
),
276 int WXUNUSED(textToLabelGap
),
277 bool WXUNUSED(isSticky
))
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 mIsToggled ( false ),
298 mHasFocusedBmp( false ),
299 mFiredEventType( wxEVT_COMMAND_MENU_SELECTED
),
301 mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID
),
302 mDarkPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
), 1, wxSOLID
),
303 mGrayPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
), 1, wxSOLID
),
304 mLightPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
), 1, wxSOLID
),
312 wxNewBitmapButton::~wxNewBitmapButton(void)
317 void wxNewBitmapButton::DrawShade( int outerLevel
,
319 wxPen
& upperLeftSidePen
,
320 wxPen
& lowerRightSidePen
)
322 wxBitmap
* pBmp
= GetStateLabel();
323 int x
= mMarginX
- (outerLevel
+ 2);
324 int y
= mMarginY
- (outerLevel
+ 2);
325 int height
= pBmp
->GetHeight() + (outerLevel
+ 2)*2 - 1;
326 int width
= pBmp
->GetWidth() + (outerLevel
+ 2)*2 - 1;
327 dc
.SetPen( upperLeftSidePen
);
328 dc
.DrawLine( x
,y
, x
+ width
, y
);
329 dc
.DrawLine( x
,y
, x
, y
+ height
);
330 dc
.DrawLine( x
,y
+1, x
+ width
, y
+1 ); // top
331 dc
.DrawLine( x
+1,y
, x
+1, y
+ height
); // left
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
);
336 dc
.DrawLine( x
+ width
-1, y
+1, x
+ width
-1, y
+ height
+1 ); // right
337 dc
.DrawLine( x
+1, y
+ height
-1, x
+ width
, y
+ height
-1 ); // bottom
340 void wxNewBitmapButton::DestroyLabels()
342 if ( mpDepressedImg
) delete mpDepressedImg
;
343 if ( mpPressedImg
) delete mpPressedImg
;
344 if ( mpDisabledImg
) delete mpDisabledImg
;
345 if ( mpFocusedImg
) delete mpFocusedImg
;
347 mpDepressedImg
= NULL
;
349 mpDisabledImg
= NULL
;
353 wxBitmap
* wxNewBitmapButton::GetStateLabel()
365 if ( mHasFocusedBmp
)
369 return mpDepressedImg
;
372 return mpDepressedImg
;
376 return mpDisabledImg
;
381 static const unsigned char _gDisableImage
[] = { 0x55,0xAA,0x55,0xAA,
389 void wxNewBitmapButton::RenderLabelImage( wxBitmap
*& destBmp
, wxBitmap
* srcBmp
,
390 bool isEnabled
, bool isPressed
)
392 if ( destBmp
!= 0 ) return;
394 // render labels on-demand
397 srcDc
.SelectObject( *srcBmp
);
399 bool hasText
= ( mTextAlignment
!= NB_NO_TEXT
) &&
400 ( mLabelText
.length() != 0 );
402 bool hasImage
= (mTextAlignment
!= NB_NO_IMAGE
);
410 long txtWidth
, txtHeight
;
412 srcDc
.SetFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
) );
413 srcDc
.GetTextExtent( mLabelText
, &txtWidth
, &txtHeight
);
415 if ( mTextAlignment
== NB_ALIGN_TEXT_RIGHT
)
417 destDim
.x
= srcBmp
->GetWidth() + 2*mTextToLabelGap
+ txtWidth
;
420 wxMax( srcBmp
->GetHeight(), txtHeight
);
422 txtPos
.x
= srcBmp
->GetWidth() + mTextToLabelGap
;
423 txtPos
.y
= (destDim
.y
- txtHeight
)/2;
425 imgPos
.y
= (destDim
.y
- srcBmp
->GetHeight())/2;
428 if ( mTextAlignment
== NB_ALIGN_TEXT_BOTTOM
)
431 wxMax( srcBmp
->GetWidth(), txtWidth
);
433 destDim
.y
= srcBmp
->GetHeight() + mTextToLabelGap
+ txtHeight
;
435 txtPos
.x
= (destDim
.x
- txtWidth
)/2;
436 txtPos
.y
= srcBmp
->GetHeight() + mTextToLabelGap
;
437 imgPos
.x
= (destDim
.x
- srcBmp
->GetWidth())/2;
442 wxFAIL_MSG(wxT("Unsupported FL alignment type detected in wxNewBitmapButton::RenderLabelImage()"));
449 destDim
.x
= srcBmp
->GetWidth();
450 destDim
.y
= srcBmp
->GetHeight();
453 destBmp
= new wxBitmap( int(destDim
.x
), int(destDim
.y
) );
456 destDc
.SelectObject( *destBmp
);
458 wxBrush
grayBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_3DFACE
), wxSOLID
);
460 destDc
.SetBrush( grayBrush
);
461 destDc
.SetPen( *wxTRANSPARENT_PEN
);
462 destDc
.DrawRectangle( 0,0, destDim
.x
+1, destDim
.y
+1 );
466 ++imgPos
.x
; ++imgPos
.y
;
467 ++txtPos
.x
; ++txtPos
.y
;
473 destDc
.Blit( imgPos
.x
, imgPos
.y
,
476 &srcDc
, 0,0, wxCOPY
,true );
481 wxWindow
* pTopWnd
= this;
485 wxWindow
* pParent
= pTopWnd
->GetParent();
493 destDc
.SetFont( wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
) );
497 destDc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
) );
501 destDc
.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
) );
503 destDc
.SetTextBackground( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
) );
505 destDc
.DrawText( mLabelText
, txtPos
.x
, txtPos
.y
);
510 #ifdef __WXMSW__ // This is currently MSW specific
511 gray_out_image_on_dc( destDc
, destDim
.x
, destDim
.y
);
513 wxBitmap
bmp( (const char*)_gDisableImage
,8,8);
514 wxBrush
checkerBrush(bmp
);
515 checkerBrush
.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
) );
516 destDc
.SetBrush( checkerBrush
);
517 destDc
.DrawRectangle( imgPos
.x
, imgPos
.y
, srcBmp
->GetWidth()+1, srcBmp
->GetHeight()+1);
520 // adjust button size to fit the new dimensions of the label
521 if ( !mSizeIsSet
&& 0 )
524 SetSize( wxDefaultCoord
, wxDefaultCoord
,
525 destBmp
->GetWidth() + mMarginX
*2,
526 destBmp
->GetHeight() + mMarginY
*2, 0
529 destDc
.SelectObject( wxNullBitmap
);
531 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
532 // Map to system colours
533 (void) wxToolBar::MapBitmap(destBmp
->GetHBITMAP(), destBmp
->GetWidth(), destBmp
->GetHeight());
537 void wxNewBitmapButton::RenderAllLabelImages()
541 RenderLabelImage( mpDisabledImg
, &mDepressedBmp
, false );
542 RenderLabelImage( mpPressedImg
, &mDepressedBmp
, true, true );
543 RenderLabelImage( mpDepressedImg
, &mDepressedBmp
, true, false );
544 if ( mHasFocusedBmp
)
546 RenderLabelImage( mpFocusedImg
, &mFocusedBmp
, true, false );
551 void wxNewBitmapButton::RenderLabelImages()
558 RenderLabelImage( mpDisabledImg
, &mDepressedBmp
, false );
564 RenderLabelImage( mpPressedImg
, &mDepressedBmp
, true, true );
569 if ( mHasFocusedBmp
)
570 RenderLabelImage( mpFocusedImg
, &mFocusedBmp
, true, false );
572 RenderLabelImage( mpDepressedImg
, &mDepressedBmp
, true, false );
575 RenderLabelImage( mpDepressedImg
, &mDepressedBmp
, true, false );
579 bool wxNewBitmapButton::Toggle(bool enable
)
581 if ( mIsToggled
== enable
)
592 bool wxNewBitmapButton::Enable(bool enable
)
594 if ( enable
!= m_isEnabled
)
609 return wxPanel::Enable( enable
);
612 void wxNewBitmapButton::DrawDecorations( wxDC
& dc
)
616 DrawShade( 1, dc
, mGrayPen
, mGrayPen
);
619 DrawShade( 0, dc
, mDarkPen
, mLightPen
);
621 else if ( mIsInFocus
)
624 DrawShade( 0, dc
, mDarkPen
, mLightPen
);
626 DrawShade( 0, dc
, mLightPen
, mDarkPen
);
629 DrawShade( 0, dc
, mGrayPen
, mGrayPen
);
633 if ( mIsPressed
|| mIsToggled
)
635 DrawShade( 0, dc
, mDarkPen
, mGrayPen
);
636 DrawShade( 1, dc
, mBlackPen
, mLightPen
);
640 DrawShade( 0, dc
, mGrayPen
, mDarkPen
);
641 DrawShade( 1, dc
, mLightPen
, mBlackPen
);
646 void wxNewBitmapButton::SetLabel(const wxBitmap
& labelBitmap
,
647 const wxString
& labelText
)
651 mLabelText
= labelText
;
652 mDepressedBmp
= labelBitmap
;
654 //RenderLabelImages();
655 RenderAllLabelImages();
658 void wxNewBitmapButton::SetAlignments( int alignText
,
667 mTextAlignment
= alignText
;
668 mTextToLabelGap
= textToLabelGap
;
670 //RenderLabelImages();
671 RenderAllLabelImages();
676 void wxNewBitmapButton::OnLButtonDown( wxMouseEvent
& WXUNUSED(event
) )
683 void wxNewBitmapButton::OnLButtonUp( wxMouseEvent
& event
)
688 mDragStarted
= false;
692 if ( IsInWindow( event
.m_x
, event
.m_y
) )
694 // fire event, if mouse was released
695 // within the bounds of button
696 wxCommandEvent
cmd( mFiredEventType
, GetId() );
697 GetParent()->ProcessEvent( cmd
);
701 bool wxNewBitmapButton::IsInWindow( int x
, int y
)
704 GetSize( &width
, &height
);
706 return ( x
>= 0 && y
>= 0 &&
711 void wxNewBitmapButton::OnMouseEnter( wxMouseEvent
& WXUNUSED(event
) )
713 bool prevIsInFocus
= mIsInFocus
;
719 if ( prevIsInFocus
!= mIsInFocus
)
725 void wxNewBitmapButton::OnMouseLeave( wxMouseEvent
& WXUNUSED(event
) )
727 bool prevIsInFocus
= mIsInFocus
;
728 bool prevIsPressed
= mIsPressed
;
734 if ( prevIsInFocus
!= mIsInFocus
|| prevIsPressed
!= mIsPressed
)
740 void wxNewBitmapButton::OnSize( wxSizeEvent
& WXUNUSED(event
) )
745 void wxNewBitmapButton::Reshape( )
747 bool wasCreated
= mIsCreated
;
752 // in the case of loading button from stream, check if we
753 // have non-empty image-file name, load if possible
755 if (!mImageFileName
.empty())
757 mDepressedBmp
.LoadFile( mImageFileName
, mImageFileType
);
759 //wxMessageBox("Image Loaded!!!");
762 //RenderLabelImages();
763 RenderAllLabelImages();
765 wxBitmap
* pCurImg
= GetStateLabel();
767 int w
= pCurImg
->GetWidth(),
768 h
= pCurImg
->GetHeight();
770 SetSize( 0,0, w
+ mMarginX
*2, h
+ mMarginY
*2 , 0 );
774 void wxNewBitmapButton::DrawLabel( wxDC
& dc
)
776 wxBitmap
* pCurBmp
= GetStateLabel();
778 if ( pCurBmp
== NULL
)
781 OnSize( evt
); // fake it up!
783 //RenderLabelImages();
784 pCurBmp
= GetStateLabel();
788 mdc
.SelectObject( *pCurBmp
);
790 dc
.Blit( mMarginX
, mMarginY
,
792 pCurBmp
->GetHeight(),
796 mdc
.SelectObject( wxNullBitmap
);
799 void wxNewBitmapButton::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
803 // first, make sure images for current state are prepared
804 //RenderLabelImages();
808 DrawDecorations( dc
);
811 void wxNewBitmapButton::OnEraseBackground( wxEraseEvent
& WXUNUSED(event
) )
816 void wxNewBitmapButton::OnKillFocus( wxFocusEvent
& WXUNUSED(event
) )
820 wxMessageBox(wxT("kill-focus for button!"));
823 // ----------------------------------------------------------------------------
825 // ----------------------------------------------------------------------------
827 void wxNewBitmapButton::OnIdle(wxIdleEvent
& event
)
834 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
835 void wxNewBitmapButton::DoButtonUpdate()
837 wxUpdateUIEvent
event(GetId());
838 event
.SetEventObject(this);
840 if ( GetParent()->ProcessEvent(event
) )
842 if ( event
.GetSetEnabled() )
844 bool enabled
= event
.GetEnabled();
845 if ( enabled
!= IsEnabled() )
848 if ( event
.GetSetChecked() )
849 Toggle( event
.GetChecked() );