www.pudn.com > TreePropSheetEx.rar > TreePropSheetResizableLibHook.cpp


// TreePropSheetResizableLibHook.cpp: implementation of the CTreePropSheetResizableLibHook class. 
// 
///////////////////////////////////////////////////////////////////////////// 
// 
// Copyright (C) 2004 by Yves Tkaczyk 
// (http://www.tkaczyk.net - yves@tkaczyk.net) 
// 
// The contents of this file are subject to the Artistic License (the "License"). 
// You may not use this file except in compliance with the License.  
// You may obtain a copy of the License at: 
// http://www.opensource.org/licenses/artistic-license.html 
// 
// Documentation: http://www.codeproject.com/property/treepropsheetex.asp 
// CVS tree:      http://sourceforge.net/projects/treepropsheetex 
// 
///////////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "TreePropSheetResizableLibHook.h" 
#include "TreePropSheetEx.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
namespace TreePropSheet 
{ 
 
//******************************************************************** 
// CResizableSheetHook 
//******************************************************************** 
 
// 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 
}; 
const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT); 
 
// horizontal line in wizard mode 
#define ID_WIZLINE	ID_WIZFINISH+1 
 
// used to save/restore active page 
// either in the registry or a private .INI file 
// depending on your application settings 
 
#define ACTIVEPAGE 	_T("ActivePage") 
 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CResizableSheetHook::CResizableSheetHook(CPropertySheet* const pSheet) 
 : m_pSheet(pSheet) 
{ 
  ASSERT( m_pSheet ); 
 
	PrivateConstruct(); 
 
} 
 
CResizableSheetHook::~CResizableSheetHook() 
{ 
} 
 
////////////////////////////////////////////////////////////////////// 
// Methods 
////////////////////////////////////////////////////////////////////// 
 
void CResizableSheetHook::Initialize() 
{ 
	ASSERT( m_pSheet->GetSafeHwnd() ); 
 
  Hook( m_pSheet ); 
 
  // Perform remaining initialization. 
 
  // From OnCreate 
	// Create and initialize the size-grip. We only do this for child windows. 
	if( m_pSheet->GetStyle() & WS_POPUP ) 
  { 
    CreateSizeGrip(); 
  } 
   
  // From OnInitDialog 
  // set the initial size as the min track size 
	CRect rc; 
	m_pSheet->GetWindowRect(&rc); 
	SetMinTrackSize(rc.Size()); 
 
	// initialize layout 
	PresetLayout(); 
 
	// prevent flickering 
	m_pSheet->GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS); 
} 
 
////////////////////////////////////////////////////////////////////// 
//  
////////////////////////////////////////////////////////////////////// 
 
void CResizableSheetHook::SetMinSize(const CSize& size) 
{ 
	SetMinTrackSize( size ); 
} 
 
////////////////////////////////////////////////////////////////////// 
//  
void CResizableSheetHook::SetMaxSize(const CSize& size) 
{ 
	SetMaxTrackSize( size ); 
} 
 
////////////////////////////////////////////////////////////////////// 
// CHookWnd overrides 
////////////////////////////////////////////////////////////////////// 
 
LRESULT CResizableSheetHook::WindowProc(UINT nMsg,WPARAM wParam,LPARAM lParam) 
{ 
  if( WM_SIZE == nMsg ) 
  { 
    LRESULT lResult = Default(); 
 
    UINT nType = (UINT)wParam; 
 
	  if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) 
		  return lResult;		// arrangement not needed 
 
	  if (nType == SIZE_MAXIMIZED) 
		  HideSizeGrip(&m_dwGripTempState); 
	  else 
		  ShowSizeGrip(&m_dwGripTempState); 
 
	  // update grip and layout 
	  if( IsSizeGripVisible() ) 
      UpdateSizeGrip(); 
	  ArrangeLayout(); 
 
    return lResult; 
  } 
  else if( WM_ERASEBKGND == nMsg ) 
  { 
    // Windows XP doesn't like clipping regions ...try this! 
    EraseBackground( (HDC)wParam ); 
	  return 0L; 
  } 
  else if( WM_GETMINMAXINFO == nMsg ) 
  { 
    LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; 
    MinMaxInfo(lpMMI); 
  } 
  else if( PSN_SETACTIVE == nMsg ) 
  { 
    ASSERT( FALSE ); 
  } 
  else if( WM_CREATE == nMsg ) 
  { 
    return Default(); 
  } 
  else if( WM_DESTROY == nMsg ) 
  { 
    if (m_bEnableSaveRestore) 
    { 
		  SaveWindowRect(m_sSection, m_bRectOnly); 
		  SavePage(); 
	  } 
	  RemoveAllAnchors(); 
  } 
  
 
  return Default(); 
} 
 
