// ResizableSheet.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// Modified 14/09/2000 by David Fleury
//		get rid if the "resizable" stuff, just kept the auto arrange of controls
//		
// Copyright (C) 2000 by Paolo Messina
// (ppescher@yahoo.com)
//
// Free for non-commercial use.
// You may change the code to your needs,
// provided that credits to the original 
// author is given in the modified files.
//  
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ResizableSheet.h"

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

/////////////////////////////////////////////////////////////////////////////
// CResizableSheet

IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)

inline void CResizableSheet::Construct()
{
	m_bInitDone = FALSE;

	m_bEnableSaveRestore = FALSE;
	m_bSavePage = FALSE;
}


CResizableSheet::CResizableSheet()
{
	Construct();
}

CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage)
	 : CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
	Construct();
}

CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage)
	 : CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
	Construct();
}

CResizableSheet::~CResizableSheet()
{
}

BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
	//{{AFX_MSG_MAP(CResizableSheet)
	ON_WM_SIZE()
	ON_WM_DESTROY()
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(ID_WIZBACK, OnPageChanged)
	ON_BN_CLICKED(ID_WIZNEXT, OnPageChanged)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CResizableSheet message handlers

int CResizableSheet::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CPropertySheet::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	/*********************************/
	// MODIFIED 14/09/2000 Fleury David, I don't want the user to be able to resize the sheet
	// // change window style to be resizable
	//	ModifyStyle(0,/* WS_THICKFRAME |*/ WS_CLIPCHILDREN);
	/*********************************/
	return 0;
}

BOOL CResizableSheet::OnInitDialog() 
{
	BOOL bResult = CPropertySheet::OnInitDialog();

	// prevent flickering
	GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);

	m_bInitDone = TRUE;

	return bResult;
}

void CResizableSheet::OnDestroy() 
{
	CPropertySheet::OnDestroy();

	if (m_bEnableSaveRestore)
	{
		SaveWindowRect();
	}

	CPropertySheet::OnDestroy();
}

// maps an index to a button ID and vice-versa
static UINT _propButtons[] =
{
	IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
	ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
};

// horizontal line in wizard mode
#define ID_WIZLINE	ID_WIZFINISH+1

void CResizableSheet::PresetLayout()
{
	CWnd* pWnd;	// points to various children
	CRect wndrc, objrc;
	GetClientRect(&wndrc);

	// tab control or wizard line position
	if (m_psh.dwFlags & PSH_WIZARD)	// wizard mode
	{
		// get wizard line's bottom-right corner
		pWnd = GetDlgItem(ID_WIZLINE);

		// hide tab control
		GetTabControl()->ShowWindow(SW_HIDE);
	}
	else	// tabbed mode
	{
		// get tab control's bottom-right corner
		pWnd = GetTabControl();
	}
	// whatever it is, take the right margin
	pWnd->GetWindowRect(&objrc);
	ScreenToClient(&objrc);

	m_szLayoutTabLine.cx = objrc.right - wndrc.right;
	m_szLayoutTabLine.cy = objrc.bottom - wndrc.bottom;

	// get child dialog's bottom-right corner
	pWnd = GetActivePage();

	pWnd->GetWindowRect(&objrc);
	ScreenToClient(&objrc);

	m_szLayoutPage.cx = objrc.right - wndrc.right;
	m_szLayoutPage.cy = objrc.bottom - wndrc.bottom;

	// store buttons position
	for (int i = 0; i < 7; i++)
	{
		pWnd = GetDlgItem(_propButtons[i]);
		
		if (pWnd == NULL)
		{
			// invalid position, button does not exist
			// (just to initialize, any button you may activate
			// in the future is present, but hidden)
			m_szLayoutButton[i].cx = 0;
			m_szLayoutButton[i].cy = 0;
			continue;
		}
		
		pWnd->GetWindowRect(&objrc);
		ScreenToClient(&objrc);

		m_szLayoutButton[i].cx = objrc.left - wndrc.right;
		m_szLayoutButton[i].cy = objrc.top - wndrc.bottom;
	}
}

