// cstm1dlg.cpp : implementation file
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "logowiz.h"
#include "cstm1dlg.h"
#include "logowaw.h"

#ifdef _PSEUDO_DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// these are expected to be in the same order as the radio buttons corresponding to these choices
// they are also assumed to start at zero
#define	RAD_UPLEFT	0		// logo goes in upper left corner
#define	RAD_LOLEFT	1		// logo goes in lower left corner
#define	RAD_LORIGHT	2		// logo goes in lower right corner
#define	RAD_NOLOGO	3		// no logo
// other buttons
#define	BT_PRESS_ME	4		// press me button (keep below radio button set)
#define	BT_DLGPIC	5		// dialog box picture (keep at bottom of list: not part of radio button set)

// Size of dialog box bitmap
#define BMP_LEFT 16
#define BMP_TOP 16
#define BMP_WIDTH 195
#define BMP_HEIGHT 147

// Other values used for drawing around the dialog box bitmap
#define RIGHT_YELLOW (163 + BMP_LEFT)
#define BOTTOM_YELLOW_DLGU 197
#define RIGHT_GRAY_DLGU 125

/////////////////////////////////////////////////////////////////////////////
// CCustom1Dlg dialog


CCustom1Dlg::CCustom1Dlg()
	: CAppWizStepDlg(CCustom1Dlg::IDD)
{
	//{{AFX_DATA_INIT(CCustom1Dlg)
	m_nLogoSpot = -1;
	m_nPressMe = FALSE;
	//}}AFX_DATA_INIT
}


void CCustom1Dlg::DoDataExchange(CDataExchange* pDX)
{
	CAppWizStepDlg::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCustom1Dlg)
	DDX_Radio(pDX, IDC_LOGO_UL, m_nLogoSpot);
	DDX_Check(pDX, IDC_PRESS_ME, m_nPressMe);
	//}}AFX_DATA_MAP
}

// set appropriate entries in the dictionary
// Parameters:
//	bWriteSymbol - Boolean value determining whether we need to write (TRUE) or delete (FALSE)
//					a dictionary value
//	     strName - the dictionary value we're working with
void CCustom1Dlg::SetSymbol(BOOL bWriteSymbol, LPCTSTR strName)
{
	if (bWriteSymbol)
		logowizaw.m_Dictionary.SetAt(strName, CString("1"));
	else
		logowizaw.m_Dictionary.RemoveKey(strName);
}

// This is called whenever the user presses Next, Back, or Finish with this step
//  present.  Do all validation & data exchange from the dialog in this function.
BOOL CCustom1Dlg::OnDismiss()
{
	if (!UpdateData(TRUE))
		return FALSE;

	// set the template variables
	SetSymbol(m_nLogoSpot == RAD_UPLEFT, _T("LOGO_UPLEFT"));
	SetSymbol(m_nLogoSpot == RAD_LOLEFT, _T("LOGO_LOLEFT"));
	SetSymbol(m_nLogoSpot == RAD_LORIGHT, _T("LOGO_LORIGHT"));
	// don't need to set a symbol for LOGO_NONE
	SetSymbol(RAD_UPLEFT || RAD_LOLEFT || RAD_LORIGHT, _T("LOGO_YES"));
	SetSymbol(m_nPressMe == TRUE, _T("PRESS_ME_DIALOG"));

	return TRUE;	// return FALSE if the dialog shouldn't be dismissed
}


BEGIN_MESSAGE_MAP(CCustom1Dlg, CAppWizStepDlg)
	ON_CONTROL_RANGE(BN_CLICKED, IDC_LOGO_UL, IDC_LOGO_NONE, OnLogoClicked)
	//{{AFX_MSG_MAP(CCustom1Dlg)
	ON_WM_PAINT()
	ON_BN_CLICKED(IDC_PRESS_ME, OnPressMe)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CCustom1Dlg message handlers

// draw a logo on the AppWiz page in the right place.  will erase the old logo if one exists
//	Parameters:
//		nOldID - logo location to erase (if it exists)
//		nNewID - logo location to draw in now
void CCustom1Dlg::DrawLogo(int nOldID, int nNewID)
{
	CDC* pdc = GetDC();

	if (nNewID == nOldID && nOldID >= RAD_UPLEFT)		// redraw without erase if same spot
	{
		DrawBitmap(pdc, IDB_LOGO_SMALL, nNewID);
		return;
	}

	if (nOldID >= RAD_UPLEFT)	// there is an old ID present, so erase it
		EraseBitmap(pdc, nOldID);

	// draw the logo in the new spot
	DrawBitmap(pdc, IDB_LOGO_SMALL, nNewID);
}

