/* -----------------------------------------------------------------------------

 Copyright (C) Siemens AG 1994-2001,  ALL RIGHTS RESERVED

 This software is protected by the inclusion of the above copyright
 notice. This software may not be provided or otherwise made available
 to, or used by, any other person. No title to or ownership of the
 software is  hereby  transferred.
 The information contained in this document is considered the
 CONFIDENTIAL and PROPRIETARY information of Siemens AG and may
 not be disclosed or discussed with anyone who is not employed by
 Siemens AG, unless the individual / company
 (i) has an express need to know such information, and
 (ii) disclosure of information is subject to the terms of a duly
 executed Confidentiality and Non-Disclosure Agreement between
 Siemens AG and the individual / company.



.AUTHOR         Zhang Jing (SLC)

.FILENAME       sp_bmpdlg.cpp

.VERSION        01.00.00

.DATE           2004-02-17

.SHORT_DESCR    Basic Bitmap Dialog for Shaped UI

.SW_COMPONENT   MMI PC-SIMULATION

.SW_TYPE        

.EXIT_CODES

.CHANGE_CONTROL 
Version  Date        Changed by
         Reason of change
--------------------------------------------------------------------------------
01.00.00 2004-03-17  Zhang Jing (SLC)
         Initial version
01.00.01 2004-05-28  Fang Yunchao  (PEK) 
		Add UNICODE support

*/


#include "smsafxh.h"
#include "sp_bmpdlgh.h"
#include "winrc.h"
#include "sms_res.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CBitmapDialog dialog

/**----------------------------------------------------------------
 * CBitmapDialog :: CBitmapDialog - constructor for CBitmapDialog
 *
 * Parameters:
 *  lpszTemplateName - the name of the dialog template resource
 *  nIDTemplate - the ID of the dialog template resource
 *  pParentWnd - the parent window
 *
 * You can leave any or all of the below NULL or 0 to not use it
 *  lpszResourceName - the name of the bitmap resource to load
 *  nIDResource - the ID of the bitmap resource to load
 *  lpszFilename - the filename of the bitmap file to load
 *  pBitmap - the bitmap to use (user is responsible for handling the bitmap)
 */

// for modless dialog
BOOL CBitmapDialog::Create()
{
	return CDialog::Create(m_nID, m_pParent);
}

CBitmapDialog::CBitmapDialog(CWnd* pParent)
	: CDialog(CBitmapDialog::IDD, pParent)
{
	//{{AFX_DATA_INIT(CAdderDialog)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	ASSERT(pParent != NULL);
	//Constructor (lpszResourceName, nIDResource, lpszFilename, pBitmap);

	m_pParent = pParent;
	m_nID = CBitmapDialog::IDD;

	m_bTransparent = FALSE;			// No transparency
	m_bStaticTransparent = TRUE;	// Static controls are transparent
	m_bBitmapCreated = FALSE;		// Don't automatically release the bitmap
	m_bBitmapExists = FALSE;		// IS there a bitmap?
	m_bClickAnywhereMove = FALSE;	// Clicking anywhere moves
	
	// Create a hollow brush used in making static controls transparent
	m_brushHollow = (HBRUSH) GetStockObject (HOLLOW_BRUSH);

}
// end of modeless Dialog


// The common constructor for CBitmapDialog
void CBitmapDialog :: Constructor (LPCTSTR lpszResourceName, UINT nIDResource,
								   LPCTSTR lpszFilename, CBitmap *pBitmap)
{
	m_bTransparent = FALSE;			// No transparency
	m_bStaticTransparent = TRUE;	// Static controls are transparent
	m_bBitmapCreated = FALSE;		// Don't automatically release the bitmap
	m_bBitmapExists = FALSE;		// IS there a bitmap?
	m_bClickAnywhereMove = FALSE;	// Clicking anywhere moves
	
	// Create a hollow brush used in making static controls transparent
	m_brushHollow = (HBRUSH) GetStockObject (HOLLOW_BRUSH);

	// Load a bitmap from a resource name
	if (lpszResourceName != NULL)
	{
		LoadBitmap (lpszResourceName, NULL);
	}
	// Load a bitmap from a resource ID
	else if (nIDResource != 0)
	{
		LoadBitmap (nIDResource);
	}
	// Use the passed bitmap
	else if (pBitmap != 0)
	{
		// NOTE: The user is responsible for handling the bitmap
		SetBitmap (pBitmap);
	}
	// else: No bitmap has been created yet
}

