www.pudn.com > EndpointDetection_Pitch.zip > xShadeButton.cpp


// CxShadeButton.cpp : implementation file 
/** 12/05/2001 v1.00 
 * - ing.davide.pizzolato@libero.it 
 ** 23/05/2001 v1.10 
 * - added text shift on button down 
 * - fixed many CxDib bugs 
 * - fixed SHS_HARDBUMP bug 
 * - added icon support 
 * - added text alignment 
 * - added flat style 
 ** 16/06/2001 v1.20 
 * - fixed keyboard shortcut bug 
 * - check box & radio button add on by Rainer@Mangold.com 
 * - 2nd icon & 2nd tooltip add on by Rainer@Mangold.com 
 ** 03/08/2001 v1.30 
 * - fixed SetIcon bug 
 * - added Font support 
 ** 23/09/2001 v1.40 
 * - fixed memory leakage bug in DrawItem() (by David Scambler )  
 * - fixed memory leakage bug in SetIcon() (by Orioli Alessandro )  
 * - fixed second tooltip initialization bug (by Jesper Kinnås) 
 * - added multiline tooltip support (thanks to Derek Lakin) 
 * - fixed OnLButtonUp() problem with drag & drop. (by Hyeonsoo Jung ) 
 ** 28/10/2001 v1.41 
 * - fixed memory leakage bug in SetIcon() and in the destructor. 
 * - added 3rd icon for highlighted state. 
 */ 
 