// Determine the rectangle we need to draw the desired bitmap in
//	there are three kinds of bitmaps expected here:
//   1. the 'big' bitmap with the picture of the dialog box on it
//   2. the 'baby' bitmap that represents the logo that shifts around on the 'big' bitmap
//   3. the 'press me' bitmap that goes in the middle of the dialog box
void CCustom1Dlg::GetBitmapRect(int nLocID, LPRECT rect)
{
	if (nLocID == BT_DLGPIC)	// major bitmap
	{
		rect->left = BMP_LEFT;
		rect->top = BMP_TOP;
		rect->right = BMP_LEFT + BMP_WIDTH;
		rect->bottom = BMP_TOP + BMP_HEIGHT;
		return;
	}
	else if (nLocID == BT_PRESS_ME)		// looking for location of 'press me' bitmap
	{
		rect->left = BMP_LEFT - 10 + (BMP_WIDTH - m_nPressWidth)/2;
		rect->top = BMP_TOP + (BMP_HEIGHT - m_nPressHeight)/2;
		rect->right = rect->left + m_nPressWidth;
		rect->bottom = rect->top + m_nPressHeight;
		return;
	 
	}
	else if (nLocID == RAD_NOLOGO)		// no baby bitmap needed
	{
		rect->top = rect->bottom = rect->left = rect->right = 0;
		return;
	}

	// figure out where to put the baby bitmap (small logo)
	if (nLocID == RAD_LOLEFT || nLocID == RAD_LORIGHT)
		rect->top = BMP_TOP + BMP_HEIGHT - 30;
	else
		rect->top = BMP_TOP + 25;
	if (nLocID == RAD_LOLEFT || nLocID == RAD_UPLEFT)
		rect->left = BMP_LEFT + 15;
	else
		rect->left = BMP_LEFT + BMP_WIDTH - 30;

	rect->right = rect->left + m_nLogoWidth;
	rect->bottom = rect->top + m_nLogoHeight;
}