CBitmapDialog::CBitmapDialog (LPCTSTR lpszTemplateName, CWnd* pParentWnd,
							  LPCTSTR lpszResourceName, UINT nIDResource,
							  LPCTSTR lpszFilename, CBitmap *pBitmap)
	: CDialog (lpszTemplateName, pParentWnd)
{
	Constructor (lpszResourceName, nIDResource, lpszFilename, pBitmap);
}

CBitmapDialog::CBitmapDialog (UINT nIDTemplate, CWnd* pParentWnd,
							  LPCTSTR lpszResourceName, UINT nIDResource,
							  LPCTSTR lpszFilename, CBitmap *pBitmap)
	: CDialog (nIDTemplate, pParentWnd)
{
	m_pParent = pParentWnd;
	m_nID = CBitmapDialog::IDD;

	Constructor (lpszResourceName, nIDResource, lpszFilename, pBitmap);
}

CBitmapDialog::CBitmapDialog (LPCTSTR lpszResourceName, UINT nIDResource,
							  LPCTSTR lpszFilename, CBitmap *pBitmap)
	: CDialog ()
{
	Constructor (lpszResourceName, nIDResource, lpszFilename, pBitmap);
}

/**----------------------------------------------------------------
 * CBitmapDialog :: LoadBitmap - load a bitmap from a resource or file
 *
 * Parameters:
 *  lpszResourceName - the name of the bitmap resource to load.
 *    Set this to NULL if you use lpszFilename.
 *  lpszFilename - the filename of the bitmap file to load.
 *    Set this to NULL if you use lpszResourceName.
 *  nIDResource - the ID of the bitmap resource to load
 */
BOOL CBitmapDialog :: LoadBitmap (LPCTSTR lpszResourceName, LPCTSTR lpszFilename)
{
	// Release the bitmap if it was created
	ReleaseBitmap ();

	if (lpszResourceName != NULL)
	{
		// Load the bitmap from a resource
		m_bmBitmap = new CBitmap;
		if (!m_bmBitmap->LoadBitmap (lpszResourceName))
		{
			m_bmBitmap->DeleteObject();
			m_bBitmapCreated = FALSE;
			m_bBitmapExists = FALSE;
			return FALSE;
		}
		// Automatically delete the object
		m_bBitmapCreated = TRUE;
		m_bBitmapExists = TRUE;

		// Make the window transparent if needed
		MakeWindowRgn ();
	}
	else
	{
		// Load the bitmap from a file
		HBITMAP hbm = (HBITMAP) LoadImage (AfxGetInstanceHandle(), lpszFilename, IMAGE_BITMAP, 0, 0,
			LR_LOADFROMFILE|LR_CREATEDIBSECTION);
		if (hbm == NULL) return FALSE;

		// Get the CBitmap object
		CopyBitmapFrom (CBitmap::FromHandle(hbm));
		//m_bmBitmap = CBitmap::FromHandle (hbm);
	}

	return TRUE;
}

BOOL CBitmapDialog :: LoadBitmap (UINT nIDResource)
{
	// Release the bitmap if it was created
	ReleaseBitmap ();
	
	// Load the bitmap
	m_bmBitmap = new CBitmap;
	if (!m_bmBitmap->LoadBitmap (nIDResource))
		return FALSE;

	// Automatically delete the object
	m_bBitmapCreated = TRUE;
	m_bBitmapExists = TRUE;

	// Make the window transparent if needed
	MakeWindowRgn ();

	return TRUE;
}

/**----------------------------------------------------------------
 * CBitmapDialog :: CopyBitmapFrom - sets the bitmap to a copy
 *  of a CBitmap.
 *
 * Parameters:
 *  pBitmap - a pointer to the bitmap to make a copy of and use.
 */