BOOL CResizableSheetHook::ArrangeLayoutCallback(LayoutInfo &layout) 
{ 
	if (layout.nCallbackID != 1)	// we only added 1 callback 
		return CResizableLayout::ArrangeLayoutCallback(layout); 
 
	// set layout info for active page 
	layout.hWnd = (HWND)::SendMessage( m_pSheet->GetSafeHwnd(), PSM_GETCURRENTPAGEHWND, 0, 0); 
	if (!::IsWindow(layout.hWnd)) 
		return FALSE; 
 
	// set margins 
	if (IsWizard())	// wizard mode 
	{ 
		// use pre-calculated margins 
		layout.sizeMarginTL = m_sizePageTL; 
		layout.sizeMarginBR = m_sizePageBR; 
	} 
	else	// tab mode 
	{ 
		CTabCtrl* pTab = m_pSheet->GetTabControl(); 
		ASSERT(pTab != NULL); 
 
		// get tab position after resizing and calc page rect 
		CRect rectPage, rectSheet; 
		GetTotalClientRect(&rectSheet); 
 
		VERIFY(GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)); 
		pTab->AdjustRect(FALSE, &rectPage); 
 
		// set margins 
		layout.sizeMarginTL = rectPage.TopLeft() - rectSheet.TopLeft(); 
		layout.sizeMarginBR = rectPage.BottomRight() - rectSheet.BottomRight(); 
	} 
 
	// set anchor types 
	layout.sizeTypeTL = TOP_LEFT; 
	layout.sizeTypeBR = BOTTOM_RIGHT; 
 
	// use this layout info 
	return TRUE; 
} 
 
////////////////////////////////////////////////////////////////////// 
// CResizableLayout implementation 
////////////////////////////////////////////////////////////////////// 
 
CWnd* CResizableSheetHook::GetResizableWnd() 
{ 
	return m_pSheet; 
} 
 
////////////////////////////////////////////////////////////////////// 
// Helpers 
////////////////////////////////////////////////////////////////////// 
 
void CResizableSheetHook::PresetLayout() 
{ 
  if (IsWizard())	// wizard mode 
	{ 
		// hide tab control 
		m_pSheet->GetTabControl()->ShowWindow(SW_HIDE); 
 
		AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT); 
	} 
	else	// tab mode 
	{ 
		AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT); 
	} 
 
	// add a callback for active page (which can change at run-time) 
	AddAnchorCallback(1); 
 
	// use *total* parent size to have correct margins 
	CRect rectPage, rectSheet; 
	GetTotalClientRect(&rectSheet); 
 
	m_pSheet->GetActivePage()->GetWindowRect(&rectPage); 
	::MapWindowPoints(NULL, m_pSheet->GetSafeHwnd(), (LPPOINT)&rectPage, 2); 
 
	// pre-calculate margins 
	m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft(); 
	m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight(); 
 
	// add all possible buttons, if they exist 
	for (int i = 0; i < _propButtonsCount; i++) 
	{ 
		if (NULL != m_pSheet->GetDlgItem(_propButtons[i])) 
			AddAnchor(_propButtons[i], BOTTOM_RIGHT); 
	} 
} 
 
inline void CResizableSheetHook::PrivateConstruct() 
{ 
	m_bEnableSaveRestore = FALSE; 
	m_bSavePage = FALSE; 
	m_dwGripTempState = 1; 
} 
 
void CResizableSheetHook::SavePage() 
{ 
	if (!m_bSavePage) 
		return; 
 
	// saves active page index, zero (the first) if problems 
	// cannot use GetActivePage, because it always fails 
 
	CTabCtrl *pTab = m_pSheet->GetTabControl(); 
	int page = 0; 
 
	if (pTab != NULL)  
		page = pTab->GetCurSel(); 
	if (page < 0) 
		page = 0; 
 
	AfxGetApp()->WriteProfileInt(m_sSection, ACTIVEPAGE, page); 
} 
 
void CResizableSheetHook::LoadPage() 
{ 
	// restore active page, zero (the first) if not found 
	int page = AfxGetApp()->GetProfileInt(m_sSection, ACTIVEPAGE, 0); 
	 
	if (m_bSavePage) 
	{ 
		m_pSheet->SetActivePage(page); 
		ArrangeLayout();	// needs refresh 
	} 
} 
 
BOOL CResizableSheetHook::IsWizard() 
{ 
  return (m_pSheet->m_psh.dwFlags & PSH_WIZARD);  
} 
 