// erase a bitmap.  do NOT call this from OnPaint.  doing so causes an infinite recursion
//  and crashes MSVC very nicely (not).  (MSVC will crash in this case only because the 
//  program you are actually running is the IDE itself.  If you do this kind of stuff in
//  a different .exe, you will crash that .exe instead.)
void CCustom1Dlg::EraseBitmap(CDC* pdc, int nLocID)
{
	RECT rect;

	GetBitmapRect(nLocID, &rect);
	RedrawWindow(&rect, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
}

// draw a bitmap
//	Parameters:
//		      pdc - device context to draw in
//		nBitmapID - which bitmap to draw
//		   nLocID - where to draw it
void CCustom1Dlg::DrawBitmap(CDC* pdc, int nBitmapID, int nLocID)
{
	CDC dcMem;
	RECT rect;

	if (nLocID == RAD_NOLOGO)	// nothing to do
		return;

	if (!dcMem.CreateCompatibleDC(pdc))
		return;

	CBitmap picture;
	picture.LoadBitmap(nBitmapID);
	BITMAP bitmap;
	picture.GetObject(sizeof (BITMAP), &bitmap);

	GetBitmapRect(nLocID, &rect);

	CBitmap* pOldBitmap = dcMem.SelectObject(&picture);
	pdc->BitBlt(rect.left, rect.top, bitmap.bmWidth, bitmap.bmHeight, &dcMem, 0, 0, SRCCOPY);
	dcMem.SelectObject(pOldBitmap);
}

// user clicked one of the logo location radio buttons
void CCustom1Dlg::OnLogoClicked(UINT /* nCmdID */) 
{
	int oldLogoSpot = m_nLogoSpot;

	UpdateData();
	DrawLogo(oldLogoSpot, m_nLogoSpot);		
}

void CCustom1Dlg::OnPressMe() 
{
	UpdateData();

	CPaintDC dc(this); // device context for painting

	// this erase forces a redraw of the 'press me' button area.
	//  if we don't do a RedrawWindow (such as is done in EraseBitmap()), 
	//  the bitmap won't paint regardless of the value of m_nPressMe.  
	//  by restricting the area that gets redrawn (erased first in this 
	//  case), we avoid flicker.
	EraseBitmap(&dc, BT_PRESS_ME);
	if (m_nPressMe)
		DrawBitmap(&dc, IDB_PRESS_ME, BT_PRESS_ME);
}

BOOL CCustom1Dlg::OnInitDialog() 
{
	CAppWizStepDlg::OnInitDialog();

	// pick up sizing information for the logo
	SetBitmapSize(IDB_LOGO_SMALL, &m_nLogoWidth, &m_nLogoHeight);

	// pick up sizing information for the 'press me' button
	SetBitmapSize(IDB_PRESS_ME, &m_nPressWidth, &m_nPressHeight);

	m_nLogoSpot = IDC_LOGO_LL - IDC_LOGO_UL;
	m_nPressMe = TRUE;
	UpdateData(FALSE);
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

// initialize the bitmap size for the specified bitmap ID
void CCustom1Dlg::SetBitmapSize(int nID, int* pwidth, int* pheight)
{
	CBitmap picture;
	picture.LoadBitmap(nID);
	BITMAP bitmap;
	picture.GetObject(sizeof (BITMAP), &bitmap);
	*pwidth = bitmap.bmWidth;
	*pheight = bitmap.bmHeight;
}	

// returns which dialog box bitmap we need (with or without help button on it as appropriate)
int CCustom1Dlg::GetDlgBitmapID()
{
	if (logowizaw.m_Dictionary.Lookup(_T("HELP"), CString("1"))) 
		return IDB_DLGPIC_WHELP;
	else
		return IDB_DLGPIC_NOHLP;
}

void CCustom1Dlg::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	CBitmap pattern;
	pattern.LoadBitmap(IDB_YELLOW_PATTERN);
	CBrush brush(&pattern);
	RECT rectBmp;
	GetBitmapRect(BT_DLGPIC, &rectBmp);
	CPen penBogus(PS_SOLID, 0, COLORREF(0));
	CPen* pOldPen = dc.SelectObject(&penBogus);  // Remember current pen.

	DrawBitmap(&dc, GetDlgBitmapID(), BT_DLGPIC);	// major bitmap (dialog box picture)
	DrawBitmap(&dc, IDB_LOGO_SMALL, m_nLogoSpot);	// baby bitmap (logo to go on above)
	if (m_nPressMe)
		DrawBitmap(&dc, IDB_PRESS_ME, BT_PRESS_ME);	// 'press me' button

	// Since the other two bitmaps are contained entirely on the major bitmap, we only have
	//  to worry about the major one when we draw the background.  If all of the bitmaps
	//  were not contained in the same rectangle, we would have to worry about all of them
	//  when drawing the background.

	// Draw yellow ABOVE bitmap(s)
	RECT rect = {0, 0, 0, 0};
	rect.bottom = rectBmp.top;
	rect.right = RIGHT_YELLOW + 1;
	dc.DPtoLP(&rect);
	dc.FillRect(&rect, &brush);

	// draw yellow to LEFT of bitmap(s)
	rect.left = 0;
	rect.top = rectBmp.top;
	rect.right = rectBmp.left;
	rect.bottom = rectBmp.bottom;
	dc.DPtoLP(&rect);
	dc.FillRect(&rect, &brush);

	// Draw yellow BELOW bitmap(s)
	rect.left = 0;
	rect.top = 0;
	rect.right = 1;
	rect.bottom = BOTTOM_YELLOW_DLGU;
	MapDialogRect(&rect);
	rect.right = RIGHT_YELLOW + 1;
	rect.top = rectBmp.bottom;
	dc.DPtoLP(&rect);
	dc.FillRect(&rect, &brush);

	// Draw right border lines
	CPen penGray(PS_SOLID, 0, 0x00808080);
	dc.SelectObject(&penGray);
	dc.MoveTo(rect.right, 0);
	POINT point;
	point.x = rect.right;
	point.y = rectBmp.top;
	dc.DPtoLP(&point);
	dc.LineTo(point.x, point.y);
	point.x = rect.right;
	point.y = rectBmp.bottom;
	dc.DPtoLP(&point);
	dc.MoveTo(point.x, point.y);
	dc.LineTo(point.x, rect.bottom);

	CPen penWhite(PS_SOLID, 0, 0x00ffffff);
	dc.SelectObject(&penWhite);
	dc.MoveTo(rect.right+1, 0);
	point.x = rect.right+1;
	point.y = rectBmp.top;
	dc.DPtoLP(&point);
	dc.LineTo(point.x, point.y);
	point.x = rect.right+1;
	point.y = rectBmp.bottom;
	dc.DPtoLP(&point);
	dc.MoveTo(point.x, point.y);
	dc.LineTo(point.x, rect.bottom);

	// Restore original pen
	dc.SelectObject(pOldPen);
}