BOOL CBitmapDialog :: CopyBitmapFrom (CBitmap *pBitmap)
{
	// Release the bitmap if it was created
	ReleaseBitmap ();

	// Get the bitmap information
	BITMAP bmSrc;
	pBitmap->GetBitmap (&bmSrc);

	// Get a DC to the source bitmap
	CDC dcSrc;
	dcSrc.CreateCompatibleDC (NULL);
	CBitmap *bmSrcOld = dcSrc.SelectObject (pBitmap);

	// Create a new bitmap
	m_bmBitmap = new CBitmap;
	if (!m_bmBitmap->CreateCompatibleBitmap (&dcSrc, bmSrc.bmWidth, bmSrc.bmHeight))
		return FALSE;

	// Get a DC to the destination bitmap
	CDC dcDst;
	dcDst.CreateCompatibleDC (NULL);
	CBitmap *bmDstOld = dcDst.SelectObject (m_bmBitmap);

	// Copy the bitmap
	dcDst.BitBlt (0, 0, bmSrc.bmWidth, bmSrc.bmHeight, &dcSrc, 0, 0, SRCCOPY);

	// Release
	dcSrc.SelectObject (bmSrcOld);
	dcDst.SelectObject (bmDstOld);
	dcSrc.DeleteDC ();
	dcDst.DeleteDC ();

	// Automatically delete the object
	m_bBitmapCreated = TRUE;
	m_bBitmapExists = TRUE;

	// Make the window transparent if needed
	MakeWindowRgn ();

	return TRUE;
}

/**----------------------------------------------------------------
 * CBitmapDialog :: SetBitmap - sets the bitmap
 *
 * Parameters:
 *  pBitmap - a pointer to the bitmap to use.
 *
 * NOTE: This function does not copy the bitmap.  You are responsible
 *  for handling the bitmap.  Use CopyBitmapFrom() to copy a bitmap.
 */
void CBitmapDialog :: SetBitmap (CBitmap *pBitmap)
{
	// Release the bitmap if it was created
	ReleaseBitmap ();

	// Set the bitmap
	m_bmBitmap = pBitmap;

	// The bitmap exists, but was not created
	m_bBitmapExists = TRUE;

	// Make the window transparent if needed
	MakeWindowRgn ();
}

/**----------------------------------------------------------------
 * CBitmapDialog :: ReleaseBitmap - releases a bitmap if it was
 *  created using LoadBitmap or CopyBitmapFrom.
 */
void CBitmapDialog :: ReleaseBitmap ()
{
	// Make sure that the bitmap was created using LoadBitmap or CopyBitmapFrom
	if (m_bBitmapCreated)
	{
		// Delete the bitmap
		m_bmBitmap->DeleteObject ();
		delete m_bmBitmap;

		// The bitmap has not been created yet
		m_bBitmapCreated = FALSE;
	}

	m_bBitmapExists = FALSE;
}

/**----------------------------------------------------------------
 * CBitmapDialog :: SetTransparent - sets the dialog's transparent
 *  state.
 */

void CBitmapDialog :: SetTransparent (BOOL bTransparent)
{
	m_bTransparent = bTransparent;
	MakeWindowRgn ();
}

void CBitmapDialog :: SetTransColor (COLORREF col)
{
	m_colTrans = col;
	MakeWindowRgn ();
}

/**----------------------------------------------------------------
 * CBitmapDialog :: MakeWindowRgn - makes a window region from
 *  the bitmap and uses it if on transparent mode.
 */