void CResizableSheetHook::EnableSaveRestore(LPCTSTR pszSection,BOOL bRectOnly /*=FALSE*/,BOOL bWithPage /*=FALSE*/) 
{ 
	m_sSection = pszSection; 
	m_bSavePage = bWithPage; 
 
	m_bEnableSaveRestore = TRUE; 
	m_bRectOnly = bRectOnly; 
 
	// restore immediately 
	LoadWindowRect(pszSection, bRectOnly); 
	LoadPage(); 
} 
 
int CResizableSheetHook::GetMinWidth() 
{ 
	CWnd* pWnd = NULL; 
	CRect rectWnd, rectSheet; 
	GetTotalClientRect(&rectSheet); 
 
	int max = 0, min = rectSheet.Width(); 
	// search for leftmost and rightmost button margins 
	for (int i = 0; i < 7; i++) 
	{ 
		pWnd = m_pSheet->GetDlgItem(_propButtons[i]); 
		// exclude not present or hidden buttons 
		if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE)) 
			continue; 
 
		// left position is relative to the right border 
		// of the parent window (negative value) 
		pWnd->GetWindowRect(&rectWnd); 
		::MapWindowPoints(NULL, m_pSheet->GetSafeHwnd(), (LPPOINT)&rectWnd, 2); 
		int left = rectSheet.right - rectWnd.left; 
		int right = rectSheet.right - rectWnd.right; 
 
		if (left > max) 
			max = left; 
		if (right < min) 
			min = right; 
	} 
 
	// sizing border width 
	int border = GetSystemMetrics(SM_CXSIZEFRAME); 
	 
	// compute total width 
	return max + min + 2*border; 
} 
 
//******************************************************************** 
// CTreePropSheetResizableLibHook 
//******************************************************************** 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CTreePropSheetResizableLibHook::CTreePropSheetResizableLibHook(TreePropSheet::CTreePropSheetEx* pTreePropSheet) 
 : CResizableSheetHook(pTreePropSheet), 
   m_pTreePropSheet(pTreePropSheet) 
{ 
} 
 
CTreePropSheetResizableLibHook::~CTreePropSheetResizableLibHook() 
{ 
} 
 
////////////////////////////////////////////////////////////////////// 
// Overridable 
////////////////////////////////////////////////////////////////////// 
 
void CTreePropSheetResizableLibHook::PresetLayout() 
{ 
	/* If in tree mode, register the tree and the frame with the layout manager. */ 
  if( m_pTreePropSheet->IsTreeViewMode() )      // Tree mode 
  { 
  	m_pTreePropSheet->GetPageTreeControl()->ModifyStyle(0, WS_CLIPSIBLINGS); 
	  m_pTreePropSheet->GetFrameControl()->GetWnd()->ModifyStyle(0, WS_CLIPSIBLINGS); 
    AddAnchor( m_pTreePropSheet->GetSplitterWnd()->GetSafeHwnd(), TOP_LEFT, BOTTOM_RIGHT ); 
    // Save the margin between the frame and the current page. This rect should NOT be normalized. 
    CRect rectFrame, rectPage; 
    ::GetWindowRect( m_pTreePropSheet->GetFrameControl()->GetWnd()->GetSafeHwnd(), &rectFrame ); 
    ::GetWindowRect( m_pTreePropSheet->GetActivePage()->GetSafeHwnd(), &rectPage ); 
    m_rectFramePageMargins.SetRect( rectPage.left - rectFrame.left, 
                                    rectPage.top - rectFrame.top, 
                                    rectFrame.right - rectPage.right, 
                                    rectFrame.bottom - rectPage.bottom ); 
  	AddAnchorCallback(1);   // Callback for frame 
	  AddAnchorCallback(2);   // Callback for page 
  } 
  else 
  { 
    if (IsWizard())	                        // wizard mode 
	  { 
		  // hide tab control 
		  m_pSheet->GetTabControl()->ShowWindow(SW_HIDE); 
 
		  AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT); 
	  } 
	  else	                                        // tab mode 
	  { 
		  AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT); 
	  } 
 
	  // add a callback for active page (which can change at run-time) 
	  AddAnchorCallback(1); 
  } 
 
	// use *total* parent size to have correct margins 
	CRect rectPage, rectSheet; 
	GetTotalClientRect(&rectSheet); 
 
	m_pSheet->GetActivePage()->GetWindowRect(&rectPage); 
	::MapWindowPoints(NULL, m_pSheet->GetSafeHwnd(), (LPPOINT)&rectPage, 2); 
 
	// pre-calculate margins 
	m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft(); 
	m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight(); 
 
	// add all possible buttons, if they exist 
  for (int i = 0; i < _propButtonsCount; i++) 
	{ 
    if (NULL != m_pSheet->GetDlgItem(_propButtons[i])) 
      AddAnchor(_propButtons[i], BOTTOM_RIGHT); 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
BOOL CTreePropSheetResizableLibHook::ArrangeLayoutCallback(LayoutInfo &layout) 
{ 
	// Handle the tree callbacks in another methods. 
  if( m_pTreePropSheet->IsTreeViewMode() )    // Tree mode 
  { 
    return TreeModeCallbacks( layout ); 
  } 
 
	if (layout.nCallbackID != 1)	// we only added 1 callback 
		return CResizableSheetHook::ArrangeLayoutCallback(layout); 
 
	// set layout info for active page 
	layout.hWnd = (HWND)::SendMessage( m_pSheet->GetSafeHwnd(), PSM_GETCURRENTPAGEHWND, 0, 0); 
	if (!::IsWindow(layout.hWnd)) 
		return FALSE; 
 
	if( m_pTreePropSheet->IsWizard() )	   // wizard mode 
	{ 
		// use pre-calculated margins 
		layout.sizeMarginTL = m_sizePageTL; 
		layout.sizeMarginBR = m_sizePageBR; 
	} 
	else	                                 // tab mode 
	{ 
		CTabCtrl* pTab = m_pSheet->GetTabControl(); 
		ASSERT(pTab != NULL); 
 
		// get tab position after resizing and calc page rect 
		CRect rectPage, rectSheet; 
		GetTotalClientRect(&rectSheet); 
 
		VERIFY(GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)); 
		pTab->AdjustRect(FALSE, &rectPage); 
 
		// set margins 
		layout.sizeMarginTL = rectPage.TopLeft() - rectSheet.TopLeft(); 
		layout.sizeMarginBR = rectPage.BottomRight() - rectSheet.BottomRight(); 
	} 
 
	// set anchor types 
	layout.sizeTypeTL = TOP_LEFT; 
	layout.sizeTypeBR = BOTTOM_RIGHT; 
 
	// use this layout info 
	return TRUE; 
} 
 