#include "stdafx.h" 
#include "xShadeButton.h" 
#include "MemDC.h" 
#include "Pitch.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
HWND myHWND; 
extern HWND myHWND; 
int currentDialog; 
extern int currentDialog; 
///////////////////////////////////////////////////////////////////////////// 
// CxDib (under development)  
///////////////////////////////////////////////////////////////////// 
CxDib::CxDib() 
{ 
	hDib=NULL; 
 
	memset(&m_bi,0,sizeof(BITMAPINFOHEADER)); 
    m_bi.biSize = sizeof(BITMAPINFOHEADER); 
 
	m_LineWidth=0; 
	m_nColors=0; 
} 
///////////////////////////////////////////////////////////////////// 
CxDib::~CxDib() 
{ 
	if (hDib) free(hDib); 
} 
///////////////////////////////////////////////////////////////////// 
bool CxDib::IsWin30Dib(){ 
	return ((*(LPDWORD)(hDib))==sizeof(BITMAPINFOHEADER)); 
} 
///////////////////////////////////////////////////////////////////// 
WORD CxDib::GetPaletteSize() 
{ 
//    if (IsWin30Dib()) 
        return (m_nColors * sizeof(RGBQUAD)); 
//    else return (m_nColors * sizeof(RGBTRIPLE)); 
} 
///////////////////////////////////////////////////////////////////// 
BYTE* CxDib::GetBits() 
{  
	if (hDib)	return ((BYTE*)hDib + *(LPDWORD)hDib + GetPaletteSize());  
	return NULL; 
} 
///////////////////////////////////////////////////////////////////// 
HDIB  CxDib::Create(DWORD dwWidth, DWORD dwHeight, WORD wBitCount) 
{ 
    LPBITMAPINFOHEADER  lpbi;	// pointer to BITMAPINFOHEADER 
    DWORD               dwLen;	// size of memory block 
 
	if (hDib) free(hDib); 
	hDib=NULL; 
 
    // Make sure bits per pixel is valid 
    if (wBitCount <= 1)			wBitCount = 1; 
    else if (wBitCount <= 4)	wBitCount = 4; 
    else if (wBitCount <= 8)	wBitCount = 8; 
    else				        wBitCount = 24; 
 
    switch (wBitCount){ 
        case 1: 
            m_nColors = 2; 
			break; 
        case 4: 
            m_nColors = 16; 
			break; 
        case 8: 
            m_nColors = 256; 
			break; 
        default: 
            m_nColors = 0; 
    } 
 
    m_LineWidth = WIDTHBYTES(wBitCount * dwWidth); 
 
    // initialize BITMAPINFOHEADER 
    m_bi.biSize = sizeof(BITMAPINFOHEADER); 
    m_bi.biWidth = dwWidth;         // fill in width from parameter 
    m_bi.biHeight = dwHeight;       // fill in height from parameter 
    m_bi.biPlanes = 1;              // must be 1 
    m_bi.biBitCount = wBitCount;    // from parameter 
    m_bi.biCompression = BI_RGB;     
    m_bi.biSizeImage = m_LineWidth * dwHeight; 
    m_bi.biXPelsPerMeter = 0; 
    m_bi.biYPelsPerMeter = 0; 
    m_bi.biClrUsed = 0; 
    m_bi.biClrImportant = 0; 
 
    // calculate size of memory block required to store the DIB.  This 
    // block should be big enough to hold the BITMAPINFOHEADER, the color 
    // table, and the bits 
    dwLen = GetSize(); 
 
	//hDib = malloc(dwLen); // alloc memory block to store our bitmap 
	hDib = new (HDIB[dwLen]); //fixes allocation problem under Win2k 
    if (!hDib) return NULL; 
 
    // use our bitmap info structure to fill in first part of 
    // our DIB with the BITMAPINFOHEADER 
	lpbi = (LPBITMAPINFOHEADER)(hDib); 
    *lpbi = m_bi; 
 
    return hDib; //return handle to the DIB 
} 
///////////////////////////////////////////////////////////////////// 
long CxDib::Draw(HDC pDC, long xoffset, long yoffset) 
{ 
	if((hDib)&&(pDC))  { 
		//palette must be correctly filled 
		LPSTR lpDIB = (char*)hDib;	//set image to hdc... 
		SetStretchBltMode(pDC,COLORONCOLOR);	 
		SetDIBitsToDevice(pDC, xoffset, yoffset, 
			m_bi.biWidth, m_bi.biHeight, 0, 0, 0, 
			m_bi.biHeight, GetBits(), 
			(BITMAPINFO*)lpDIB, DIB_RGB_COLORS); 
		return 1; 
	}  
	return 0; 
} 
///////////////////////////////////////////////////////////////////// 
long CxDib::Stretch(HDC pDC, long xoffset, long yoffset, long xsize, long ysize) 
{ 
	if((hDib)&&(pDC)) { 
		//palette must be correctly filled 
		LPSTR lpDIB = (char*)hDib;	//set image to hdc... 
		SetStretchBltMode(pDC,COLORONCOLOR);	 
		StretchDIBits(pDC, xoffset, yoffset, 
					xsize, ysize, 0, 0, m_bi.biWidth, m_bi.biHeight, 
					GetBits(),(BITMAPINFO*)lpDIB,DIB_RGB_COLORS,SRCCOPY); 
		return 1; 
	} 
	return 0; 
} 
///////////////////////////////////////////////////////////////////// 
void CxDib::SetPaletteIndex(BYTE idx, BYTE r, BYTE g, BYTE b) 
{ 
	if ((hDib)&&(m_nColors)){ 
		BYTE* iDst = (BYTE*)(hDib) + sizeof(BITMAPINFOHEADER); 
		if ((idx>=0)&&(idx=0)&&(idx=0)&&(idx=0)&&(idx=m_bi.biWidth)||(y>=m_bi.biHeight)) return 0; 
	BYTE* iDst = GetBits(); 
	return iDst[(m_bi.biHeight - y - 1)*m_LineWidth + x]; 
} 
///////////////////////////////////////////////////////////////////// 
RGBQUAD CxDib::GetPixelColor(long x,long y) 
{ 
	RGBQUAD rgb={0,0,0,0}; 
	if ((hDib==NULL)||(x<0)||(y<0)|| 
		(x>=m_bi.biWidth)||(y>=m_bi.biHeight)) return rgb; 
	if (m_nColors) return GetPaletteIndex(GetPixelIndex(x,y)); 
	else { 
		BYTE* iDst = GetBits()+(m_bi.biHeight - y - 1)*m_LineWidth + x*sizeof(RGBQUAD); 
		rgb.rgbBlue = *iDst++; 
		rgb.rgbGreen= *iDst++; 
		rgb.rgbRed =*iDst; 
		return rgb; 
	} 
} 
///////////////////////////////////////////////////////////////////// 
void CxDib::SetPixelIndex(long x,long y,BYTE i) 
{ 
	if ((hDib==NULL)||(m_nColors==0)|| 
		(x<0)||(y<0)||(x>=m_bi.biWidth)||(y>=m_bi.biHeight)) return ; 
	BYTE* iDst = GetBits(); 
	iDst[(m_bi.biHeight - y - 1)*m_LineWidth + x]=i; 
} 
///////////////////////////////////////////////////////////////////// 
void CxDib::SetPixelColor(long x,long y,COLORREF cr) 
{ 
	SetPixelColor(x,y,RGB2RGBQUAD(cr)); 
} 
///////////////////////////////////////////////////////////////////// 
void CxDib::SetPixelColor(long x,long y,RGBQUAD c) 
{ 
	if ((hDib==NULL)||(x<0)||(y<0)|| 
		(x>=m_bi.biWidth)||(y>=m_bi.biHeight)) return; 
	if (m_nColors) 
		SetPixelIndex(x,y,GetNearestIndex(c)); 
	else { 
		BYTE* iDst = GetBits()+(m_bi.biHeight - y - 1)*m_LineWidth + x*sizeof(RGBQUAD); 
		*(RGBQUAD*)iDst = c; 
	} 
} 
///////////////////////////////////////////////////////////////////// 
BYTE CxDib::GetNearestIndex(RGBQUAD c) 
{ 
	if ((hDib==NULL)||(m_nColors==0)) return 0; 
	BYTE* iDst = (BYTE*)(hDib) + sizeof(BITMAPINFOHEADER); 
	long distance=200000; 
	BYTE i,j; 
	long k,l; 
	for(i=0,l=0;i achromatic case */ 
		S = 0;					/* saturation */ 
		H = UNDEFINED;			/* hue */ 
	} else {					/* chromatic case */ 
		if (L <= (HSLMAX/2))	/* saturation */ 
			S = (((cMax-cMin)*HSLMAX)+((cMax+cMin)/2))/(cMax+cMin); 
		else 
			S = (((cMax-cMin)*HSLMAX)+((2*RGBMAX-cMax-cMin)/2))/(2*RGBMAX-cMax-cMin); 
		/* hue */ 
		Rdelta = ( ((cMax-R)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin); 
		Gdelta = ( ((cMax-G)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin); 
		Bdelta = ( ((cMax-B)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin); 
 
		if (R == cMax) 
			H = Bdelta - Gdelta; 
		else if (G == cMax) 
			H = (HSLMAX/3) + Rdelta - Bdelta; 
		else /* B == cMax */ 
			H = ((2*HSLMAX)/3) + Gdelta - Rdelta; 
 
		if (H < 0) H += HSLMAX; 
		if (H > HSLMAX) H -= HSLMAX; 
	} 
	RGBQUAD hsl={L,S,H,0}; 
	return hsl; 
} 
///////////////////////////////////////////////////////////////////// 
WORD CxDib::HueToRGB(WORD n1,WORD n2,WORD hue) 
{  
	/* range check: note values passed add/subtract thirds of range */ 
	if (hue < 0) hue += HSLMAX; 
	if (hue > HSLMAX) hue -= HSLMAX; 
 
	/* return r,g, or b value from this tridrant */ 
	if (hue < (HSLMAX/6)) 
		return ( n1 + (((n2-n1)*hue+(HSLMAX/12))/(HSLMAX/6)) ); 
	if (hue < (HSLMAX/2)) 
		return ( n2 ); 
	if (hue < ((HSLMAX*2)/3)) 
		return ( n1 + (((n2-n1)*(((HSLMAX*2)/3)-hue)+(HSLMAX/12))/(HSLMAX/6)));  
	else 
		return ( n1 ); 
}  
///////////////////////////////////////////////////////////////////// 
RGBQUAD CxDib::HSLtoRGB(COLORREF cHSLColor) 
{ 
	return HSLtoRGB(RGB2RGBQUAD(cHSLColor)); 
} 
///////////////////////////////////////////////////////////////////// 
RGBQUAD CxDib::HSLtoRGB(RGBQUAD lHSLColor) 
{  
	WORD hue,lum,sat; 
	BYTE R,G,B;					/* RGB component values */ 
	WORD Magic1,Magic2;			/* calculated magic numbers (really!) */ 
 
	hue = lHSLColor.rgbRed;	/* get H, S, and L out of DWORD */ 
	sat = lHSLColor.rgbGreen; 
	lum = lHSLColor.rgbBlue; 
 
	if (sat == 0) {            /* achromatic case */ 
		R=G=B=(lum*RGBMAX)/HSLMAX; 
	} else {                   /* chromatic case */ 
		/* set up magic numbers */ 
		if (lum <= (HSLMAX/2)) 
			Magic2 = (lum*(HSLMAX + sat) + (HSLMAX/2))/HSLMAX; 
		else 
			Magic2 = lum + sat - ((lum*sat) + (HSLMAX/2))/HSLMAX; 
		Magic1 = 2*lum-Magic2; 
 
		/* get RGB, change units from HSLMAX to RGBMAX */ 
		R = (HueToRGB(Magic1,Magic2,(WORD)(hue+(HSLMAX/3)))*RGBMAX+(HSLMAX/2))/HSLMAX;  
		G = (HueToRGB(Magic1,Magic2,hue)*RGBMAX + (HSLMAX/2)) / HSLMAX; 
		B = (HueToRGB(Magic1,Magic2,(WORD)(hue-(HSLMAX/3)))*RGBMAX+(HSLMAX/2))/HSLMAX;  
	} 
	RGBQUAD rgb={B,G,R,0}; 
	return rgb; 
} 
///////////////////////////////////////////////////////////////////// 
RGBQUAD CxDib::RGB2RGBQUAD(COLORREF cr) 
{ 
	RGBQUAD c; 
	c.rgbRed = GetRValue(cr);	/* get R, G, and B out of DWORD */ 
	c.rgbGreen = GetGValue(cr); 
	c.rgbBlue = GetBValue(cr); 
	c.rgbReserved=0; 
	return c; 
} 
///////////////////////////////////////////////////////////////////// 
COLORREF CxDib::RGBQUAD2RGB (RGBQUAD c) 
{ 
	return RGB(c.rgbRed,c.rgbGreen,c.rgbBlue); 
} 
///////////////////////////////////////////////////////////////////// 
void CxDib::SetGrayPalette() 
{ 
	if ((hDib==NULL)||(m_nColors==0)) return; 
	RGBQUAD pal[256]; 
	RGBQUAD* ppal; 
	BYTE* iDst; 
	int ni; 
	ppal=(RGBQUAD*)&pal[0]; 
	iDst = (BYTE*)(hDib) + sizeof(BITMAPINFOHEADER); 
	for (ni=0;ni100) perc=100; 
	for(i=0;i no overlapped) 
		hFile,			// handle of file to write  
		(LPSTR) &hdr,	// address of buffer that contains data   
		sizeof(BITMAPFILEHEADER),	// number of bytes to write  
		&nByteWrite,	// address of number of bytes written  
		NULL	 		// address of structure for data  
		); 
 
    // Write the DIB header and the bits 
	WriteFile(			// write ini (sync mode <-> no overlapped) 
		hFile,			// handle of file to write  
		(LPSTR) hDib,	// address of buffer that contains data   
		GetSize(),		// number of bytes to write  
		&nByteWrite,	// address of number of bytes written  
		NULL	 		// address of structure for data  
		); 
 
	CloseHandle(hFile);		//free file handle 
	return 1; 
} 
///////////////////////////////////////////////////////////////////// 
long CxDib::GetSize() 
{ 
	return m_bi.biSize + m_bi.biSizeImage + GetPaletteSize(); 
} 
///////////////////////////////////////////////////////////////////// 
BOOL CxDib::IsValid() 
{ 
	return (hDib!=NULL); 
} 
///////////////////////////////////////////////////////////////////// 
void CxDib::Clone(CxDib *src) 
{ 
 	Create(src->GetWidth(),src->GetHeight(),src->GetBitCount()); 
 	if (hDib) memcpy(hDib,src->hDib,GetSize()); 
} 
///////////////////////////////////////////////////////////////////// 
void CxDib::Clear(BYTE bval) 
{ 
	if (hDib) memset(GetBits(),bval,m_bi.biSizeImage); 
} 
///////////////////////////////////////////////////////////////////// 
 
 
 
 
 
 
 
 
 
 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CxShadeButton 
CxShadeButton::CxShadeButton() 
{ 
	m_Border=1;				//draw 3D border 
	m_FocusRectMargin=4;	//focus dotted rect margin 
	m_TextColor=GetSysColor(COLOR_BTNTEXT); // default button text color 
	m_flat = m_Checked = m_button_down = m_tracking = false; 
 
	m_Icon=m_IconDown=m_IconHighLight=NULL;	// icon handle 
	m_IconBox.SetRectEmpty(); //icon location 
	m_IconAlign=BS_CENTER;	//icon alignment 
	m_TextAlign=DT_CENTER;	//text alignment 
	m_pLF=NULL;				//font structure pointer 
} 
///////////////////////////////////////////////////////////////////////////// 
CxShadeButton::~CxShadeButton() 
{ 
	m_Font.DeleteObject(); 
	if (m_pLF)	free(m_pLF); 
	if (m_IconDown!=m_Icon && m_IconDown) DestroyIcon(m_IconDown); 
	if (m_IconHighLight!=m_Icon && m_IconHighLight) DestroyIcon(m_IconHighLight); 
	if (m_Icon) DestroyIcon(m_Icon); 
} 
///////////////////////////////////////////////////////////////////////////// 
BEGIN_MESSAGE_MAP(CxShadeButton, CButton) 
	//{{AFX_MSG_MAP(CxShadeButton) 
	ON_WM_ERASEBKGND() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_MOUSEMOVE() 
	ON_WM_LBUTTONDBLCLK() 
	ON_WM_KILLFOCUS() 
	//ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked) 
	ON_WM_KEYDOWN() 
	//}}AFX_MSG_MAP 
    ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) 
	ON_MESSAGE(WM_CXSHADE_RADIO , OnRadioInfo) 
	ON_MESSAGE(BM_SETCHECK , OnBMSetCheck) 
	ON_MESSAGE(BM_GETCHECK , OnBMGetCheck) 
END_MESSAGE_MAP() 
///////////////////////////////////////////////////////////////////////////// 
// CxShadeButton message handlers 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::PreSubclassWindow()  
{ 
	m_Style=GetStyle(); //get general button styles 
	m_IsPushLike=((m_Style & BS_PUSHLIKE)!=0); 
	m_flat=((m_Style & BS_FLAT)!=0); 
	SetTextAlign(m_Style & 0x0300); 
 
	m_Style=GetButtonStyle();	///get specific BS_ styles 
	if ((m_Style & BS_AUTOCHECKBOX)==BS_AUTOCHECKBOX) 
//		||((m_Style & BS_CHECKBOX)==BS_CHECKBOX)) 
		m_Style=BS_CHECKBOX; 
	else if ((m_Style & BS_AUTORADIOBUTTON)==BS_AUTORADIOBUTTON) 
//			||((m_Style & BS_RADIOBUTTON)==BS_RADIOBUTTON)) 
		m_Style=BS_RADIOBUTTON; 
	else { m_Style=BS_PUSHBUTTON; m_IsPushLike=true;} 
 
	//default radio & check-box has no border 
	if (!m_IsPushLike) m_Border = false; 
 
	CButton::PreSubclassWindow(); 
	ModifyStyle(0, BS_OWNERDRAW); 
} 
///////////////////////////////////////////////////////////////////////////// 
BOOL CxShadeButton::OnEraseBkgnd(CDC* pDC)  
{ return 1; }	// doesn't erase the button background 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
{ 
    ASSERT (lpDrawItemStruct); 
    //TRACE("* Captured: %08X\n", ::GetCapture()); 
 
    //Check if the button state in not in inconsistent mode... 
    POINT mouse_position; 
    if ((m_button_down) && (::GetCapture() == m_hWnd) && (::GetCursorPos(&mouse_position))){ 
		if (::WindowFromPoint(mouse_position) == m_hWnd){ 
			if ((GetState() & BST_PUSHED) != BST_PUSHED) { 
				//TRACE("* Inconsistency up detected! Fixing.\n"); 
				SetState(TRUE); 
				return; 
			} 
		} else { 
			if ((GetState() & BST_PUSHED) == BST_PUSHED) { 
				//TRACE("* Inconsistency up detected! Fixing.\n"); 
				SetState(FALSE); 
				return; 
	}	}	} 
	 
    //TRACE("* Drawing: %08x\n", lpDrawItemStruct->itemState); 
	CString sCaption; 
	CDC *pRealDC = CDC::FromHandle(lpDrawItemStruct->hDC);	// get device context 
	RECT r=lpDrawItemStruct->rcItem;					// context rectangle 
	int cx = r.right  - r.left ;						// get width 
	int cy = r.bottom - r.top  ;						// get height 
	// get text box position 
	RECT tr={r.left+m_FocusRectMargin+2,r.top,r.right-m_FocusRectMargin-2,r.bottom}; 
 
	CDC hdcMem;	//create a memory DC to avoid flicker 
	hdcMem.CreateCompatibleDC(pRealDC); 
	CDC* pDC = &hdcMem; //(just use pRealDC to paint directly the screen) 
    CBitmap hBitmap; //create a destination for raster operations 
	hBitmap.CreateCompatibleBitmap(pRealDC,cx,cy); 
	CBitmap* pOldBitmap = hdcMem.SelectObject(&hBitmap); //select the destination for MemDC 
 
	GetWindowText(sCaption);							// get button text 
	pDC->SetBkMode(TRANSPARENT); 
	// with MemDC we need to select the font... 
 
	//get text font 
	CFont* pOldFont=NULL; 
	if (m_Font.m_hObject) pOldFont = pDC->SelectObject(&m_Font); 
	else pDC->SelectObject(GetStockObject(DEFAULT_GUI_FONT)); 
//	TEXTMETRIC tm; 
//	pDC->GetTextMetrics(&tm);							// get font metrics 
 
	// accommodate text location 
	if (m_Icon){ 
		switch (m_IconAlign){ 
		case BS_LEFT: 
			tr.left+=m_IconBox.Width();		// shift left 
			break; 
		case BS_RIGHT: 
			tr.right-=m_IconBox.Width();	// shift right 
			break; 
		case BS_CENTER: 
			tr.top+=m_IconBox.bottom;		// shift text under the icon 
			tr.bottom-=m_FocusRectMargin + 1; 
		} 
	} 
	// Select the correct skin  
	if (lpDrawItemStruct->itemState & ODS_DISABLED){	// DISABLED BUTTON 
		if(m_dDisabled.IsValid())	// paint the skin 
			m_dDisabled.Draw(pDC->GetSafeHdc(),0,0); 
		else	// no skin selected for disabled state -> standard button 
			pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE)); 
 
		if (m_Icon)	//draw the icon 
			pDC->DrawState(m_IconBox.TopLeft(),m_IconBox.Size(), 
				m_Icon,DSS_DISABLED,(CBrush*)NULL); 
 
		// if needed, draw the standard 3D rectangular border 
		if ((m_Border)&&(m_flat==FALSE)) pDC->DrawEdge(&r,EDGE_RAISED,BF_RECT); 
		// paint the etched button text 
		pDC->SetTextColor(GetSysColor(COLOR_3DHILIGHT)); 
		pDC->DrawText(sCaption,&tr,m_TextAlign); 
		pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT)); 
		OffsetRect(&tr,-1,-1); 
		pDC->DrawText(sCaption,&tr,m_TextAlign); 
	} else { 
//--------------------------------------------------------------------------- 
		if ((lpDrawItemStruct->itemState & ODS_SELECTED)||m_Checked){ //SELECTED (DOWN) BUTTON 
			if(m_dDown.IsValid())	// paint the skin 
				m_dDown.Draw(pDC->GetSafeHdc(),m_Border,m_Border); 
			else	// no skin selected for selected state -> standard button 
				pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE)); 
 
			if (m_IconDown){ //draw the pushed icon 
				if (m_IsPushLike) m_IconBox.OffsetRect(1,1); 
				pDC->DrawState(m_IconBox.TopLeft(),m_IconBox.Size(), 
								m_IconDown,DSS_NORMAL,(CBrush*)NULL); 
				if (m_IsPushLike) m_IconBox.OffsetRect(-1,-1); 
			} 
			//shift text 
			if (m_IsPushLike) OffsetRect(&tr,1,1); 
			// if needed, draw the standard 3D rectangular border 
			if (m_Border){ 
				if (m_flat) pDC->Draw3dRect(&r,GetSysColor(COLOR_BTNSHADOW),GetSysColor(COLOR_BTNHILIGHT)); 
				else		pDC->DrawEdge(&r,EDGE_SUNKEN,BF_RECT); 
			} 
		} else { 
//--------------------------------------------------------------------------- 
			if(m_dNormal.IsValid()){ // paint the skin			// DEFAULT BUTTON 
                if ((m_tracking)&&(m_dOver.IsValid())){ 
					m_dOver.Draw(pDC->GetSafeHdc(),0,0); 
				} else { 
					m_dNormal.Draw(pDC->GetSafeHdc(),0,0); 
				} 
			} else	// no skin selected for normal state -> standard button 
				pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE)); 
 
			if (m_IconHighLight && m_tracking) { // draw the highlighted icon 
				pDC->DrawState(m_IconBox.TopLeft(),m_IconBox.Size(), 
								m_IconHighLight,DSS_NORMAL,(CBrush*)NULL); 
			} else if (m_Icon) //draw the icon 
				pDC->DrawState(m_IconBox.TopLeft(),m_IconBox.Size(), 
								m_Icon,DSS_NORMAL,(CBrush*)NULL); 
 
			// if needed, draw the standard 3D rectangular border 
			if ((m_Border)&&((m_tracking)||(m_flat==FALSE))){ 
				if (lpDrawItemStruct->itemState & ODS_DEFAULT){ 
					pDC->DrawEdge(&r,EDGE_SUNKEN,BF_RECT); 
					InflateRect(&r,-1,-1); 
					pDC->DrawEdge(&r,EDGE_RAISED,BF_RECT); 
				} else { 
					if (m_flat) pDC->Draw3dRect(&r,GetSysColor(COLOR_BTNHILIGHT),GetSysColor(COLOR_BTNSHADOW)); 
					else		pDC->DrawEdge(&r,EDGE_RAISED,BF_RECT); 
				} 
			} 
