///////////////////////////////////////////////////////////////////////////// // Name: No names yet. // Purpose: Contrib. demo // Author: Aleksandras Gluchovas // Modified by: // Created: ??/09/98 // RCS-ID: $Id$ // Copyright: (c) Aleksandras Gluchovas // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "newbmpbtn.h" #endif // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "wx/fl/newbmpbtn.h" #include "wx/utils.h" // import wxMin,wxMax macros ///////////// button-label rendering helpers ////////////////// static int* create_array( int width, int height, int fill = 0 ) { int* array = new int[width*height]; int len = width*height; int i; for ( i = 0; i != len; ++i ) array[i] = fill; return array; } #define GET_ELEM(array,x,y) (array[width*(y)+(x)]) #define MIN_COLOR_DIFF 10 #define IS_IN_ARRAY(x,y) ( (x) < width && (y) < height && (x) >= 0 && (y) >= 0 ) #define GET_RED(col) col & 0xFF #define GET_GREEN(col) (col >> 8) & 0xFF #define GET_BLUE(col) (col >> 16) & 0xFF #define MAKE_INT_COLOR(red,green,blue) ( (red) | \ ( ( (green) << 8 ) & 0xFF00 ) | \ ( ( (blue) << 16) & 0xFF0000) \ ) #define IS_GREATER(col1,col2) ( ( (GET_RED(col1) ) > (GET_RED(col2) ) + MIN_COLOR_DIFF ) && \ ( (GET_GREEN(col1)) > (GET_GREEN(col2)) + MIN_COLOR_DIFF ) && \ ( (GET_BLUE(col1) ) > (GET_BLUE(col2) ) + MIN_COLOR_DIFF ) \ ) #define MASK_BG 0 #define MASK_DARK 1 #define MASK_LIGHT 2 // helper function, used internally static void gray_out_pixmap( int* src, int* dest, int width, int height ) { // assuming the pixels along the edges are of the background color int x = 0; int y = 1; do { int cur = GET_ELEM(src,x,y); if ( IS_IN_ARRAY(x-1,y-1) ) { int upperElem = GET_ELEM(src,x-1,y-1); // if the upper element is lighter than current if ( IS_GREATER(upperElem,cur) ) { GET_ELEM(dest,x,y) = MASK_DARK; } else // if the current element is ligher than the upper if ( IS_GREATER(cur,upperElem) ) { GET_ELEM(dest,x,y) = MASK_LIGHT; } else { if ( GET_ELEM(dest,x-1,y-1) == MASK_LIGHT ) GET_ELEM(dest,x,y) = MASK_BG; if ( GET_ELEM(dest,x-1,y-1 ) == MASK_DARK ) GET_ELEM(dest,x,y) = MASK_DARK; else GET_ELEM(dest,x,y) = MASK_BG; } } // go zig-zag if ( IS_IN_ARRAY(x+1,y-1) ) { ++x; --y; } else { while ( IS_IN_ARRAY(x-1,y+1) ) { --x; ++y; } if ( IS_IN_ARRAY(x,y+1) ) { ++y; continue; } else { if ( IS_IN_ARRAY(x+1,y) ) { ++x; continue; } else break; } } } while (1); } // alg. for making the image look "grayed" (e.g. disabled button) // NOTE:: used GetPixel(), which is Windows-Only! void gray_out_image_on_dc( wxDC& dc, int width, int height ) { // assuming the pixels along the edges are of the background color wxColour bgCol; dc.GetPixel( 0, 0, &bgCol ); wxPen darkPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW),1, wxSOLID ); wxPen lightPen( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT),1, wxSOLID ); wxPen bgPen ( bgCol, 1, wxSOLID ); int* src = create_array( width, height, MASK_BG ); int* dest = create_array( width, height, MASK_BG ); int x, y; for ( y = 0; y != height; ++y ) { for ( x = 0; x != width; ++x ) { wxColour col; dc.GetPixel( x,y, &col ); GET_ELEM(src,x,y) = MAKE_INT_COLOR( col.Red(), col.Green(), col.Blue() ); } } gray_out_pixmap( src, dest, width, height ); for ( y = 0; y != height; ++y ) { for ( x = 0; x != width; ++x ) { int mask = GET_ELEM(dest,x,y); switch (mask) { case MASK_BG : { dc.SetPen( bgPen ); dc.DrawPoint( x,y ); break; } case MASK_DARK : { dc.SetPen( darkPen ); dc.DrawPoint( x,y ); break; } case MASK_LIGHT : { dc.SetPen( lightPen ); dc.DrawPoint( x,y ); break; } default : break; } } } delete [] src; delete [] dest; } /////////////////////////////// /***** Impelementation for class wxNewBitmapButton *****/ IMPLEMENT_DYNAMIC_CLASS(wxNewBitmapButton, wxPanel) BEGIN_EVENT_TABLE( wxNewBitmapButton, wxPanel ) EVT_LEFT_DOWN( wxNewBitmapButton::OnLButtonDown ) EVT_LEFT_UP ( wxNewBitmapButton::OnLButtonUp ) EVT_MOTION ( wxNewBitmapButton::OnMouseMove ) EVT_SIZE ( wxNewBitmapButton::OnSize ) EVT_PAINT( wxNewBitmapButton::OnPaint ) //EVT_KILL_FOCUS( wxNewBitmapButton::OnKillFocus ) EVT_ERASE_BACKGROUND( wxNewBitmapButton::OnEraseBackground ) END_EVENT_TABLE() wxNewBitmapButton::wxNewBitmapButton( const wxBitmap& labelBitmap, const wxString& labelText, int alignText, bool isFlat, int firedEventType, int marginX, int marginY, int textToLabelGap, bool isSticky) : mTextToLabelGap ( textToLabelGap ), mMarginX( marginX ), mMarginY( marginY ), mTextAlignment( alignText ), mIsSticky( isSticky ), mIsFlat( isFlat ), mLabelText( labelText ), mImageFileType( wxBITMAP_TYPE_INVALID ), mDepressedBmp( labelBitmap ), mpDepressedImg( NULL ), mpPressedImg ( NULL ), mpDisabledImg ( NULL ), mpFocusedImg ( NULL ), mDragStarted ( FALSE ), mIsPressed ( FALSE ), mIsInFocus( FALSE ), mPrevPressedState( FALSE ), mPrevInFocusState( FALSE ), mHasFocusedBmp( FALSE ), mFiredEventType( firedEventType ), mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID ), mDarkPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID ), mGrayPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ), mLightPen( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT), 1, wxSOLID ), mIsCreated( FALSE ), mSizeIsSet( FALSE ) { } wxNewBitmapButton::wxNewBitmapButton( const wxString& bitmapFileName, const wxBitmapType bitmapFileType, const wxString& labelText, int alignText, bool isFlat, int firedEventType, int marginX, int marginY, int textToLabelGap, bool isSticky) : mTextToLabelGap ( 2 ), mMarginX( 2 ), mMarginY( 2 ), mTextAlignment( alignText ), mIsSticky( FALSE ), mIsFlat( isFlat ), mLabelText( labelText ), mImageFileName( bitmapFileName ), mImageFileType( bitmapFileType ), mpDepressedImg( NULL ), mpPressedImg ( NULL ), mpDisabledImg ( NULL ), mpFocusedImg ( NULL ), mDragStarted ( FALSE ), mIsPressed ( FALSE ), mIsInFocus ( FALSE ), mPrevPressedState( FALSE ), mPrevInFocusState( FALSE ), mHasFocusedBmp( FALSE ), mFiredEventType( wxEVT_COMMAND_MENU_SELECTED ), mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID ), mDarkPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID ), mGrayPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ), mLightPen( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT), 1, wxSOLID ), mIsCreated( FALSE ), mSizeIsSet( FALSE ) { } wxNewBitmapButton::~wxNewBitmapButton(void) { DestroyLabels(); } void wxNewBitmapButton::DrawShade( int outerLevel, wxDC& dc, wxPen& upperLeftSidePen, wxPen& lowerRightSidePen ) { wxBitmap* pBmp = GetStateLabel(); int x = mMarginX - (outerLevel + 1); int y = mMarginY - (outerLevel + 1); int height = pBmp->GetHeight() + (outerLevel + 1)*2 - 1; int width = pBmp->GetWidth() + (outerLevel + 1)*2 - 1; dc.SetPen( upperLeftSidePen ); dc.DrawLine( x,y, x + width, y ); dc.DrawLine( x,y, x, y + height ); dc.SetPen( lowerRightSidePen ); dc.DrawLine( x + width, y, x + width, y + height + 1 ); dc.DrawLine( x, y + height, x + width, y + height ); } void wxNewBitmapButton::DestroyLabels() { if ( mpDepressedImg ) delete mpDepressedImg; if ( mpPressedImg ) delete mpPressedImg; if ( mpDisabledImg ) delete mpDisabledImg; if ( mpFocusedImg ) delete mpFocusedImg; mpDepressedImg = NULL; mpPressedImg = NULL; mpDisabledImg = NULL; mpFocusedImg = NULL; } wxBitmap* wxNewBitmapButton::GetStateLabel() { if ( IsEnabled() ) { if ( mIsPressed ) { return mpPressedImg; } else { if ( mIsInFocus ) { if ( mHasFocusedBmp ) return mpFocusedImg; else return mpDepressedImg; } else return mpDepressedImg; } } else return mpDisabledImg; } static const unsigned char _gDisableImage[] = { 0x55,0xAA,0x55,0xAA, 0x55,0xAA,0x55,0xAA, 0x55,0xAA,0x55,0xAA, 0x55,0xAA,0x55,0xAA }; void wxNewBitmapButton::RenderLabelImage( wxBitmap*& destBmp, wxBitmap* srcBmp, bool isEnabled, bool isPressed ) { if ( destBmp != 0 ) return; // render lables on-demand wxMemoryDC srcDc; srcDc.SelectObject( *srcBmp ); bool hasText = ( mTextAlignment != NB_NO_TEXT ) && ( mLabelText.length() != 0 ); bool hasImage = (mTextAlignment != NB_NO_IMAGE); wxSize destDim; wxPoint txtPos; wxPoint imgPos; if ( hasText ) { long txtWidth, txtHeight; srcDc.SetFont( wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT) ); srcDc.GetTextExtent( mLabelText, &txtWidth, &txtHeight ); if ( mTextAlignment == NB_ALIGN_TEXT_RIGHT ) { destDim.x = srcBmp->GetWidth() + 2*mTextToLabelGap + txtWidth; destDim.y = wxMax( srcBmp->GetHeight(), txtHeight ); txtPos.x = srcBmp->GetWidth() + mTextToLabelGap; txtPos.y = (destDim.y - txtHeight)/2; imgPos.x = 0; imgPos.y = (destDim.y - srcBmp->GetHeight())/2; } else if ( mTextAlignment == NB_ALIGN_TEXT_BOTTOM ) { destDim.x = wxMax( srcBmp->GetWidth(), txtWidth ); destDim.y = srcBmp->GetHeight() + mTextToLabelGap + txtHeight; txtPos.x = (destDim.x - txtWidth)/2; txtPos.y = srcBmp->GetHeight() + mTextToLabelGap; imgPos.x = (destDim.x - srcBmp->GetWidth())/2; imgPos.y = 0; } else { wxFAIL_MSG("Unsupported FL alignment type detected in wxNewBitmapButton::RenderLabelImage()"); } } else { imgPos.x = 0; imgPos.y = 0; destDim.x = srcBmp->GetWidth(); destDim.y = srcBmp->GetHeight(); } destBmp = new wxBitmap( int(destDim.x), int(destDim.y) ); wxMemoryDC destDc; destDc.SelectObject( *destBmp ); wxBrush grayBrush( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_3DFACE), wxSOLID ); wxPen nullPen( wxColour(0,0,0), 1, wxTRANSPARENT ); destDc.SetBrush( grayBrush ); destDc.SetPen( nullPen ); destDc.DrawRectangle( 0,0, destDim.x+1, destDim.y+1 ); if ( isPressed ) { ++imgPos.x; ++imgPos.y; ++txtPos.x; ++txtPos.y; } if ( hasImage ) { destDc.Blit( imgPos.x, imgPos.y, srcBmp->GetWidth()+1, srcBmp->GetHeight()+1, &srcDc, 0,0, wxCOPY,TRUE ); } if ( hasText ) { wxWindow* pTopWnd = this; do { wxWindow* pParent = pTopWnd->GetParent(); if ( pParent == 0 ) break; pTopWnd = pParent; } while (1); destDc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT) ); if ( isEnabled ) { destDc.SetTextForeground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT) ); } else { destDc.SetTextForeground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW) ); } destDc.SetTextBackground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE) ); destDc.DrawText( mLabelText, txtPos.x, txtPos.y ); } destDc.SetBrush( grayBrush ); destDc.SetPen( nullPen ); destDc.DrawRectangle( 0,0, destDim.x+1, destDim.y+1 ); if ( isPressed ) { ++imgPos.x; ++imgPos.y; ++txtPos.x; ++txtPos.y; } if ( hasImage ) { destDc.Blit( imgPos.x, imgPos.y, srcBmp->GetWidth()+1, srcBmp->GetHeight()+1, &srcDc, 0,0, wxCOPY,TRUE ); } if ( hasText ) { wxWindow* pTopWnd = this; do { wxWindow* pParent = pTopWnd->GetParent(); if ( pParent == 0 ) break; pTopWnd = pParent; } while (1); destDc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT) ); if ( isEnabled ) { destDc.SetTextForeground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT) ); } else { destDc.SetTextForeground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW) ); } destDc.SetTextBackground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE) ); destDc.DrawText( mLabelText, txtPos.x, txtPos.y ); } if ( !isEnabled ){ #ifdef __WXMSW__ // This is currently MSW specific gray_out_image_on_dc( destDc, destDim.x, destDim.y ); #else wxBrush checkerBrush( wxBitmap( (const char*)_gDisableImage,8,8) ); checkerBrush.SetColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ) ); destDc.SetBrush( checkerBrush ); destDc.DrawRectangle( imgPos.x, imgPos.y, srcBmp->GetWidth()+1, srcBmp->GetHeight()+1); #endif } // adjust button size to fit the new dimensions of the label if ( !mSizeIsSet && 0 ) { mSizeIsSet = TRUE; SetSize( -1,-1, destBmp->GetWidth() + mMarginX*2, destBmp->GetHeight() + mMarginY*2, 0 ); } } void wxNewBitmapButton::RenderAllLabelImages() { if ( !mIsCreated ) return; RenderLabelImage( mpDisabledImg, &mDepressedBmp, FALSE ); RenderLabelImage( mpPressedImg, &mDepressedBmp, TRUE, TRUE ); RenderLabelImage( mpDepressedImg, &mDepressedBmp, TRUE, FALSE ); if ( mHasFocusedBmp ) { RenderLabelImage( mpFocusedImg, &mFocusedBmp, TRUE, FALSE ); } } void wxNewBitmapButton::RenderLabelImages() { if ( !mIsCreated ) return; if ( !IsEnabled() ) { RenderLabelImage( mpDisabledImg, &mDepressedBmp, FALSE ); } else if ( mIsPressed ) RenderLabelImage( mpPressedImg, &mDepressedBmp, TRUE, TRUE ); else { if ( mIsInFocus ) { if ( mHasFocusedBmp ) RenderLabelImage( mpFocusedImg, &mFocusedBmp, TRUE, FALSE ); else RenderLabelImage( mpDepressedImg, &mDepressedBmp, TRUE, FALSE ); } else RenderLabelImage( mpDepressedImg, &mDepressedBmp, TRUE, FALSE ); } } void wxNewBitmapButton::DrawDecorations( wxDC& dc ) { if ( mIsFlat ) { DrawShade( 1, dc, mGrayPen, mGrayPen ); if ( mIsInFocus ) { if ( mIsPressed ) DrawShade( 0, dc, mDarkPen, mLightPen ); else DrawShade( 0, dc, mLightPen, mDarkPen ); } else DrawShade( 0, dc, mGrayPen, mGrayPen ); } else { if ( mIsPressed ) { DrawShade( 0, dc, mDarkPen, mGrayPen ); DrawShade( 1, dc, mBlackPen, mLightPen ); } else { DrawShade( 0, dc, mGrayPen, mDarkPen ); DrawShade( 1, dc, mLightPen, mBlackPen ); } } } void wxNewBitmapButton::SetLabel(const wxBitmap& labelBitmap, const wxString& labelText ) { DestroyLabels(); mLabelText = labelText; mDepressedBmp = labelBitmap; //RenderLabelImages(); RenderAllLabelImages(); } void wxNewBitmapButton::SetAlignments( int alignText, int marginX, int marginY, int textToLabelGap) { DestroyLabels(); mMarginX = marginX; mMarginY = marginY; mTextAlignment = alignText; mTextToLabelGap = textToLabelGap; //RenderLabelImages(); RenderAllLabelImages(); } // event handlers void wxNewBitmapButton::OnLButtonDown( wxMouseEvent& event ) { mPrevPressedState = FALSE; mDragStarted = TRUE; mIsPressed = TRUE; Refresh(); if ( !mIsInFocus ) CaptureMouse(); } void wxNewBitmapButton::OnLButtonUp( wxMouseEvent& event ) { if ( !mDragStarted ) return; mDragStarted = FALSE; mIsPressed = FALSE; mIsInFocus = FALSE; Refresh(); ReleaseMouse(); if ( IsInWindow( event.m_x, event.m_y ) ) { // fire event, if mouse was released // within the bounds of button wxCommandEvent cmd( mFiredEventType, GetId() ); GetParent()->ProcessEvent( cmd ); } } bool wxNewBitmapButton::IsInWindow( int x, int y ) { int width, height; GetSize( &width, &height ); return ( x >= 0 && y >= 0 && x < width && y < height ); } void wxNewBitmapButton::OnMouseMove( wxMouseEvent& event ) { mPrevPressedState=mIsPressed; mPrevInFocusState=mIsInFocus; if ( !mIsInFocus && IsInWindow( event.m_x, event.m_y ) ) { if ( !mDragStarted ) CaptureMouse(); mIsInFocus = TRUE; } else if ( mIsInFocus && !IsInWindow( event.m_x, event.m_y ) ) { mIsInFocus = FALSE; if ( !mDragStarted ) ReleaseMouse(); } if ( mDragStarted ) { if ( IsInWindow( event.m_x, event.m_y ) ) mIsPressed = TRUE; else mIsPressed = FALSE; } if ((mIsPressed != mPrevPressedState) || (mIsInFocus!=mPrevInFocusState)) { Refresh(); } } void wxNewBitmapButton::OnSize( wxSizeEvent& event ) { //Reshape(); } void wxNewBitmapButton::Reshape( ) { bool wasCreated = mIsCreated; mIsCreated = TRUE; if ( !wasCreated ) { // in the case of loading button from stream, check if we // have non-empty image-file name, load if possible if ( mImageFileName != "" ) { mDepressedBmp.LoadFile( mImageFileName, mImageFileType ); //wxMessageBox("Image Loaded!!!"); } //RenderLabelImages(); RenderAllLabelImages(); wxBitmap* pCurImg = GetStateLabel(); int w = pCurImg->GetWidth(), h = pCurImg->GetHeight(); SetSize( 0,0, w + mMarginX*2, h + mMarginY*2 , 0 ); } } void wxNewBitmapButton::DrawLabel( wxDC& dc ) { wxBitmap* pCurBmp = GetStateLabel(); if ( pCurBmp == NULL ) { wxSizeEvent evt; OnSize( evt ); // fake it up! //RenderLabelImages(); pCurBmp = GetStateLabel(); } wxMemoryDC mdc; mdc.SelectObject( *pCurBmp ); dc.Blit( mMarginX, mMarginY, pCurBmp->GetWidth(), pCurBmp->GetHeight(), &mdc, 0,0, wxCOPY ); mdc.SelectObject( wxNullBitmap ); } void wxNewBitmapButton::OnPaint( wxPaintEvent& event ) { wxPaintDC dc(this); // first, make sure images for current state are prepared //RenderLabelImages(); DrawLabel( dc ); DrawDecorations( dc ); } void wxNewBitmapButton::OnEraseBackground( wxEraseEvent& event ) { // do nothing } void wxNewBitmapButton::OnKillFocus( wxFocusEvent& event ) { // useless wxMessageBox("kill-focus for button!"); }