Files
wxWidgets/utils/framelayout/src/newbmpbtn.cpp
J. Russell Smyth 8a704c2b39 1. Made use system colors/fonts
2. Made able to use xpm's and honor xpm transparency


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1925 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1999-03-14 00:26:08 +00:00

756 lines
16 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// 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.cpp"
#pragma interface "newbmpbtn.cpp"
#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 "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;
for( int 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 bgCol = GET_ELEM(src,0,0);
int x = 0;
int y = 1;
do
{
int cur = GET_ELEM(src,x,y);
int r = GET_RED(cur);
int g = GET_GREEN(cur);
int b = GET_BLUE(cur);
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 greay_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 y = 0;
for( y = 0; y != height; ++y )
for( int x = 0; x != width; ++x )
{
wxColour col;
dc.GetPixel( x,y, &col );
int r = col.Red(),
g = col.Green(),
b = col.Blue();
int o = MAKE_INT_COLOR( r,g,b );
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( int 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)
: mpDepressedImg( NULL ),
mpPressedImg ( NULL ),
mpDisabledImg ( NULL ),
mpFocusedImg ( NULL ),
mMarginX( marginX ),
mMarginY( marginY ),
mTextAlignment( alignText ),
mIsFlat( isFlat ),
mIsPressed ( FALSE ),
mDragStarted ( FALSE ),
mPrevPressedState( FALSE ),
mTextToLabelGap ( textToLabelGap ),
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 ),
mFiredEventType( firedEventType ),
mIsSticky( isSticky ),
mIsCreated( FALSE ),
mSizeIsSet( FALSE ),
mHasFocusedBmp( FALSE ),
mIsInFocus( FALSE ),
mDepressedBmp( labelBitmap ),
mLabelText( labelText ),
mImageFileType( -1 )
{
}
wxNewBitmapButton::wxNewBitmapButton( const wxString& bitmapFileName,
const int bitmapFileType,
const wxString& labelText,
int alignText,
bool isFlat,
int firedEventType,
int marginX,
int marginY,
int textToLabelGap,
bool isSticky)
: mpDepressedImg( NULL ),
mpPressedImg ( NULL ),
mpDisabledImg ( NULL ),
mpFocusedImg ( NULL ),
mMarginX( 2 ),
mMarginY( 2 ),
mTextAlignment( alignText ),
mIsFlat( isFlat ),
mIsPressed ( FALSE ),
mDragStarted ( FALSE ),
mPrevPressedState( FALSE ),
mTextToLabelGap ( 2 ),
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 ),
mFiredEventType( wxEVT_COMMAND_MENU_SELECTED ),
mIsSticky( FALSE ),
mIsCreated( FALSE ),
mSizeIsSet( FALSE ),
mHasFocusedBmp( FALSE ),
mIsInFocus( FALSE ),
mLabelText( labelText ),
mImageFileName( bitmapFileName ),
mImageFileType( bitmapFileType )
{
//mDepressedBmp.LoadFile( bitmapFileName, bitmapFileType );
}
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;
}
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_SYSTEM_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 wxASSERT(0);// unsupported alignment type
}
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_SYSTEM_FONT) );
// Should be wxSYS_COLOUR_BTNTEXT, but gtk gives white?
destDc.SetTextForeground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT) );
destDc.SetTextBackground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE) );
destDc.DrawText( mLabelText, txtPos.x, txtPos.y );
}
if ( !isEnabled )
greay_out_image_on_dc( destDc, destDim.x, destDim.y );
// 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::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();
}
void wxNewBitmapButton::SetAlignments( int alignText,
int marginX,
int marginY,
int textToLabelGap)
{
DestroyLabels();
mMarginX = marginX;
mMarginY = marginY;
mTextAlignment = alignText;
mTextToLabelGap = textToLabelGap;
RenderLabelImages();
}
// 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 )
{
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 )
Refresh();
mPrevPressedState = mIsPressed;
}
// FOR NOW::
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();
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!");
}