//--------------------------------------------------------------------------- 
		} 
		// paint the focus rect 
		if ((lpDrawItemStruct->itemState & ODS_FOCUS)&&(m_FocusRectMargin>0)){ 
			InflateRect(&r,-m_FocusRectMargin,-m_FocusRectMargin); 
			m_dh.Draw(pDC->GetSafeHdc(),1+r.left,r.top); 
			m_dh.Draw(pDC->GetSafeHdc(),1+r.left,r.bottom); 
			m_dv.Draw(pDC->GetSafeHdc(),r.left,1+r.top); 
			m_dv.Draw(pDC->GetSafeHdc(),r.right,1+r.top); 
		} 
		// paint the enabled button text 
		pDC->SetTextColor(m_TextColor); 
		pDC->DrawText(sCaption,&tr,m_TextAlign); 
	} 
 
	if (pOldFont) pDC->SelectObject(pOldFont);	//restore the old font object 
 
	pRealDC->BitBlt(0,0,cx,cy,&hdcMem,0,0,SRCCOPY); //copy in the real world 
	//restore the old objects to avoid memory leakage  
	if (pOldBitmap)	hdcMem.SelectObject(pOldBitmap); 
//	hdcMem.DeleteDC(); the destructor will do this for us 
//	hBitmap.DeleteObject(); the destructor will do this for us 
 
} 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::SetShade(UINT shadeID,BYTE granularity,BYTE highlight,BYTE coloring,COLORREF color) 
{ 
	long	sXSize,sYSize,bytes,j,i,k,h; 
	BYTE	*iDst ,*posDst; 
	 
	RECT rect; 
	GetWindowRect(&rect); 
	sYSize=rect.bottom-rect.top; 
	sXSize=rect.right-rect.left ; 
 
	m_dh.Create(max(1,sXSize-2*m_FocusRectMargin-1),1,8);	//create the horizontal focus bitmap 
	m_dv.Create(1,max(1,sYSize-2*m_FocusRectMargin),8);	//create the vertical focus bitmap 
 
	m_dNormal.Create(sXSize,sYSize,8);					//create the default bitmap 
 
	COLORREF hicr=GetSysColor(COLOR_BTNHIGHLIGHT);		//get the button base colors 
	COLORREF midcr=GetSysColor(COLOR_BTNFACE); 
	COLORREF locr=GetSysColor(COLOR_BTNSHADOW); 
	long r,g,b;											//build the shaded palette 
	for(i=0;i<129;i++){ 
		r=((128-i)*GetRValue(locr)+i*GetRValue(midcr))/128; 
		g=((128-i)*GetGValue(locr)+i*GetGValue(midcr))/128; 
		b=((128-i)*GetBValue(locr)+i*GetBValue(midcr))/128; 
		m_dNormal.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dh.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dv.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b); 
	} 
	for(i=1;i<129;i++){ 
		r=((128-i)*GetRValue(midcr)+i*GetRValue(hicr))/128; 
		g=((128-i)*GetGValue(midcr)+i*GetGValue(hicr))/128; 
		b=((128-i)*GetBValue(midcr)+i*GetBValue(hicr))/128; 
		m_dNormal.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dh.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b); 
		m_dv.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b); 
	} 
 
	m_dNormal.BlendPalette(color,coloring);	//color the palette 
 
	iDst=m_dh.GetBits();		//build the horiz. dotted focus bitmap 
	j=(long)m_dh.GetWidth(); 
	for(i=0;i0)&&((y+i)0)) 
					m_dNormal.SetPixelIndex(sXSize-x+i,y-i,(BYTE)d); 
			} 
		} 
		//blend strokes with SHS_DIAGONAL 
		posDst =iDst; 
		a=(idxmax-idxmin-k)/2; 
		for(i = 0; i < sYSize; i++) { 
			for(j = 0; j < sXSize; j++) { 
				d=posDst[j]+((a*i)/sYSize+(a*(sXSize-j))/sXSize); 
				posDst[j]=(BYTE)d; 
				posDst[j]+=rand()/grainx2; 
			} 
			posDst+=bytes; 
		} 
 
		break; 