BOOL CTreePropSheetResizableLibHook::TreeModeCallbacks(LayoutInfo &layout) 
{ 
	ASSERT( m_pTreePropSheet->IsTreeViewMode() ); 
 
  if (layout.nCallbackID != 1 && layout.nCallbackID != 2)	// we only added 1 callback 
		return CResizableSheetHook::ArrangeLayoutCallback(layout); 
 
  /* Callbacks: 
      1: Tab 
      2: Page */ 
 
  CWnd* pFrame = m_pTreePropSheet->GetFrameControl()->GetWnd(); 
  ASSERT( pFrame ); 
  CRect rectSheet, rectFrame; 
  m_pTreePropSheet->GetClientRect( &rectSheet ); 
	pFrame->GetWindowRect(&rectFrame); 
  m_pTreePropSheet->ScreenToClient(&rectFrame); 
 
  if( layout.nCallbackID == 1 ) 
  { // Tab control 
    // Need to set the tab and page according to the frame. Since this  
    // is resized by 'anchors', it is guaranteed to be already resized  
    // properly. 
    layout.hWnd = m_pTreePropSheet->GetTabControl()->GetSafeHwnd(); 
     
	  layout.sizeTypeTL = TOP_LEFT; 
	  layout.sizeTypeBR = BOTTOM_RIGHT; 
 
		// set margins 
		layout.sizeMarginTL = rectFrame.TopLeft() - rectSheet.TopLeft(); 
		layout.sizeMarginBR = rectFrame.BottomRight() - rectSheet.BottomRight(); 
 
    ::MoveWindow( layout.hWnd, rectFrame.left, rectFrame.top, rectFrame.Width(), rectFrame.Height(), FALSE ); 
  } 
  else 
  { // Page 
	  // set layout info for active page 
	  layout.hWnd = (HWND)::SendMessage( m_pSheet->GetSafeHwnd(), PSM_GETCURRENTPAGEHWND, 0, 0); 
	  if (!::IsWindow(layout.hWnd)) 
		  return FALSE; 
 
	  layout.sizeTypeTL = TOP_LEFT; 
	  layout.sizeTypeBR = BOTTOM_RIGHT; 
    rectFrame.DeflateRect( m_rectFramePageMargins ); 
 
		// set margins 
		layout.sizeMarginTL = rectFrame.TopLeft() - rectSheet.TopLeft(); 
		layout.sizeMarginBR = rectFrame.BottomRight() - rectSheet.BottomRight(); 
 
    ::MoveWindow( layout.hWnd, rectFrame.left, rectFrame.top, rectFrame.Width(), rectFrame.Height(), FALSE ); 
  } 
  return TRUE; 
} 
 
};