void CBitmapDialog :: MakeWindowRgn ()
{
	if (!m_bTransparent)
	{
		// Set the window region to the full window
		CRect rc;
		//GetWindowRect (rc);
		GetClientRect (rc);
		CRgn rgn;
		
		rgn.CreateRectRgn (rc.left, rc.top, rc.Width(), rc.Height());
		SetWindowRgn (rgn, TRUE);
	}
	else
	{
		// Set the region to the window rect minus the client rect
		CRect rcWnd;
		GetWindowRect (rcWnd);

		CRgn rgn;
		//rgn.CreateRectRgn (rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom);

		CRect rcClient;
		GetClientRect (rcClient);
		ClientToScreen (rcClient);

		CRgn rgnClient;
		rgn.CreateRectRgn (rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
		rgnClient.CreateRectRgn (rcClient.left, rcClient.top, rcClient.right,
			rcClient.bottom);

		// Subtract rgnClient from rgn
		rgn.CombineRgn (&rgn, &rgnClient, RGN_XOR);

		// Get a DC for the bitmap
		CDC dcImage;
		dcImage.CreateCompatibleDC (NULL);
		CBitmap *pOldBitmap = dcImage.SelectObject (m_bmBitmap);

		// Get the bitmap for width and height information
		BITMAP bm;
		m_bmBitmap->GetBitmap (&bm);

		// Get window width and height
		CRect rc;
		GetClientRect (rc);

		// Use the minimum width and height
		int width = min (bm.bmWidth, rc.Width());
		int height = min (bm.bmHeight, rc.Height());

		// Use RLE (run-length) style because it goes faster.
		// Row start is where the first opaque pixel is found.  Once
		// a transparent pixel is found, a line region is created.
		// Then row_start becomes the next opaque pixel.
		int row_start;

		// Go through all rows
		for (int y=0; y<height; y++)
		{
			// Start looking at the beginning
			row_start = 0;

			// Go through all columns
			for (int x=0; x<width; x++)
			{
				// If this pixel is transparent
				if (dcImage.GetPixel(x, y) == m_colTrans)
				{
					// If we haven't found an opaque pixel yet, keep searching
					if (row_start == x) row_start ++;
					else
					{
						// We have found the start (row_start) and end (x) of
						// an opaque line.  Add it to the region.
						CRgn rgnAdd;
						rgnAdd.CreateRectRgn (3+row_start,
							y, 3+x, y+1);
						//rgnAdd.CreateRectRgn (0+row_start,
						//	0+y, 0+x, 0+y+1);
						rgn.CombineRgn (&rgn, &rgnAdd, RGN_OR);
						row_start = x+1;
					}
				}
			}

			// If the last pixel is still opaque, make a region.
			if (row_start != x)
			{
				CRgn rgnAdd;
				rgnAdd.CreateRectRgn (rcClient.left+row_start, rcClient.top+y,
					rcClient.left+x, rcClient.top+y+1);
				rgn.CombineRgn (&rgn, &rgnAdd, RGN_OR);
			}
		}
		
		SetWindowRgn (rgn, TRUE);
	}
}

BEGIN_MESSAGE_MAP(CBitmapDialog, CDialog)
	//{{AFX_MSG_MAP(CBitmapDialog)
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDOWN()
	ON_WM_CTLCOLOR()
	//}}AFX_MSG_MAP
	ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBitmapDialog message handlers

/**----------------------------------------------------------------
 * CBitmapDialog :: OnEraseBkgnd - normally erases the background.
 *  We override this function to replace it with window drawing
 *  code.
 */
BOOL CBitmapDialog :: OnEraseBkgnd (CDC *pDC)
{
	// If no bitmap is loaded, behave like a normal dialog box
	if (!m_bBitmapExists)
		return CDialog :: OnEraseBkgnd (pDC);

	// Get the client rectangle of the window
	CRect rc;
	GetClientRect (rc);

	// Get a DC for the bitmap
	CDC dcImage;
	dcImage.CreateCompatibleDC (pDC);
	CBitmap *pOldBitmap = dcImage.SelectObject (m_bmBitmap);

	// Get bitmap width and height
	BITMAP bm;
	m_bmBitmap->GetBitmap (&bm);

	// Use the minimum width and height
	int width = min (bm.bmWidth, rc.Width());
	int height = min (bm.bmHeight, rc.Height());

	// Draw the bitmap as the window background
	pDC->BitBlt (0, 0, rc.Width(), rc.Height(), &dcImage, 0, 0, SRCCOPY);

	// Release
	dcImage.SelectObject (pOldBitmap);
	dcImage.DeleteDC ();

	// Return value: Nonzero if it erases the background.
	return TRUE;
}

/**----------------------------------------------------------------
 * CBitmapDialog :: OnLButtonDown - left mouse button is clicked
 *  on the window
 */
void CBitmapDialog::OnLButtonDown(UINT nFlags, CPoint point) 
{

#if CLICKANYWHERE // not defined becasue don't want it move
	// Fool windows into thinking that we clicked on the caption
	if (m_bClickAnywhereMove)
		PostMessage (WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x,point.y));
#endif
	CDialog::OnLButtonDown(nFlags, point);
}

/*----------------------------------------------------------------
 * CBitmapDialog :: OnCtlColor - set the colors for controls
 */
HBRUSH CBitmapDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
	HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
	
	// TODO: Change any attributes of the DC here

	// Make static controls transparent
	if (m_bStaticTransparent && nCtlColor == CTLCOLOR_STATIC)
	{
		// Make sure that it's not a slider control
		TCHAR lpszClassName[256];
		GetClassName (pWnd->m_hWnd, lpszClassName, 255);
		if (_tcscmp (lpszClassName, TRACKBAR_CLASS) == 0)
			return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

		pDC->SetBkMode (TRANSPARENT);
		return m_brushHollow;
	}
	
	// TODO: Return a different brush if the default is not desired
	return hbr;
}

void CBitmapDialog::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	CDialog::OnLButtonUp(nFlags, point);
}