//---------------------------------------------------- 
	case 7:	// SHS_HARDBUMP 
		//set horizontal bump 
		for(i = 0; i < sYSize; i++) { 
			k=(255*i/sYSize)-127; 
			k=(k*(k*k)/128)/128; 
			k=(k*(128-granularity*2))/128+128; 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		//set vertical bump 
		d=min(16,sXSize/6);	//max edge=16 
		a=sYSize*sYSize/4; 
		posDst =iDst; 
		for(i = 0; i < sYSize; i++) { 
			y=i-sYSize/2; 
			for(j = 0; j < sXSize; j++) { 
				x=j-sXSize/2; 
				xs=sXSize/2-d+(y*y*d)/a; 
				if (x>xs) posDst[j]=idxmin+(BYTE)(((sXSize-j)*128)/d); 
				if ((x+xs)<0) posDst[j]=idxmax-(BYTE)((j*128)/d); 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case 6: //SHS_SOFTBUMP 
		for(i = 0; i < sYSize; i++) { 
			h=(255*i/sYSize)-127; 
			for(j = 0; j < sXSize; j++) { 
				k=(255*(sXSize-j)/sXSize)-127; 
				k=(h*(h*h)/128)/128+(k*(k*k)/128)/128; 
				k=k*(128-granularity)/128+128; 
				if (kidxmax) k=idxmax; 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case 5: // SHS_VBUMP 
		for(j = 0; j < sXSize; j++) { 
			k=(255*(sXSize-j)/sXSize)-127; 
			k=(k*(k*k)/128)/128; 
			k=(k*(128-granularity))/128+128; 
			for(i = 0; i < sYSize; i++) { 
				posDst[j+i*bytes]=(BYTE)k; 
				posDst[j+i*bytes]+=rand()/grainx2-granularity; 
			} 
		} 
		break; 
//---------------------------------------------------- 
	case 4: //SHS_HBUMP 
		for(i = 0; i < sYSize; i++) { 
			k=(255*i/sYSize)-127; 
			k=(k*(k*k)/128)/128; 
			k=(k*(128-granularity))/128+128; 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case 1:	//SHS_DIAGSHADE 
		a=(idxmax-idxmin)/2; 
		for(i = 0; i < sYSize; i++) { 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)(idxmin+a*i/sYSize+a*(sXSize-j)/sXSize); 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case 2:	//SHS_HSHADE 
		a=idxmax-idxmin; 
		for(i = 0; i < sYSize; i++) { 
			k=a*i/sYSize+idxmin; 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=(BYTE)k; 
				posDst[j]+=rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
		break; 
//---------------------------------------------------- 
	case 3:	//SHS_VSHADE: 
		a=idxmax-idxmin; 
		for(j = 0; j < sXSize; j++) { 
			k=a*(sXSize-j)/sXSize+idxmin; 
			for(i = 0; i < sYSize; i++) { 
				posDst[j+i*bytes]=(BYTE)k; 
				posDst[j+i*bytes]+=rand()/grainx2-granularity; 
			} 
		} 
		break; 
//---------------------------------------------------- 
	default:	//SHS_NOISE 
		for(i = 0; i < sYSize; i++) { 
			for(j = 0; j < sXSize; j++) { 
				posDst[j]=128+rand()/grainx2-granularity; 
			} 
			posDst+=bytes; 
		} 
	} 
//---------------------------------------------------- 
	m_dDisabled.Clone(&m_dNormal);	//build the other bitmaps 
	m_dOver.Clone(&m_dNormal); 
	m_dOver.BlendPalette(hicr,highlight); 
	m_dDown.Clone(&m_dOver); 
} 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::SetIcon(UINT nIcon, UINT nIconAlign, UINT nIconDown, UINT nIconHighLight) 
{ 
	if (m_IconDown!=m_Icon && m_IconDown) DestroyIcon(m_IconDown); 
	if (m_IconHighLight!=m_Icon && m_IconHighLight) DestroyIcon(m_IconHighLight); 
	if (m_Icon) DestroyIcon(m_Icon); 
		 
	m_Icon = (HICON)::LoadImage(AfxGetInstanceHandle(), 
								MAKEINTRESOURCE(nIcon), 
								IMAGE_ICON, 0, 0, 0); 
	if (m_Icon){							// if success... 
		ICONINFO iinfo;						// get icon info 
		GetIconInfo(m_Icon, &iinfo); 
		m_IconBox.left=m_IconBox.top=0; 
		m_IconBox.right = iinfo.xHotspot * 2; 
		m_IconBox.bottom = iinfo.yHotspot * 2; 
 
		long x,y; 
		RECT rect; 
		GetWindowRect(&rect); 
		y=rect.bottom-rect.top; 
		x=rect.right-rect.left; 
		switch (nIconAlign){				//set the icon location 
		case BS_RIGHT: 
			m_IconAlign=BS_RIGHT; 
			m_IconBox.OffsetRect(x - iinfo.xHotspot*2 - m_FocusRectMargin, 
								 max(0, (long)(y/2 - iinfo.yHotspot))); 
			break; 
		case BS_LEFT: 
			m_IconAlign=BS_LEFT; 
			m_IconBox.OffsetRect(m_FocusRectMargin, 
								 max(0, (long)(y/2 - iinfo.yHotspot))); 
			break; 
		default: 
			m_IconAlign=BS_CENTER; 
			m_IconBox.OffsetRect(max(0, (long)(x/2 - iinfo.xHotspot)), 
								 max(0, (long)(y/2 - 2*iinfo.yHotspot))); 
		} 
 
		//release icon mask bitmaps (Orioli Alessandro ) 
		if( iinfo.hbmColor ) DeleteObject( iinfo.hbmColor ); 
		if( iinfo.hbmMask ) DeleteObject( iinfo.hbmMask ); 
 
		if (nIconDown > 0){	//load down icon 
			m_IconDown = (HICON)::LoadImage(AfxGetInstanceHandle(), 
											MAKEINTRESOURCE(nIconDown), 
											IMAGE_ICON, 0, 0, 0); 
			if (m_IconDown==NULL) m_IconDown= m_Icon; 
		} else { m_IconDown= m_Icon; }	//reuse resource handle 
 
		if (nIconHighLight > 0){	//load highlighted icon 
			m_IconHighLight = (HICON)::LoadImage(AfxGetInstanceHandle(), 
											MAKEINTRESOURCE(nIconHighLight), 
											IMAGE_ICON, 0, 0, 0); 
			if (m_IconHighLight==NULL) m_IconHighLight= m_Icon; 
		} else { m_IconHighLight= m_Icon; }	//reuse resource handle 
	} 
} 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::SetTextAlign(UINT nTextAlign) 
{ 
//	see DrawText() styles... 
	switch (nTextAlign){ 
	case BS_RIGHT: 
		m_TextAlign=DT_RIGHT; 
		break; 
	case BS_LEFT: 
		m_TextAlign=DT_LEFT; 
		break; 
	default: 
		m_TextAlign=DT_CENTER; 
	} 
	m_TextAlign|=(DT_SINGLELINE|DT_VCENTER); 
} 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::SetFlat(bool bFlag) 
{ m_flat=bFlag; }	//set flat border mode 
///////////////////////////////////////////////////////////////////////////// 
COLORREF CxShadeButton::SetTextColor(COLORREF new_color) 
{ 
	COLORREF tmp_color=m_TextColor; 
	m_TextColor=new_color; 
	return tmp_color;			//returns the previous color 
} 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::SetToolTipText(CString s, CString sDown) 
{ 
	m_ToolTipUp = s;		//normal tooltip 
	m_ToolTipDw = sDown;	//tooltip for checked state 
 
	//select the down tooltip if the button is already checked  
	if (m_Checked && !m_ToolTipDw.IsEmpty()) s = m_ToolTipDw; 
	 
	if(m_tooltip.m_hWnd==NULL){ 
		if(m_tooltip.Create(this))	//first assignment 
			if(m_tooltip.AddTool(this, (LPCTSTR)s)){ 
				m_tooltip.Activate(1); 
				// enable multiline tooltips  
				m_tooltip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 300); 
			} 
	} else { 
		m_tooltip.UpdateTipText((LPCTSTR)s,this); 
	} 
} 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::RelayEvent(UINT message, WPARAM wParam, LPARAM lParam) 
{ 
// This function will create a MSG structure, fill it in a pass it to 
// the ToolTip control, m_ttip.  Note that we ensure the point is in window 
// coordinates (relative to the control's window). 
	if(NULL != m_tooltip.m_hWnd){ 
		MSG msg; 
		msg.hwnd = m_hWnd; 
		msg.message = message; 
		msg.wParam = wParam; 
		msg.lParam = lParam; 
		msg.time = 0; 
		msg.pt.x = LOWORD(lParam); 
		msg.pt.y = HIWORD(lParam); 
 
		m_tooltip.RelayEvent(&msg); 
	} 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnLButtonDblClk 
//Class.......: CxShadeButton 
// 
//Author......: Milan Gardian 
//Created.....: MAR-2001 
// 
//Return value: NONE 
//Parameters..: Used only to be forwarded as WM_LBUTTONDOWN message parameters 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > We do not care about doublelicks - handle this event 
//    like an ordinary left-button-down event 
//--------------------------------------------------------- 
void CxShadeButton::OnLButtonDblClk(UINT flags, CPoint point)  
{ 
    SendMessage(WM_LBUTTONDOWN, flags, MAKELPARAM(point.x, point.y)); 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnLButtonDown 
//Class.......: CxShadeButton 
// 
//Author......: Milan Gardian 
//Created.....: MAR-2001 
// 
//Return value: NONE 
//Parameters..: As follows 
//    > [in] nFlags: not used 
//    > [in] point: coordinates of the mouse pointer when this event was spawned 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > Handle event when left button is pressed down 
//--------------------------------------------------------- 
void CxShadeButton::OnLButtonDown(UINT nFlags, CPoint point) 
{ 
    //TRACE("* %08X: down\n", ::GetTickCount()); 
 
	//Pass this message to the ToolTip control 
	RelayEvent(WM_LBUTTONDOWN,(WPARAM)nFlags,MAKELPARAM(LOWORD(point.x),LOWORD(point.y))); 
 
    //If we are tracking this button, cancel it 
    if (m_tracking) { 
        TRACKMOUSEEVENT t = { 
            sizeof(TRACKMOUSEEVENT), 
            TME_CANCEL | TME_LEAVE, 
            m_hWnd, 0 
		}; 
        if (::_TrackMouseEvent(&t)) { 
            m_tracking = false; 
        } 
    } 
 
    //Default-process the message 
	CButton::OnLButtonDown(nFlags, point); 
    m_button_down = true; 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnLButtonUp 
//Class.......: CxShadeButton 
// 
//Author......: Milan Gardian 
//Created.....: MAR-2001 
// 
//Return value: NONE 
//Parameters..: As follows 
//    > [in] nFlags: not used 
//    > [in] point: coordinates of the mouse pointer when this event was spawned 
//Exceptions..: NONE 
//------------ 
//Description : 
// 
//  > Handle event when left button is released (goes up) 
//--------------------------------------------------------- 
void CxShadeButton::OnLButtonUp(UINT nFlags, CPoint point) 
{ 
    //TRACE("* %08X: up\n", ::GetTickCount()); 
 
	if (m_Style){ //track mouse for radio & check buttons 
		POINT p2 = point; 
		::ClientToScreen(m_hWnd, &p2); 
		HWND mouse_wnd = ::WindowFromPoint(p2); 
		if (mouse_wnd == m_hWnd && m_button_down == true){ // mouse is in button 
			if (m_Style==BS_CHECKBOX) SetCheck(m_Checked ? 0 : 1); 
			if (m_Style==BS_RADIOBUTTON) SetCheck(1); 
		} 
	} 
 
	//Pass this message to the ToolTip control 
	RelayEvent(WM_LBUTTONUP,(WPARAM)nFlags,MAKELPARAM(LOWORD(point.x),LOWORD(point.y))); 
 
    //Default-process the message 
    m_button_down = false; 
	CButton::OnLButtonUp(nFlags, point); 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnMouseMove 
//Class.......: CxShadeButton 
// 
//Author......: Milan Gardian 
//Created.....: MAR-2001 
// 
//Return value: NONE 
//Parameters..: As follows 
//    > [in] nFlags: not used 
//    > [in] point: coordinates of the mouse pointer when this event was spawned 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > Handle change of mouse position: see the comments in the 
//    method for further info. 
//--------------------------------------------------------- 
void CxShadeButton::OnMouseMove(UINT nFlags, CPoint point) 
{ 
    //TRACE("* %08X: Mouse\n", ::GetTickCount()); 
 
	//Pass this message to the ToolTip control 
	RelayEvent(WM_MOUSEMOVE,(WPARAM)nFlags,MAKELPARAM(LOWORD(point.x),LOWORD(point.y))); 
 
    //If we are in capture mode, button has been pressed down 
    //recently and not yet released - therefore check is we are 
    //actually over the button or somewhere else. If the mouse 
    //position changed considerably (e.g. we moved mouse pointer 
    //from the button to some other place outside button area) 
    //force the control to redraw 
    // 
	if ((m_button_down) && (::GetCapture() == m_hWnd))  
	{ 
	    POINT p2 = point; 
        ::ClientToScreen(m_hWnd, &p2); 
        HWND mouse_wnd = ::WindowFromPoint(p2); 
 
        bool pressed = ((GetState() & BST_PUSHED) == BST_PUSHED); 
        bool need_pressed = (mouse_wnd == m_hWnd); 
        if (pressed != need_pressed) { 
            //TRACE("* %08X Redraw\n", GetTickCount()); 
            SetState(need_pressed ? TRUE : FALSE); 
            Invalidate(); 
        } 
    } 
	else  
	{ 
 
	//Otherwise the button is released. That means we should 
    //know when we leave its area - and so if we are not tracking 
    //this mouse leave event yet, start now! 
    // 
        if (!m_tracking) { 
            TRACKMOUSEEVENT t = { 
                sizeof(TRACKMOUSEEVENT), 
                TME_LEAVE, 
                m_hWnd, 
                0 
            }; 
            if (::_TrackMouseEvent(&t)) { 
                //TRACE("* Mouse enter\n"); 
                m_tracking = true; 
                Invalidate(); 
            } 
        } 
    } 
 
//  vj additions to trace mouse movement over shade buttons follows 
	myHWND = GetSafeHwnd( );    // handle of this button 
	if (currentDialog == PerfectDialog) 
		{GetParent()->SendMessage(UWM_PerfectButtonMove, nFlags, MAKELPARAM(point.x, point.y));} 
	if (currentDialog == RelativeDialog) 
		{GetParent()->SendMessage(UWM_RelativeButtonMove, nFlags, MAKELPARAM(point.x, point.y));} 
//  vj additions to trace mouse movement over shade buttons Preceeds 
 
    //Forward this event to superclass 
    CButton::OnMouseMove(nFlags, point); 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnMouseLeave 
//Class.......: CxShadeButton 
// 
//Author......: Milan Gardian 
//Created.....: MAR-2001 
// 
//Return value: NULL 
//Parameters..: NOT USED 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > Handle situation when mouse cursor leaves area of this 
//    window (button). This event might be generated ONLY 
//    if we explicitely call 'TrackMouseEvent'. This is 
//    signalled by setting the m_tracking flag (see the assert 
//    precondition) - in 'OnMouseMove' method 
// 
//  > When a mouse pointer leaves area of this button (i.e. 
//    when this method is invoked), presumably the look of 
//    the button changes (e.g. when hover/non-hover images are set) 
//    and therefore we force the control to redraw. 
//--------------------------------------------------------- 
LRESULT CxShadeButton::OnMouseLeave(WPARAM, LPARAM) 
{ 
WPARAM wParam; 
LPARAM lParam; 
    ASSERT (m_tracking); 
  //TRACE("* Mouse leave\n"); 
    m_tracking = false; 
    Invalidate(); 
//  vj additions to trace mouse movement over shade buttons follows 
	myHWND = GetSafeHwnd( );	// handle of this button 
	if (currentDialog == PerfectDialog) 
		GetParent()->SendMessage(UWM_PerfectButtonLeave, wParam, lParam); 
	if (currentDialog == RelativeDialog) 
		GetParent()->SendMessage(UWM_RelativeButtonLeave, wParam, lParam); 
//  vj additions to trace mouse movement over shade buttons Preceeds 
	return 0; 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnKillFocus 
//Class.......: CxShadeButton 
// 
//Author......: Milan Gardian 
//Created.....: MAR-2001 
// 
//Return value: NONE 
//Parameters..: See superclass documentation 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > If focus is killed during capture, we may no longer 
//    have the exclusive access to user input and therefore 
//    release it. 
// 
//  > Such a situation might happens when the user left-clicks 
//    this button, keeps the button down and simultaneously 
//    presses TAB key. 
//--------------------------------------------------------- 
void CxShadeButton::OnKillFocus(CWnd *new_wnd) 
{ 
    if (::GetCapture() == m_hWnd) { 
        ::ReleaseCapture(); 
        ASSERT (!m_tracking); 
        m_button_down = false; 
    } 
    CButton::OnKillFocus(new_wnd); 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnClicked 
//Class.......: CxShadeButton 
// 
//Author......: Milan Gardian 
//Created.....: MAR-2001 
// 
//Return value: FALSE (do not stop in this handler - forward to parent) 
//Parameters..: NONE 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > Keep consistency of attributes of this instance before 
//    submitting click event to the parent. 
// 
//  > Currently NOT used. To use, umcomment line 
//    "ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)" in message map 
//    at the beginning of this file. 
//--------------------------------------------------------- 
BOOL CxShadeButton::OnClicked()  
{ 
    if (::GetCapture() == m_hWnd) { 
        ::ReleaseCapture(); 
        ASSERT (!m_tracking); 
    } 
    m_button_down = false; 
    //Invalidate(); 
    return FALSE; 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: OnRadioInfo 
//Class.......: CxShadeButton 
// 
//Author......: Rainer Mangold 
//Created.....: JUN-2001 
// 
//Return value: NULL 
//Parameters..: WPARAM and LPARAM (LPARAM not used) 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > Handle notification, that a Button in the same group was pushed 
//--------------------------------------------------------- 
LRESULT CxShadeButton::OnRadioInfo(WPARAM wparam, LPARAM) 
{ 
	if (m_Checked){	//only checked buttons need to be unchecked 
		m_Checked = false; 
		if(m_tooltip.m_hWnd!=NULL) 
			m_tooltip.UpdateTipText((LPCTSTR)m_ToolTipUp,this); 
		Invalidate(); 
	} 
	return 0; 
} 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)  
{ 
	if ((m_Style)&&(nChar==' ')){ //needed stuff for check & radio buttons 
		if (m_Style==BS_CHECKBOX) SetCheck(m_Checked ? 0 : 1); 
		if (m_Style==BS_RADIOBUTTON) SetCheck(1); 
	} 
	CButton::OnKeyDown(nChar, nRepCnt, nFlags); 
} 
///////////////////////////////////////////////////////////////////////////// 
//Method......: SetCheck 
//Class.......: CxShadeButton 
// 
//Author......: Rainer Mangold 
//Created.....: JUN-2001 
// 
//Return value: NONE 
//Parameters..: bool 
//Exceptions..: NONE 
//------------ 
//Description : 
//  > Set the state of this button (pushed or not).  
//    Works for both, Radio and CheckBox - Buttons 
//--------------------------------------------------------- 
LRESULT CxShadeButton::OnBMSetCheck(WPARAM wparam, LPARAM) 
{ 
	m_Checked=wparam!=0; 
	switch (m_Style) 
	{ 
	case BS_RADIOBUTTON: 
		if (m_Checked) { //uncheck the other radio buttons (in the same group) 
			HWND hthis,hwnd2,hpwnd; 
			hpwnd=GetParent()->GetSafeHwnd();	//get button parent handle 
			hwnd2=hthis=GetSafeHwnd();			//get this button handle 
			if (hthis && hpwnd){				//consistency check 
				for( ; ; ){	//scan the buttons within the group 
					hwnd2=::GetNextDlgGroupItem(hpwnd,hwnd2,0); 
					//until we reach again this button 
					if ((hwnd2==hthis)||(hwnd2==NULL)) break; 
					//post the uncheck message 
					::PostMessage(hwnd2, WM_CXSHADE_RADIO, 0, 0); 
				} 
			} 
		} 
		break; 
	case BS_PUSHBUTTON: 
		m_Checked=false; 
		ASSERT(false); // Must be a Check or Radio button to use this function 
	} 
 
	//set the correct tooltip 
	if (m_tooltip.m_hWnd!=NULL){ 
		m_tooltip.Pop();	//to avoid flicker 
		if (m_Checked && !m_ToolTipDw.IsEmpty()) 
			m_tooltip.UpdateTipText((LPCTSTR)m_ToolTipDw,this); 
		else 
			m_tooltip.UpdateTipText((LPCTSTR)m_ToolTipUp,this); 
	} 
	Invalidate(); 
	return 0; 
} 
///////////////////////////////////////////////////////////////////////////// 
LRESULT CxShadeButton::OnBMGetCheck(WPARAM wparam, LPARAM) 
{ return m_Checked; }	//returns the state for check & radio buttons 
///////////////////////////////////////////////////////////////////////////// 
void CxShadeButton::SetButtonStyle(UINT nStyle, BOOL bRedraw) 
{ 
	// see PreSubclassWindow 
	m_IsPushLike=((nStyle & BS_PUSHLIKE)!=0); 
	m_flat=((nStyle & BS_FLAT)!=0); 
 
	if ((nStyle & BS_AUTOCHECKBOX)==BS_AUTOCHECKBOX) 
//		||((m_Style & BS_CHECKBOX)==BS_CHECKBOX)) 
		m_Style=BS_CHECKBOX; 
	else if ((nStyle & BS_AUTORADIOBUTTON)==BS_AUTORADIOBUTTON) 
//			||((m_Style & BS_RADIOBUTTON)==BS_RADIOBUTTON)) 
		m_Style=BS_RADIOBUTTON; 
	else { m_Style=BS_PUSHBUTTON; m_IsPushLike=true; m_Checked=false; } 
 
	//default radio & check-box has no border 
	if (!m_IsPushLike) m_Border = false; 
 
	if (bRedraw) Invalidate(); 
} 
///////////////////////////////////////////////////////////////////////////// 
bool CxShadeButton::SetFont(CString sFontName,long lSize, long lWeight, BYTE bItalic, BYTE bUnderline) 
{ 
	if (m_pLF==NULL) m_pLF=(LOGFONT*)calloc(1,sizeof(LOGFONT)); 
	if (m_pLF){ 
		strncpy(m_pLF->lfFaceName,sFontName,31); 
		m_pLF->lfHeight=lSize; 
		m_pLF->lfWeight=lWeight; 
		m_pLF->lfItalic=bItalic; 
		m_pLF->lfUnderline=bUnderline; 
		m_Font.DeleteObject(); 
		if (m_Font.CreateFontIndirect(m_pLF)) return true; 
	} 
	return false; 
} 
///////////////////////////////////////////////////////////////////////////// 
bool CxShadeButton::SetFont(LOGFONT* pNewStyle) 
{ 
	if (pNewStyle){ 
		if (m_pLF==NULL) m_pLF=(LOGFONT*)calloc(1,sizeof(LOGFONT)); 
		if (m_pLF){ 
			memcpy(m_pLF,pNewStyle,sizeof(LOGFONT)); 
			m_Font.DeleteObject(); 
			if (m_Font.CreateFontIndirect(m_pLF)) return true; 
		} 
	} 
	return false; 
} 
void CxShadeButton::OnButtonEnter() 
{ 
	Invalidate(); 
} 
 
void CxShadeButton::OnButtonLeave() 
{ 
	Invalidate(); 
} 
///////////////////////////////////////////////////////////////////////////// 
LOGFONT* CxShadeButton::GetFont() 
{ return m_pLF; } 
///////////////////////////////////////////////////////////////////////////// 
//EOF