www.pudn.com > 酒店管理系统源代码.rar > RollupCtrl.cpp


////////////////////////////////////////////////////////////////////////////// 
// 
// RollupCtrl.cpp 
//  
// Code Johann Nadalutti 
// Mail: jnadalutti@worldonline.fr 
// 
////////////////////////////////////////////////////////////////////////////// 
// 
// This code is free for personal and commercial use, providing this  
// notice remains intact in the source files and all eventual changes are 
// clearly marked with comments. 
// 
// No warrantee of any kind, express or implied, is included with this 
// software; use at your own risk, responsibility for damages (if any) to 
// anyone resulting from the use of this software rests entirely with the 
// user. 
// 
////////////////////////////////////////////////////////////////////////////// 
// 
// History 
// -------- 
// #v1.0 
//	31/03/01:	Created 
// 
// #v1.01 
//	13/04/01:	Added ScrollToPage() method 
//				Added automatic page visibility to ExpandPage() method 
//				Added Mousewheel support 
//	15/04/01:	Added mouse capture checking on WM_MOUSEMOVE dialog msg 
//				Added SetCursor() on Dialog WM_SETCURSOR 
//				Added MovePageAt() method 
//	17/04/01:	Fixed Group Boxes displayed over Buttons 
//	20/04/01:	Added IsPageExpanded() and IsPageExpanded() methods 
//				Added PopupMenu 
//				Added Button subclassing (now button's focus not drawn) 
// 
// Note 
// ----- 
//	Dialog box width is 
//		RollupCtrlClientRect.Width() - RC_SCROLLBARWIDTH - (RC_GRPBOXINDENT*2) 
// 
// 
// Thanks to 
// ---------- 
// PJ Arends, Ramon Smits, Uwe Keim, Daniel Madden, Do Quyet Tien, 
// Ravi Bhavnani, Masaaki Onishi, ... 
// and all others users for their comments. 
// 
///////////////////////////////////////////////////////////////////////////// 
 
///////////////////////////////////////////////////////////////////////////// 
// CRollupCtrl Includes 
#include "stdafx.h" 
#include "RollupCtrl.h" 
 
///////////////////////////////////////////////////////////////////////////// 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CRollupCtrl Message Map 
 
BEGIN_MESSAGE_MAP(CRollupCtrl, CWnd) 
	//{{AFX_MSG_MAP(CRollupCtrl) 
	ON_WM_PAINT() 
	ON_WM_SIZE() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_MOUSEMOVE() 
	ON_WM_MOUSEWHEEL() 
	ON_WM_MOUSEACTIVATE() 
	ON_WM_CONTEXTMENU() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CRollupCtrl Implementation 
 
IMPLEMENT_DYNCREATE(CRollupCtrl, CWnd) 
 
//--------------------------------------------------------------------------- 
// Constructor 
//--------------------------------------------------------------------------- 
CRollupCtrl::CRollupCtrl() 
{ 
	m_strMyClass = AfxRegisterWndClass( 
		CS_VREDRAW | CS_HREDRAW, 
		(HCURSOR)::LoadCursor(NULL, IDC_ARROW), 
		(HBRUSH)COLOR_WINDOW, 
		NULL); 
 
	m_nStartYPos = m_nPageHeight = 0; 
} 
 
//--------------------------------------------------------------------------- 
// Destructor 
//--------------------------------------------------------------------------- 
CRollupCtrl::~CRollupCtrl() 
{ 
	//Remove all pages allocations 
	for (int i=0; ipwndButton)		delete m_PageList[i]->pwndButton; 
		if (m_PageList[i]->pwndGroupBox)	delete m_PageList[i]->pwndGroupBox; 
 
		if (m_PageList[i]->pwndTemplate && m_PageList[i]->bAutoDestroyTpl)	{ 
			m_PageList[i]->pwndTemplate->DestroyWindow(); 
			delete m_PageList[i]->pwndTemplate; 
		} 
 
		delete m_PageList[i]; 
	} 
 
} 
 