void CResizableSheet::ArrangeLayout()
{
	// init some vars
	CWnd* pWnd;
	CRect wndrc, objrc;
	GetClientRect(&wndrc);

	// usually no more than
	// 4 buttons +
	// 1 tab control or wizard line +
	// 1 active page
	HDWP hdwp = BeginDeferWindowPos(6);

	if (m_psh.dwFlags & PSH_WIZARD)	// wizard mode
	{
		// get wizard line's bottom-right corner
		pWnd = GetDlgItem(ID_WIZLINE);

		pWnd->GetWindowRect(&objrc);
		ScreenToClient(&objrc);

		int oldHeight = objrc.Height();
		objrc.right = m_szLayoutTabLine.cx + wndrc.right;
		objrc.bottom = m_szLayoutTabLine.cy + wndrc.bottom;
		objrc.top = objrc.bottom - oldHeight;

		// add the control
		DeferWindowPos(hdwp, *pWnd, NULL, objrc.left, objrc.top,
			objrc.Width(), objrc.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
	}
	else	// tabbed mode
	{
		// get tab control's bottom-right corner
		pWnd = GetTabControl();

		pWnd->GetWindowRect(&objrc);
		ScreenToClient(&objrc);

		objrc.right = m_szLayoutTabLine.cx + wndrc.right;
		objrc.bottom = m_szLayoutTabLine.cy + wndrc.bottom;

		// add the control, only resize
		DeferWindowPos(hdwp, *pWnd, NULL, 0, 0, objrc.Width(),
			objrc.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
	}

	// get child dialog's bottom-right corner
	pWnd = GetActivePage();

	pWnd->GetWindowRect(&objrc);
	ScreenToClient(&objrc);

	objrc.right = m_szLayoutPage.cx + wndrc.right;
	objrc.bottom = m_szLayoutPage.cy + wndrc.bottom;

	// add the control, only resize
	DeferWindowPos(hdwp, *pWnd, NULL, 0, 0, objrc.Width(),
		objrc.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);

	// arrange buttons position
	for (int i = 0; i < 7; i++)
	{
		pWnd = GetDlgItem(_propButtons[i]);
		
		if (pWnd == NULL)
			continue;	// ignores deleted buttons

		// this should never happen, because all the buttons you
		// may activate already exist at time PresetLayout is called
		ASSERT(m_szLayoutButton[i].cx != 0 || m_szLayoutButton[i].cy != 0);
		
		pWnd->GetWindowRect(&objrc);
		ScreenToClient(&objrc);

		objrc.left = m_szLayoutButton[i].cx + wndrc.right;
		objrc.top = m_szLayoutButton[i].cy + wndrc.bottom;

		// add the control, only move
		DeferWindowPos(hdwp, *pWnd, NULL, objrc.left, objrc.top,
			0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
	}

	// go re-arrange child windows
	EndDeferWindowPos(hdwp);
}

void CResizableSheet::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	
	if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
		return;		// arrangement not needed

	if (m_bInitDone)
		ArrangeLayout();
}

// only gets called in wizard mode
// (when back or next button pressed)
void CResizableSheet::OnPageChanged()
{
	// call default handler to allow page change
	Default();

	// update new wizard page
	ArrangeLayout();
}


// protected members


// NOTE: this must be called after all the other settings
//       to have the dialog and its controls displayed properly
void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, LPCTSTR pszEntry, BOOL bWithPage)
{
	m_sSection = pszSection;
	m_sEntry = pszEntry;
	m_bSavePage = bWithPage;

	m_bEnableSaveRestore = TRUE;

	LoadWindowRect();
}

// private memebers

// used to save/restore window's size and position
// either in the registry or a private .INI file
// depending on your application settings

#define PROFILE_FMT 	_T("%d,%d,%d,%d,%d,%d [%d]")

void CResizableSheet::SaveWindowRect()
{
	CString data;
	WINDOWPLACEMENT wp;

	ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
	wp.length = sizeof(WINDOWPLACEMENT);
	GetWindowPlacement(&wp);
	
	RECT& rc = wp.rcNormalPosition;	// alias

	// also saves active page index, zero (the first) if problems
	// cannot use GetActivePage, because it always fails
	CTabCtrl *pTab = GetTabControl();
	int page = 0;

	if (pTab != NULL) 
		page = pTab->GetCurSel();
	if (page < 0)
		page = 0;

	// always save page
	data.Format(PROFILE_FMT, rc.left, rc.top,
		rc.right, rc.bottom, wp.showCmd, wp.flags, page);

	AfxGetApp()->WriteProfileString(m_sSection, m_sEntry, data);
}

void CResizableSheet::LoadWindowRect()
{
	CString data;
	WINDOWPLACEMENT wp;
	int page;

	data = AfxGetApp()->GetProfileString(m_sSection, m_sEntry);
	
	if (data.IsEmpty())	// never saved before
		return;
	
	ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
	wp.length = sizeof(WINDOWPLACEMENT);

	RECT& rc = wp.rcNormalPosition;	// alias

	if (_stscanf_s(data, PROFILE_FMT, &rc.left, &rc.top,
		&rc.right, &rc.bottom, &wp.showCmd, &wp.flags, &page) == 7)
	{
		SetWindowPlacement(&wp);
		if (m_bSavePage)
		{
			SetActivePage(page);
			ArrangeLayout();	// needs refresh
		}
	}
}

int CResizableSheet::GetMinWidth()
{/*
	int min = 0;

	// search for leftmost button
	for (int i = 0; i < 7; i++)
	{
		// left position is relative to the right border
		// of the parent window (negative value)
		if (m_szLayoutButton[i].cx < min)
			min = m_szLayoutButton[i].cx;
	}

	// sizing border width
	int border = GetSystemMetrics(SM_CXSIZEFRAME);
	
	// get tab control or wizard line left position
	CWnd* pWnd;
	CRect objrc;

	if (m_psh.dwFlags & PSH_WIZARD)
		pWnd = GetDlgItem(ID_WIZLINE);
	else
		pWnd = GetTabControl();

	pWnd->GetWindowRect(&objrc);
	ScreenToClient(&objrc);

	// add the left margin and window's border
	return -min + objrc.left + border*2;
*/
	return 1;
}