//--------------------------------------------------------------------------- 
// Create 
//--------------------------------------------------------------------------- 
BOOL CRollupCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) 
{ 
	return  CWnd::Create(m_strMyClass, "RollupCtrl", dwStyle, rect, pParentWnd, nID); 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: InsertPage 
// Description		: Return -1 if an error occurs 
//					  Make sure template had WS_CHILD style 
//--------------------------------------------------------------------------- 
int CRollupCtrl::InsertPage(LPCTSTR caption, UINT nIDTemplate, CRuntimeClass* rtc, int idx) 
{ 
	if (idx>0 && idx>=m_PageList.GetSize())		idx=-1; 
 
	//Create Template 
	ASSERT(rtc!=NULL); 
	CDialog* pwndTemplate = (CDialog*)rtc->CreateObject(); 
	BOOL b = pwndTemplate->Create(nIDTemplate, this); 
	if (!b)	{ delete pwndTemplate; return -1; } 
 
	//Insert Page 
	return _InsertPage(caption, pwndTemplate, idx, TRUE); 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: InsertPage 
// Description		: return -1 if an error occurs 
//					  Make sure template had WS_CHILD style 
//--------------------------------------------------------------------------- 
int CRollupCtrl::InsertPage(LPCTSTR caption, CDialog* pwndTemplate, BOOL bAutoDestroyTpl, int idx) 
{ 
	if (!pwndTemplate)		return -1; 
 
	if (idx>0 && idx>=m_PageList.GetSize())		idx=-1; 
 
	//Insert Page 
	return _InsertPage(caption, pwndTemplate, idx, bAutoDestroyTpl); 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: InsertPage 
// Description		: Called by InsertPage(...) methods 
//					  Return -1 if an error occurs 
//					  Make sure template had WS_CHILD style 
//--------------------------------------------------------------------------- 
int CRollupCtrl::_InsertPage(LPCTSTR caption, CDialog* pwndTemplate, int idx, BOOL bAutoDestroyTpl) 
{ 
	ASSERT(pwndTemplate!=NULL); 
	ASSERT(pwndTemplate->m_hWnd!=NULL); 
 
 	//Get client rect 
	CRect r; GetClientRect(r); 
 
	//Create GroupBox 
	CButton* groupbox = new CButton; 
	groupbox->Create("", WS_CHILD|BS_GROUPBOX, r, this, 0 ); 
 
	//Create Button 
	CButton* but = new CButton; 
	but->Create(caption, WS_CHILD|BS_AUTOCHECKBOX|BS_PUSHLIKE|BS_FLAT, r, this, 0 );  
 
	//Change Button's font 
	HFONT hfont= (HFONT)::GetStockObject(DEFAULT_GUI_FONT); 
	CFont* font = CFont::FromHandle(hfont); 
	but->SetFont(font); 
 
	//Add page at pagelist 
	RC_PAGEINFO*	pi = new RC_PAGEINFO; 
	pi->bExpanded		= FALSE; 
	pi->bEnable			= TRUE; 
	pi->pwndTemplate	= pwndTemplate; 
	pi->pwndButton		= but; 
	pi->pwndGroupBox	= groupbox; 
	pi->pOldDlgProc		= (WNDPROC)::GetWindowLong(pwndTemplate->m_hWnd, DWL_DLGPROC); 
	pi->pOldButProc		= (WNDPROC)::GetWindowLong(but->m_hWnd, GWL_WNDPROC); 
	pi->bAutoDestroyTpl	= bAutoDestroyTpl; 
 
	int newidx; 
	if (idx<0)	newidx = m_PageList.Add(pi); 
	else	{ m_PageList.InsertAt(idx, pi); newidx=idx; } 
 
	//Set Dlg Window datas 
	::SetWindowLong(pwndTemplate->m_hWnd, GWL_USERDATA,	(LONG)m_PageList[newidx]); 
	::SetWindowLong(pwndTemplate->m_hWnd, DWL_USER,		(LONG)this); 
 
	//Set But Window data 
	::SetWindowLong(but->m_hWnd, GWL_USERDATA,	(LONG)m_PageList[newidx]); 
 
	//SubClass Template window proc 
	::SetWindowLong(pwndTemplate->m_hWnd, DWL_DLGPROC, (LONG)CRollupCtrl::DlgWindowProc); 
 
	//SubClass Button window proc 
	::SetWindowLong(but->m_hWnd, GWL_WNDPROC, (LONG)CRollupCtrl::ButWindowProc); 
 
	//Update 
	m_nPageHeight+=RC_PGBUTTONHEIGHT+(RC_GRPBOXINDENT/2); 
	RecalLayout(); 
 
	return newidx; 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: RemovePage 
// Description		:  
//--------------------------------------------------------------------------- 
void CRollupCtrl::RemovePage(int idx) 
{ 
	if (idx>=m_PageList.GetSize() || idx<0)				return; 
 
	//Remove 
	_RemovePage(idx); 
 
	//Update 
	RecalLayout(); 
} 
 
//--------------------------------------------------------------------------- 
// Function name	: RemoveAllPages 
// Description		: 
//--------------------------------------------------------------------------- 
void CRollupCtrl::RemoveAllPages() 
{ 
	//Remove all 
	for (; m_PageList.GetSize();) 
		_RemovePage(0); 
 
	//Update 
	RecalLayout(); 
} 
 
//--------------------------------------------------------------------------- 
// Function name	: _RemovePage 
// Description		: Called by RemovePage or RemoveAllPages methods 
//--------------------------------------------------------------------------- 
void CRollupCtrl::_RemovePage(int idx) 
{ 
	RC_PAGEINFO* pi = m_PageList[idx]; 
 
	//Get Page Rect 
	CRect tr; pi->pwndTemplate->GetWindowRect(&tr); 
 
	//Update PageHeight 
	m_nPageHeight-=RC_PGBUTTONHEIGHT+(RC_GRPBOXINDENT/2); 
	if (pi->bExpanded)		m_nPageHeight-=tr.Height(); 
 
	//Remove wnds 
	if (pi->pwndButton)				delete pi->pwndButton; 
	if (pi->pwndGroupBox)			delete pi->pwndGroupBox; 
 
	if (pi->pwndTemplate && pi->bAutoDestroyTpl) { 
		pi->pwndTemplate->DestroyWindow(); 
		delete pi->pwndTemplate; 
	} 
 
	//Remove page from array 
	m_PageList.RemoveAt(idx); 
 
	//Delete pageinfo 
	delete pi; 
} 
 
//--------------------------------------------------------------------------- 
// Function name	: ExpandPage 
// Description		: 
//--------------------------------------------------------------------------- 
void CRollupCtrl::ExpandPage(int idx, BOOL bExpand) 
{ 
	if (idx>=m_PageList.GetSize() || idx<0)				return; 
 
	//Expand-collapse 
	_ExpandPage(m_PageList[idx], bExpand); 
 
	//Update 
	RecalLayout(); 
 
	//Scroll to this page (Automatic page visibility) 
	if (bExpand)	ScrollToPage(idx, FALSE); 
 
} 
 
//--------------------------------------------------------------------------- 
// Function name	: ExpandAllPages 
// Description		:  
//--------------------------------------------------------------------------- 
void CRollupCtrl::ExpandAllPages(BOOL bExpand) 
{ 
	//Expand-collapse All 
	for (int i=0; ibExpanded==bExpand)					return; 
	if (!pi->bEnable)							return; 
 
	//Get Page Rect 
	CRect tr; pi->pwndTemplate->GetWindowRect(&tr); 
 
	//Expand-collapse 
	pi->bExpanded = bExpand; 
 
	if (bExpand)	m_nPageHeight+=tr.Height(); 
	else			m_nPageHeight-=tr.Height(); 
 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: EnablePage 
// Description		:  
//--------------------------------------------------------------------------- 
void CRollupCtrl::EnablePage(int idx, BOOL bEnable) 
{ 
	if (idx>=m_PageList.GetSize() || idx<0)		return; 
 
	//Enable-Disable 
	_EnablePage(m_PageList[idx], bEnable); 
 
	//Update 
	RecalLayout(); 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: EnableAllPages 
// Description		:  
//--------------------------------------------------------------------------- 
void CRollupCtrl::EnableAllPages(BOOL bEnable) 
{ 
	//Enable-disable All 
	for (int i=0; ibEnable==bEnable)		return; 
 
	//Get Page Rect 
	CRect tr; pi->pwndTemplate->GetWindowRect(&tr); 
 
	//Change state 
	pi->bEnable = bEnable; 
 
	if (pi->bExpanded)	{ m_nPageHeight-=tr.Height(); pi->bExpanded=FALSE; } 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: ScrollToPage 
// Description		: Scroll a page at the top of the RollupCtrl if bAtTheTop=TRUE 
//					  or just ensure page visibility into view if bAtTheTop=FALSE 
//--------------------------------------------------------------------------- 
void CRollupCtrl::ScrollToPage(int idx, BOOL bAtTheTop) 
{ 
	if (idx>=m_PageList.GetSize() || idx<0)				return; 
 
	//Get page infos 
	RC_PAGEINFO* pi = m_PageList[idx]; 
 
	//Get windows rect 
	CRect r; GetWindowRect(&r); 
	CRect tr; pi->pwndTemplate->GetWindowRect(&tr); 
 
	//Check page visibility 
	if (bAtTheTop || ((tr.bottom>r.bottom) || (tr.toppwndButton->GetWindowRect(&tr); 
		m_nStartYPos-= (tr.top-r.top); 
 
		//Update 
		RecalLayout(); 
	} 
 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: MovePageAt 
// Description		: newidx can be equal to -1 (move at end) 
//					  Return -1 if an error occurs 
//--------------------------------------------------------------------------- 
int CRollupCtrl::MovePageAt(int idx, int newidx) 
{ 
	if (idx==newidx)									return -1; 
	if (idx>=m_PageList.GetSize() || idx<0)				return -1; 
 
	if (newidx>0 && newidx>=m_PageList.GetSize())		newidx=-1; 
 
	//Remove page from its old position 
	RC_PAGEINFO* pi = m_PageList[idx]; 
	m_PageList.RemoveAt(idx); 
 
	//Insert at its new position 
	int retidx; 
	if (newidx<0)	retidx = m_PageList.Add(pi); 
	else	{ m_PageList.InsertAt(newidx, pi); retidx=newidx; } 
 
 
	//Update 
	RecalLayout(); 
	 
	return retidx; 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: IsPageExpanded 
// Description		:  
//--------------------------------------------------------------------------- 
BOOL CRollupCtrl::IsPageExpanded(int idx) 
{ 
	if (idx>=m_PageList.GetSize() || idx<0)				return FALSE; 
	return m_PageList[idx]->bExpanded; 
} 
 
//--------------------------------------------------------------------------- 
// Function name	: IsPageEnabled 
// Description		:  
//--------------------------------------------------------------------------- 
BOOL CRollupCtrl::IsPageEnabled(int idx) 
{ 
	if (idx>=m_PageList.GetSize() || idx<0)				return FALSE; 
	return m_PageList[idx]->bEnable; 
} 
 
 
//--------------------------------------------------------------------------- 
// Function name	: RecalLayout 
// Description		:  
//--------------------------------------------------------------------------- 
void CRollupCtrl::RecalLayout() 
{ 
	//Check StartPosY 
	CRect r; GetClientRect(&r); 
	int BottomPagePos = m_nStartYPos+m_nPageHeight; 
 
	if (BottomPagePos0)					m_nStartYPos = 0; 
 
 
	//Update layout 
	HDWP hdwp = BeginDeferWindowPos(m_PageList.GetSize()*3);	//*3 for pwndButton+pwndTemplate+pwndGroupBox 
 
	int posy=m_nStartYPos; 
 
	for (int i=0; ipwndButton->SetCheck(pi->bEnable&pi->bExpanded); 
		pi->pwndButton->EnableWindow(pi->bEnable); 
 
		//Expanded 
		if (pi->bExpanded && pi->bEnable) { 
			CRect tr; pi->pwndTemplate->GetWindowRect(&tr); 
 
			//Update GroupBox position and size 
			DeferWindowPos(hdwp, pi->pwndGroupBox->m_hWnd, 0, 2, posy, r.Width()-3-RC_SCROLLBARWIDTH, tr.Height()+RC_PGBUTTONHEIGHT+RC_GRPBOXINDENT-4, SWP_NOZORDER|SWP_SHOWWINDOW); 
 
			//Update Template position and size 
			DeferWindowPos(hdwp, pi->pwndTemplate->m_hWnd, 0, RC_GRPBOXINDENT, posy+RC_PGBUTTONHEIGHT, r.Width()-RC_SCROLLBARWIDTH-(RC_GRPBOXINDENT*2), tr.Height(), SWP_NOZORDER|SWP_SHOWWINDOW); 
 
			//Update Button's position and size 
			DeferWindowPos(hdwp, pi->pwndButton->m_hWnd, 0, RC_GRPBOXINDENT, posy, r.Width()-RC_SCROLLBARWIDTH-(RC_GRPBOXINDENT*2), RC_PGBUTTONHEIGHT, SWP_NOZORDER|SWP_SHOWWINDOW); 
 
			posy+=tr.Height()+RC_PGBUTTONHEIGHT; 
 
		//Collapsed 
		} else { 
 
			//Update GroupBox position and size 
			DeferWindowPos(hdwp, pi->pwndGroupBox->m_hWnd, 0, 2, posy, r.Width()-3-RC_SCROLLBARWIDTH, 16,SWP_NOZORDER|SWP_SHOWWINDOW); 
 
			//Update Template position and size 
			DeferWindowPos(hdwp, pi->pwndTemplate->m_hWnd, 0, RC_GRPBOXINDENT, 0, 0, 0,SWP_NOZORDER|SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE); 
 
			//Update Button's position and size 
			DeferWindowPos(hdwp, pi->pwndButton->m_hWnd, 0, RC_GRPBOXINDENT, posy, r.Width()-RC_SCROLLBARWIDTH-(RC_GRPBOXINDENT*2), RC_PGBUTTONHEIGHT, SWP_NOZORDER|SWP_SHOWWINDOW); 
 
			posy+=RC_PGBUTTONHEIGHT; 
		} 
 
		posy+=(RC_GRPBOXINDENT/2); 
 
	} 
	EndDeferWindowPos(hdwp); 
 
 
	//Update Scroll Bar 
	CRect br = CRect(r.right-RC_SCROLLBARWIDTH,r.top, r.right, r.bottom); 
	InvalidateRect(&br, FALSE); 
	UpdateWindow(); 
} 
 
//--------------------------------------------------------------------------- 
// Function name	: GetPageIdxFromButtonHWND 
// Description		: Return -1 if matching hwnd not found 
//--------------------------------------------------------------------------- 
int CRollupCtrl::GetPageIdxFromButtonHWND(HWND hwnd) 
{ 
	//Search matching button's hwnd 
	for (int i=0; ipwndButton->m_hWnd)		return i; 
 
	return -1; 
} 
 
//--------------------------------------------------------------------------- 
// Function name	: GetPageInfo 
// Description		: Return -1 if an error occurs 
//--------------------------------------------------------------------------- 
RC_PAGEINFO* CRollupCtrl::GetPageInfo(int idx) 
{ 
	if (idx>=m_PageList.GetSize() || idx<0)				return (RC_PAGEINFO*)-1; 
 
	return m_PageList[idx]; 
} 
 
 
//--------------------------------------------------------------------------- 
// Dialog SubClasser 
//--------------------------------------------------------------------------- 
LRESULT CALLBACK CRollupCtrl::DlgWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
	RC_PAGEINFO* pi		= (RC_PAGEINFO*)GetWindowLong(hWnd, GWL_USERDATA); 
	CRollupCtrl* _this	= (CRollupCtrl*)GetWindowLong(hWnd, DWL_USER); 
 
	CRect r; _this->GetClientRect(&r); 
	if (_this->m_nPageHeight>r.Height())	//Can Scroll ? 
	{ 
 
		switch (uMsg) { 
 
			case WM_LBUTTONDOWN: 
			case WM_MBUTTONDOWN: 
			{ 
				CPoint pos; GetCursorPos(&pos); 
				_this->m_nOldMouseYPos = pos.y; 
				::SetCapture(hWnd); 
			return 0; 
			} 
 
			case WM_LBUTTONUP: 
			case WM_MBUTTONUP: 
			{ 
				if (::GetCapture() == hWnd)	{ ::ReleaseCapture(); return 0; } 
			break; 
			} 
 
			case WM_MOUSEMOVE: 
			{ 
				if ((::GetCapture() == hWnd) && (wParam==MK_LBUTTON || wParam==MK_MBUTTON)) { 
					CPoint pos; GetCursorPos(&pos); 
					_this->m_nStartYPos+=(pos.y-_this->m_nOldMouseYPos); 
					_this->RecalLayout(); 
					_this->m_nOldMouseYPos = pos.y; 
					return 0; 
				} 
 
			break; 
			} 
 
			case WM_SETCURSOR: 
				if ((HWND)wParam==hWnd)	{ ::SetCursor(::LoadCursor(NULL, RC_ROLLCURSOR)); return TRUE; } 
			break; 
 
		}//switch(uMsg) 
	} 
 
	return ::CallWindowProc(pi->pOldDlgProc, hWnd, uMsg, wParam, lParam); 
} 
 
 
//--------------------------------------------------------------------------- 
// Button SubClasser 
//--------------------------------------------------------------------------- 
LRESULT CALLBACK CRollupCtrl::ButWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
	if (uMsg==WM_SETFOCUS)		return FALSE; 
 
	RC_PAGEINFO* pi	= (RC_PAGEINFO*)GetWindowLong(hWnd, GWL_USERDATA); 
	return ::CallWindowProc(pi->pOldButProc, hWnd, uMsg, wParam, lParam); 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CRollupCtrl message handlers 
 
//--------------------------------------------------------------------------- 
// OnCommand 
//--------------------------------------------------------------------------- 
BOOL CRollupCtrl::OnCommand(WPARAM wParam, LPARAM lParam)  
{ 
	//PopupMenu command ExpandAllPages 
	if		(LOWORD(wParam)==RC_IDM_EXPANDALL)			ExpandAllPages(TRUE); 
	else if	(LOWORD(wParam)==RC_IDM_COLLAPSEALL)		ExpandAllPages(FALSE); 
 
	//PopupMenu command ExpandPage 
	else if (LOWORD(wParam)>=RC_IDM_STARTPAGES 
		&&	 LOWORD(wParam)bExpanded); 
			return 0; 
		} 
	} 
 
	return CWnd::OnCommand(wParam, lParam); 
} 
 
//--------------------------------------------------------------------------- 
// OnPaint 
//--------------------------------------------------------------------------- 
void CRollupCtrl::OnPaint()  
{ 
	CPaintDC dc(this); 
 
	//Draw ScrollBar 
	CRect r; GetClientRect(&r); 
	CRect br = CRect(r.right-RC_SCROLLBARWIDTH,r.top, r.right, r.bottom); 
	dc.DrawEdge(&br, EDGE_RAISED, BF_RECT  ); 
 
	int SB_Pos	= 0; 
	int SB_Size = 0; 
	int ClientHeight = r.Height()-4; 
 
	if (m_nPageHeight>r.Height()) { 
		SB_Size = ClientHeight-(((m_nPageHeight-r.Height())*ClientHeight)/m_nPageHeight); 
		SB_Pos	= -(m_nStartYPos*ClientHeight)/m_nPageHeight; 
	} else { 
		SB_Size = ClientHeight; 
	} 
 
	br.left		+=2; 
	br.right	-=1; 
	br.top		= SB_Pos+2; 
	br.bottom	= br.top+SB_Size; 
 
	dc.FillSolidRect(&br, RC_SCROLLBARCOLOR); 
	dc.FillSolidRect(CRect(br.left,2,br.right,br.top), RGB(0,0,0)); 
	dc.FillSolidRect(CRect(br.left,br.bottom,br.right,2+ClientHeight), RGB(0,0,0)); 
 
	// Do not call CWnd::OnPaint() for painting messages 
} 
 
//--------------------------------------------------------------------------- 
// OnSize 
//--------------------------------------------------------------------------- 
void CRollupCtrl::OnSize(UINT nType, int cx, int cy)  
{ 
	CWnd::OnSize(nType, cx, cy); 
	RecalLayout(); 
} 
 
//--------------------------------------------------------------------------- 
// OnLButtonDown 
//--------------------------------------------------------------------------- 
void CRollupCtrl::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
	CRect r; GetClientRect(&r); 
	if (m_nPageHeight<=r.Height())		return;	//Can't Scroll 
 
	CRect br = CRect(r.right-RC_SCROLLBARWIDTH,r.top, r.right, r.bottom); 
 
	if ((nFlags&MK_LBUTTON) && br.PtInRect(point)) { 
 
		SetCapture(); 
 
		int ClientHeight = r.Height()-4; 
 
		int SB_Size = ClientHeight-(((m_nPageHeight-r.Height())*ClientHeight)/m_nPageHeight); 
		int	SB_Pos	= -(m_nStartYPos*ClientHeight)/m_nPageHeight; 
 
		//Click inside scrollbar cursor 
		if ((point.y<(SB_Pos+SB_Size)) && (point.y>SB_Pos)) { 
 
			m_nSBOffset = SB_Pos-point.y+1; 
		 
		//Click outside scrollbar cursor (2 cases => above or below cursor) 
		} else { 
			int distup	= point.y-SB_Pos;	 
			int distdown= (SB_Pos+SB_Size)-point.y; 
			if (distuppwndButton->GetWindowText(cstrPageName); 
			menu.AppendMenu(MF_STRING, RC_IDM_STARTPAGES+i, cstrPageName);	 
			if (m_PageList[i]->bExpanded) 
				menu.CheckMenuItem(RC_IDM_STARTPAGES+i, MF_CHECKED); 
		} 
 
		menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON, point.x, point.y, this); 
	} 
}