Click here to Skip to main content
15,885,309 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 254.8K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
// ==========================================================================
// 					Class Implementation : COXRollup
// ==========================================================================

// Source file : oxrollup.cpp

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
                         
// //////////////////////////////////////////////////////////////////////////


#include "stdafx.h"
#include "OXTleBar.h"
#include "OXRollup.h"

#include <stdlib.h>		
#include "UTB64Bit.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

// internal struct for helping scrolling

#define IDC_CAPTION			1		// ID of caption

IMPLEMENT_DYNAMIC(COXRollup, CDialog);

#define new DEBUG_NEW		// track memory allocation with line numbers

/////////////////////////////////////////////////////////////////////////////
// Definition of static members
CPtrList COXRollup::m_RollupList;
CPtrList COXRollup::m_ArrangedRollups;

// Data members -------------------------------------------------------------
// protected:
	// COXTitleBar* m_pTitleBar;
	// --- Pointer to the Titlebar window

	// BOOL	m_bRolledUp;
	// --- rolled up?

	// BOOL	m_bResizingFrame;
	// --- do we have a resizing frame?
	
	// UINT	m_myTimerID;
	// --- timer id used for rolling up and down
	
	// int m_xWidth;
	// int m_yHeight;
	// --- stored heights and widths of rollup (for resizeable)

	// CMenu* m_pSysMenu;
	// --- pointer to system menu
	
	// WORD m_Rollup;
	// --- ID of our dialog, external
	
	// UINT	m_nTemplateID;
	// --- Ressource ID of dialog
	
	// HWND	m_hWndMR;
	// --- window getting messages (currently)

	// HWND	m_hWndDestroyRC;
	// --- window that gets call to destroy rollup	

	// CString m_sCaption;
	// --- caption of Rollup

// private:
	
// Member functions ---------------------------------------------------------
// public:

COXRollup::COXRollup(UINT nTemplate,CWnd* pParent /*=NULL*/)
	: CDialog(nTemplate, pParent),
	m_myTimerID(12345),	// timer id
	m_nTemplateID(nTemplate),
	m_bResizingFrame(FALSE),
	m_bRolledUp(FALSE),                   
	m_xWidth(-1),
	m_yHeight(-1),
	m_nRollup(0),
	m_nScrollSteps(ROLL_STATES),
	m_pSysMenu(NULL),
	m_pTitleBar(NULL),
	m_hWndMR(NULL),
	m_hWndDestroyRC(NULL),
	m_bIsArranged(FALSE),
	m_bRolling(FALSE)
	{
	// add entry to our rollup list
	m_RollupList.AddTail(this);
	}

COXRollup::~COXRollup()
	{
	if (m_pSysMenu)
		{
		m_pSysMenu->DestroyMenu();
		delete m_pSysMenu;
		}

    if (m_pTitleBar)
		{
		m_pTitleBar->DestroyWindow();
		delete m_pTitleBar;
		}
	// we have to remove ourselves from the rollup-list
	RemoveFromRUList();

	DestroyWindow();
	}

void COXRollup::RemoveFromRUList()
	{
	ASSERT_VALID(this);
	POSITION pos = m_RollupList.Find(this, NULL);

	// this is not to be expected an error (maybe you don�t want this rollup to arrange, so
	// you called this function before)
	if (pos != NULL)
		m_RollupList.RemoveAt(pos);
	}

void COXRollup::DoDataExchange(CDataExchange* pDX)
	{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(COXRollup)
	// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP  
	}

BOOL COXRollup::IsRolling()
	{
	return m_bRolling;
	}

BEGIN_MESSAGE_MAP(COXRollup, CDialog)
	//{{AFX_MSG_MAP(COXRollup)
	ON_COMMAND(IDM_OX_RU_ROLLUP, OnClickedRoll)
	ON_COMMAND(IDM_OX_RU_CLOSE, OnCloseRollup)
	ON_MESSAGE(WM_LMSUROLLUP,OnRollMessage)
	ON_COMMAND(IDM_OX_RU_ABOUT, OnRollUpAbout)
	ON_WM_SIZE()
	ON_WM_ACTIVATE()   
	ON_WM_TIMER()
	ON_WM_CREATE()
	ON_COMMAND(IDM_OX_RU_ARRANGE, Arrange)
	ON_COMMAND(IDM_OX_RU_ARRANGEALL, ArrangeAll)
	ON_COMMAND(IDM_OX_RU_ROLLDOWN, OnClickedRoll)
	ON_WM_DESTROY()
	ON_WM_NCPAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COXRollup message handlers

void COXRollup::OnNcPaint()
	{
	Default();

	if (!m_bRolledUp && m_bResizingFrame)
		{
		CWindowDC dc(this);
		COLORREF FrameColor = ::GetSysColor(COLOR_WINDOWFRAME);
		CPen FramePen(PS_SOLID, 1, FrameColor);
		CPen* pOldPen = dc.SelectObject(&FramePen);

		CRect WndRect;
		GetWindowRect(WndRect);
		dc.MoveTo (0, 0);
		dc.LineTo (WndRect.Width() - 1, 0);
		dc.LineTo (WndRect.Width() - 1, WndRect.Height() - 1);
		dc.LineTo (0, WndRect.Height() - 1);
		dc.LineTo (0, 0);

		dc.SelectObject(pOldPen);
		}
	}

void COXRollup::OnClickedRoll()
	{
	// don�t care about it if I�m no window
	if (GetSafeHwnd() == NULL)
		return;
	
	if (m_bRolledUp)	// currently rolled up, do downrolling
		{
//====================================================================================
//  commented out (behaviour dependent on own needs)
//		UnArrange();	// get out of arranging (false heights otherwise)
//====================================================================================
		CRect fullRect;
		GetWindowRect(&fullRect);
		int	capHeight = fullRect.Height();
		
		if (m_bResizingFrame)
			{
			// memorize new width if border resizable
			m_xWidth = fullRect.Width();
			} 
		
		int decrement = m_yHeight - capHeight;
		decrement /= m_nScrollSteps;
		
		m_SCROLL_HELP.decrement	= decrement;
		m_SCROLL_HELP.width		= m_xWidth;
		m_SCROLL_HELP.height		= m_yHeight;
		m_SCROLL_HELP.capHeight	= capHeight;
		m_SCROLL_HELP.steps		= m_nScrollSteps;
		m_SCROLL_HELP.curstep		= 1;
		m_SCROLL_HELP.direction	= SCROLL_DOWN;
		if (SetTimer(m_myTimerID, DELAY_TIME,NULL) == 0)
			{
			CString sMessage;
			VERIFY(sMessage.LoadString(IDS_OX_ROLLUPCOULDNTALLOCTIMER));//"Could not alloc timer!"
			AfxMessageBox(sMessage);
			}
		m_bRolling = TRUE;
		}
	else	// roll it up again
		{
		// now roll it up
		if (m_bResizingFrame || m_xWidth == -1)
			{
			CRect fullRect;
			GetWindowRect(&fullRect);
			m_xWidth = fullRect.Width();
			m_yHeight = fullRect.Height();
			}
		
		CRect roll2;
		m_pTitleBar->GetClientRect(&roll2);
		
		int nFrameSize = 2 * ::GetSystemMetrics(SM_CYBORDER);
		int decrement = m_yHeight - roll2.Height() - nFrameSize +
			(m_bResizingFrame ? 2 * ::GetSystemMetrics(SM_CYDLGFRAME) : 0);
		
		decrement /= m_nScrollSteps;
		
		m_SCROLL_HELP.decrement	= decrement;
		m_SCROLL_HELP.width		= m_xWidth;
		m_SCROLL_HELP.height		= m_yHeight;
		m_SCROLL_HELP.capHeight	= roll2.Height() + nFrameSize;
		m_SCROLL_HELP.steps		= m_nScrollSteps;
		m_SCROLL_HELP.curstep		= 1;
		m_SCROLL_HELP.direction	= SCROLL_UP;
		if (SetTimer(m_myTimerID, DELAY_TIME,NULL) == 0)
			{
			CString sMessage;
			VERIFY(sMessage.LoadString(IDS_OX_ROLLUPCOULDNTALLOCTIMER));//"Could not alloc timer!"
			AfxMessageBox(sMessage);
			}
		m_bRolling = TRUE;
		}

	m_bRolledUp = !m_bRolledUp;

	// reflect the changes
	m_pTitleBar->SetRollupState(m_bRolledUp ? SCROLL_DOWN : SCROLL_UP);
	Invalidate();
	}

void COXRollup::OnCloseRollup()
	{
	// called either from titlebar or from OnCloseRollup
	// override if you want to do something special in here (delete this, anything like that)
	ShowWindow(SW_HIDE);	// first we hide
	UnArrange();			// second get out of arrange orderings
	
	ReleaseRecipient(CWnd::FromHandle(m_hWndMR));	// release MR to send to parent
	Send2MR(IDCANCEL);
	}

void COXRollup::OnProcessSysMenu()
	{
	// dim the roll up and down commands via the boolean flag
	CMenu *pSysmenu = GetSysMenu();
	pSysmenu->EnableMenuItem(IDM_OX_RU_ROLLUP,
		MF_BYCOMMAND|(m_bRolledUp ? MF_DISABLED|MF_GRAYED : MF_ENABLED));
	pSysmenu->EnableMenuItem(IDM_OX_RU_ROLLDOWN,
		MF_BYCOMMAND|(m_bRolledUp ? MF_ENABLED : MF_DISABLED|MF_GRAYED));
	pSysmenu->EnableMenuItem(IDM_OX_RU_ARRANGE,
		MF_BYCOMMAND|(IsArranged() ? MF_DISABLED|MF_GRAYED : MF_ENABLED));
	
	// set the position of the system menu
	CRect rect;
	m_pTitleBar->GetWindowRect(&rect);
	pSysmenu->TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTALIGN, rect.left, rect.bottom, this, NULL);
	}

BOOL COXRollup::CreateRollUp(CWnd* pParent, WORD nID, int nIDCaption)
{
	CString sCaption;
	VERIFY(sCaption.LoadString(nIDCaption));
	return CreateRollUp(pParent, nID, sCaption);
}

BOOL COXRollup::CreateRollUp(CWnd* pParent, WORD nID, LPCTSTR lpszCaption)
{
	ASSERT(pParent!=NULL && ::IsWindow(pParent->GetSafeHwnd()));
	ASSERT(lpszCaption!=NULL);

	BOOL bAlreadyCreated=::IsWindow(GetSafeHwnd());
	if(bAlreadyCreated)
	{
		DestroyWindow();
	}

	ASSERT(nID!=0);
	// set our roll up ID used later when dispatching messages
	m_nRollup=nID;

	m_sCaption=lpszCaption;

	// set up the window which is responsible for handling the close msg
	m_hWndDestroyRC = pParent->GetSafeHwnd();

	// register ourselves ( the parent ) as owner of the message dispatch
	SetRecipient(pParent);

	// now create us!
	m_bRolledUp = FALSE;	// full size
	if(!CDialog::Create(m_nTemplateID, pParent))
		return FALSE;
	
	ASSERT(::IsWindow(m_hWnd));
	DetermineFrameStyle();
	
	LPCTSTR lptstrBitmap=GetTitleBarBitmap();
	ASSERT(lptstrBitmap!=NULL);
	VERIFY(m_pTitleBar->LoadBitmap(lptstrBitmap));
	
	return TRUE;
}

// find our responsible window for acknowledging our messages
//
HWND COXRollup::GetCurMsgRecipient()
	{
	// if nobody is there except our parent..
	return m_hWndMR != NULL ? m_hWndMR : m_hWndDestroyRC;
	}

// SendMessage like
//
LRESULT COXRollup::Send2MR(WORD msg)
	{
	// we can�t send a message to a parent if we are no window!
	ASSERT(GetSafeHwnd() != NULL);
	
	HWND hWnd = GetCurMsgRecipient();

	// now route the message to the one who feels responsible	
	return ::SendMessage(hWnd, WM_LMSUROLLUP, (WPARAM)GetSafeHwnd(), MAKELPARAM(msg, m_nRollup));
	}

//
// "message posting" implemented; intended use is simple notification
// like "we are rolling up now"
//
BOOL COXRollup::Post2MR(WORD msg)
	{
	// we can�t send a message to a parent if we are no window!
	ASSERT(GetSafeHwnd() != NULL);
	
	HWND hWnd = GetCurMsgRecipient();

	// now route the message to the one who feels responsible	
	return ::PostMessage(hWnd, WM_LMSUROLLUP, (WPARAM)GetSafeHwnd(), MAKELPARAM(msg, m_nRollup));
	}

HWND COXRollup::SetRecipient(CWnd* pWnd)
	{
	ASSERT(pWnd != NULL && ::IsWindow(pWnd->GetSafeHwnd()));
	
	// store old value for return
	HWND hOld = m_hWndMR;
	// set recipient
	m_hWndMR = pWnd->GetSafeHwnd();

	TRACE1("[RU]New recipient�s HWND : %ld\n", m_hWndMR);
	return hOld;
	} 

void COXRollup::ReleaseRecipient(const CWnd* pRCRequesting, BOOL bCallNotifyFunction)
	{
	// do this only when he is the current owner of the message dispatch system
	if (IsOwner(pRCRequesting)) 
		{
		TRACE1("[RU]Released the owner of the mds. Handle : %ld\n", m_hWndMR);
		
		// if he chose to do some cleanup, do it
		if (bCallNotifyFunction)
			OnRecipientRelease();
		
		m_hWndMR = NULL;
		}
	// else do nothing (somebody else has registered as current user
	}

// Intent: Parent can inform us to roll up or down
//
LRESULT COXRollup::OnRollMessage(WPARAM /* wParam */, LPARAM lParam)
	{
	if (HIWORD(lParam) == m_nRollup)
		{
		switch (LOWORD(lParam))
			{
			case ID_ROLLDOWN:
				( m_bRolledUp ? OnClickedRoll() : NULL);
				break;
			case ID_ROLLUP:
				( m_bRolledUp ? NULL : OnClickedRoll());
				break;
			}
		}

	return 0L;
	}

// Intent: Display About information 
//
void COXRollup::OnRollUpAbout()
	{
	// just a very simple about box
	AfxMessageBox(IDS_OX_RU_ABOUT, MB_OK | MB_ICONINFORMATION);
	}

// Intent: don�t allow wrong resources the class doesn�t allow
//
void  COXRollup::DetermineFrameStyle()
	{
	long style = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
#ifdef _DEBUG
	if (style & DS_MODALFRAME)
		{
		TRACE0("Create a rollup with DS_MODALFRAME? Uh,no!\n");
		ASSERT(FALSE);
		} 
	
	if (style & WS_CHILD)
		{
		TRACE0("Create a rollup with WS_CHILD property? Uh,no!\n");
		ASSERT(FALSE);
		}
#endif 
	
	if (style & WS_BORDER)
		m_bResizingFrame = FALSE;
	if (style & WS_THICKFRAME)
		m_bResizingFrame = TRUE;
	}

void COXRollup::OnSize(UINT nType, int cx, int cy)
	{
	CDialog::OnSize(nType, cx, cy);
	// if no resizing style and I don�t exist
	if ((!m_bResizingFrame) || (GetSafeHwnd() == NULL))
		return;
	
	CRect crCaption, crClient;
	GetClientRect(&crClient);
	
	// if dialog (Titlebar) doesn�t exist, skip sizing
	// this will happen at the first call in this routine
	if((m_pTitleBar == NULL) || (m_pTitleBar->GetSafeHwnd() == NULL))
		return;

	// if its allowed, now I will resize
	m_pTitleBar->GetClientRect(&crCaption);
    m_pTitleBar->MoveWindow(0, 0, crClient.Width(), crCaption.Height());
	}

void COXRollup::OnActivate(UINT nState, CWnd* pOther, BOOL bMinimized)
{
	CDialog::OnActivate(nState,pOther,bMinimized);

	// now draw the caption bars
	if((WA_ACTIVE == nState) || (WA_CLICKACTIVE == nState))
	{
		DrawCaption(COLOR_ACTIVECAPTION);
	}

	if(WA_INACTIVE==nState)
	{
		DrawCaption(COLOR_INACTIVECAPTION);
	}
}


void COXRollup::DrawCaption(int nDisplayElement)
	{
	// activation automatically draws menu bar
	m_pTitleBar->SetActivation(nDisplayElement);
	}

// v9.3 - update 03 - 64-bit - using OXTPARAM here - see UTB64Bit.h
void COXRollup::OnTimer(OXTPARAM nIDEvent)
	{
	// this is not my timer event...
	if ((m_myTimerID)!= nIDEvent)
		return;

	if (SCROLL_DOWN == m_SCROLL_HELP.direction)
		{
		if (m_SCROLL_HELP.curstep != m_SCROLL_HELP.steps)
			{
			SetWindowPos(NULL, 0, 0, m_SCROLL_HELP.width,
				m_SCROLL_HELP.capHeight + m_SCROLL_HELP.decrement * m_SCROLL_HELP.curstep,
				SWP_NOMOVE | SWP_NOZORDER);
			m_SCROLL_HELP.curstep++;
			}
		else
			{
			SetWindowPos(NULL, 0, 0, m_SCROLL_HELP.width, m_SCROLL_HELP.height,
				SWP_NOMOVE | SWP_NOZORDER);	

			if (m_bResizingFrame)
				{
				long style = ::GetWindowLongPtr(m_hWnd,GWL_STYLE);
				style |= WS_THICKFRAME;
				style &= ~WS_BORDER;
				::SetWindowLongPtr(m_hWnd, GWL_STYLE, style); 

				// Now make Windows redraw the window.
				SetWindowPos(NULL, 0, 0, 0, 0,
							 SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED);
				}

			// kill the timer
			KillTimer(m_myTimerID);
			m_bRolling = FALSE;
			}
		} // end scroll down
	else if (SCROLL_UP == m_SCROLL_HELP.direction)
		{	
		if (m_SCROLL_HELP.curstep != m_SCROLL_HELP.steps)
			{
			SetWindowPos(NULL, 0, 0, m_SCROLL_HELP.width,
				m_SCROLL_HELP.height - m_SCROLL_HELP.decrement * m_SCROLL_HELP.curstep,
				SWP_NOMOVE | SWP_NOZORDER);
			m_SCROLL_HELP.curstep++;			
			}
		else
			{
			// last final positioning
			SetWindowPos(NULL, 0, 0, m_SCROLL_HELP.width, m_SCROLL_HELP.capHeight,
				SWP_NOMOVE | SWP_NOZORDER);			
			
			// set back to thinframe
			if (m_bResizingFrame)
				{
				long style = ::GetWindowLongPtr(m_hWnd,GWL_STYLE);
				style &= ~WS_THICKFRAME;
				style |= WS_BORDER;
				::SetWindowLongPtr(m_hWnd,GWL_STYLE,style);

				// Now make Windows redraw the window.
				SetWindowPos(NULL, 0, 0, 0, 0,
					 SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED);
				}

			KillTimer(m_myTimerID);
			m_bRolling = FALSE;
			}
		} // end scroll up
	}

// Intent: Works like COleServerDoc::GetEmbeddedItem
//		   One time construction per menu needed	
CMenu* COXRollup::GetSysMenu()
	{
	if (NULL == m_pSysMenu)
		{
		m_pSysMenu = OnGetSysMenu();
		}

	ASSERT_VALID(m_pSysMenu);	// this check is for your override of OnGet...
	return m_pSysMenu;
	}

// Intent: Works like COleServerDoc::OnGetEmbeddedItem
//		   Constructs a menu once to be used further
CMenu* COXRollup::OnGetSysMenu()
	{
	// this is our base implementation; you can override it if you want to
	CMenu *pSysMenu = new CMenu();
	VERIFY(pSysMenu->CreatePopupMenu());

	// add all menu items; for strings see string table in OXRollup.rc
	CString sMenuText;
	sMenuText.LoadString(IDS_OX_RUM_ROLLUP);
	pSysMenu->AppendMenu(MF_STRING | MF_ENABLED, IDM_OX_RU_ROLLUP, sMenuText);
	sMenuText.LoadString(IDS_OX_RUM_ROLLDOWN);
	pSysMenu->AppendMenu(MF_STRING | MF_ENABLED, IDM_OX_RU_ROLLDOWN, sMenuText);
	pSysMenu->AppendMenu(MF_SEPARATOR);
	sMenuText.LoadString(IDS_OX_RUM_ARRANGE);
	pSysMenu->AppendMenu(MF_STRING | MF_ENABLED, IDM_OX_RU_ARRANGE, sMenuText);
	sMenuText.LoadString(IDS_OX_RUM_ARRANGEALL);
	pSysMenu->AppendMenu(MF_STRING | MF_ENABLED, IDM_OX_RU_ARRANGEALL, sMenuText);
	pSysMenu->AppendMenu(MF_SEPARATOR);
	sMenuText.LoadString(IDS_OX_RUM_ABOUT);
	pSysMenu->AppendMenu(MF_STRING | MF_ENABLED, IDM_OX_RU_ABOUT, sMenuText);
	sMenuText.LoadString(IDS_OX_RUM_CLOSE);
	pSysMenu->AppendMenu(MF_STRING | MF_ENABLED, IDM_OX_RU_CLOSE, sMenuText);
	
	ASSERT_VALID(pSysMenu);
	return pSysMenu;
	}

int COXRollup::OnCreate(LPCREATESTRUCT lpCreateStruct) 
	{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// this happens if: called CreateRollUp, closed and 
	// reopened via CreateRollUp
	if (m_pTitleBar != NULL)
		{
		ASSERT(m_pTitleBar->GetSafeHwnd() == NULL);
		}
	else
		{
		if ((m_pTitleBar = OnGetTitleBar()) == NULL)
			return -1;
		}
	// you have to derive from COXTitleBar!!!
	ASSERT_VALID(m_pTitleBar);
	ASSERT(m_pTitleBar->IsKindOf(RUNTIME_CLASS(COXTitleBar)));
	
	CRect rcTBar;
	GetTitleBarRect(rcTBar);
	if (! m_pTitleBar->Create(m_sCaption, rcTBar, this, IDC_CAPTION))
		return -1;
	
	return 0;
	}

void COXRollup::OnDestroy() 
	{
	CDialog::OnDestroy();
	}

COXTitleBar* COXRollup::OnGetTitleBar()
	{
	ASSERT_VALID(this);
	
	// here your override should create an own window
	COXTitleBar* pTitleBar = new COXTitleBar();
	return pTitleBar;
	}

void COXRollup::GetTitleBarRect(CRect& rcTBarRect)
	{
	GetClientRect(rcTBarRect);
	rcTBarRect.bottom = TBAR_HEIGHT;
	}


/////////////////////////////////////////////////////////////////////////////
// COXRollup::Arrange - arrange this rollup

void COXRollup::Arrange()
	{
	ASSERT_VALID(this);
	if (IsArranged()) return;
	
	CWnd* pMainWnd = AfxGetMainWnd();
	ASSERT((pMainWnd != NULL) && ::IsWindow(pMainWnd->m_hWnd));		// don�t care about OLE
	if (!pMainWnd->IsWindowEnabled() && pMainWnd->IsIconic())
		return;
	
	InternalRollUp();
	
	COXRollup* pRollup = NULL;
	if (!m_ArrangedRollups.IsEmpty())
		pRollup = (COXRollup*)m_ArrangedRollups.GetTail();	// get last rolled up element
	
	// we have got a rollup (or not...)
	CPoint topLeft(0,0);
	if (pRollup == NULL)
		{
		// we found no college that was rolled up, so we arrange to the left of the screen
		CRect rcLeftOver;
		CWnd* pWndLeftOverPane = pMainWnd->GetDlgItem(AFX_IDW_PANE_FIRST);
		ASSERT(pWndLeftOverPane != NULL);
		pWndLeftOverPane->GetWindowRect(&rcLeftOver);
		topLeft = CPoint(rcLeftOver.left, rcLeftOver.top);
		}
	else
		{
		ASSERT(pRollup != this);		// can�t happen, otherwise we would have been arranged
		ASSERT(pRollup->IsRolledUp());	// must be up if arranged
		CRect rcLastRollup;
		pRollup->GetWindowRect(&rcLastRollup);
		topLeft = CPoint(rcLastRollup.left, rcLastRollup.bottom - 1);
		}
	
	SetWindowPos(NULL, topLeft.x, topLeft.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
	m_ArrangedRollups.AddTail(this);
	m_bIsArranged = TRUE;			
	}

/////////////////////////////////////////////////////////////////////////////
// COXRollup::ArrangeAll - all open rollups are arranged

void COXRollup::ArrangeAll()
	{
	ASSERT_VALID(this);
	
	CWnd* pMainWnd = AfxGetMainWnd();
	ASSERT((pMainWnd != NULL) && ::IsWindow(pMainWnd->m_hWnd));		// don�t care about OLE
	if (!pMainWnd->IsWindowEnabled() && pMainWnd->IsIconic())
		return;
	
	// set out new top point; because we have to move to first position
	CWnd* pWndLeftOverPane = pMainWnd->GetDlgItem(AFX_IDW_PANE_FIRST);
	ASSERT(pWndLeftOverPane != NULL);
	
	CRect rcWndNewPos;
	pWndLeftOverPane->GetWindowRect(&rcWndNewPos);
	int nLeft = rcWndNewPos.left;
	int nNewTop = rcWndNewPos.top;
	
	POSITION pos = m_ArrangedRollups.GetHeadPosition();
	COXRollup* pRoll = NULL;
	while (pos != NULL)
		{
		pRoll = (COXRollup*)m_ArrangedRollups.GetNext(pos);
		pRoll->GetWindowRect(&rcWndNewPos);
		pRoll->SetWindowPos(NULL, nLeft, nNewTop, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
		nNewTop += rcWndNewPos.Height() - 1;
		}
	// now add the ones that haven�t been rolled up before
	POSITION posNotArranged = m_RollupList.GetHeadPosition();
	while (posNotArranged != NULL)
		{
		pRoll = (COXRollup*)m_ArrangedRollups.GetNext(posNotArranged);
		if (m_ArrangedRollups.Find(pRoll, NULL) == NULL)
			{
			if ((::IsWindow(pRoll->m_hWnd)) && pRoll->IsWindowVisible())
				{
				pRoll->InternalRollUp();
				pRoll->SetArrangeFlagTrue();
				pRoll->GetWindowRect(&rcWndNewPos);
				pRoll->SetWindowPos(NULL, nLeft, nNewTop, 0, 0,SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
				nNewTop += rcWndNewPos.Height() - 1;
				m_ArrangedRollups.AddTail(pRoll);	// add it to list
				}
			}
		}
	}

/////////////////////////////////////////////////////////////////////////////
// COXRollup::ReArrangeArranged - call this function if your application moves

void COXRollup::ReArrangeArranged()
	{
	POSITION pos = m_ArrangedRollups.GetHeadPosition();
	if (pos == NULL)
		return;	// this function has to be as fast as possible
	
	CWnd* pMainWnd = AfxGetMainWnd();
	ASSERT((pMainWnd != NULL) && ::IsWindow(pMainWnd->m_hWnd));		// don�t care about OLE
	if (!pMainWnd->IsWindowEnabled() && pMainWnd->IsIconic())
		return;
	
	// set out new top point; because we have to move to first position
	CWnd* pWndLeftOverPane = pMainWnd->GetDlgItem(AFX_IDW_PANE_FIRST);
	ASSERT(pWndLeftOverPane != NULL);
	
	CRect rcWndNewPos;
	pWndLeftOverPane->GetWindowRect(&rcWndNewPos);
	int nLeft = rcWndNewPos.left;
	int nNewTop = rcWndNewPos.top;
	
	COXRollup* pRoll = NULL;
	while (pos != NULL)
		{
		pRoll = (COXRollup*)m_ArrangedRollups.GetNext(pos);
		pRoll->GetWindowRect(&rcWndNewPos);
		pRoll->SetWindowPos(NULL, nLeft, nNewTop, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
		nNewTop += rcWndNewPos.Height() - 1;
		}
	}

/////////////////////////////////////////////////////////////////////////////
// COXRollup::InternalRollUp - roll up quickly

void COXRollup::InternalRollUp()
	{
	ASSERT_VALID(this);
	ASSERT(::IsWindow(m_hWnd));
	ASSERT(m_pTitleBar != NULL);
	
	if (m_bRolledUp)
		return;	// we are up, get out
	
	CRect rcWnd;
	if (m_bResizingFrame || m_xWidth == -1)
		{
		GetWindowRect(&rcWnd);
		m_xWidth = rcWnd.Width();
		m_yHeight = rcWnd.Height();
		// set back to thickframe
		if (m_bResizingFrame)
			{
			long style = ::GetWindowLongPtr(m_hWnd,GWL_STYLE);
			style &= ~WS_THICKFRAME;
			style |= WS_BORDER;
			::SetWindowLongPtr(m_hWnd,GWL_STYLE,style);
			}
		}
	
	m_pTitleBar->GetClientRect(&rcWnd);
	int nFrameSize = 2 * ::GetSystemMetrics(SM_CYBORDER);
	
	SetWindowPos(NULL, 0, 0, m_xWidth, rcWnd.Height() + nFrameSize,	SWP_NOMOVE | SWP_NOZORDER);			
	m_bRolledUp = TRUE;
	m_pTitleBar->SetRollupState(SCROLL_DOWN);
	Invalidate();
	}

void COXRollup::PostNcDestroy()
	{
	// why this unarrange here and not in the destructor?
	// You would get a GP-fault when referencing the main wnd if you have arranged rollups
	// at application termination time, so this is the last valid time to do it safely
	UnArrange();
	CDialog::PostNcDestroy();
	}

void COXRollup::UnArrange()
	{
	ASSERT_VALID(this);
	m_bIsArranged = FALSE;

	// we have to find ourselves in the list
	POSITION pos = m_ArrangedRollups.Find(this, NULL);
	if (pos != NULL )
		{
		// first: all other rollups (arranged ones) move up one step
		COXRollup* pNext = (COXRollup*)m_ArrangedRollups.GetAt(pos);
		POSITION posCur = pos;
		CRect rcWndNewPos;
		int nLeft, nNewTop;
		
		if (m_ArrangedRollups.GetHeadPosition() == posCur)
			{
			// set out new top point; because we have to move to first position
			CWnd* pWndLeftOverPane = AfxGetMainWnd()->GetDlgItem(AFX_IDW_PANE_FIRST);
			ASSERT(pWndLeftOverPane != NULL);
			pWndLeftOverPane->GetWindowRect(&rcWndNewPos);
			nLeft = rcWndNewPos.left;
			nNewTop = rcWndNewPos.top;
			}
		else											   
			{
			POSITION posPrev = posCur;
			m_ArrangedRollups.GetPrev(posPrev);	// we skip this element
			COXRollup* pPrev = (COXRollup*)m_ArrangedRollups.GetPrev(posPrev);
			pPrev->GetWindowRect(&rcWndNewPos);
			nLeft = rcWndNewPos.left;
			nNewTop = rcWndNewPos.bottom - 1;
			}
		
		m_ArrangedRollups.GetNext(posCur);	// we skip this element
		while (posCur != NULL)	// only if we are not last element
			{
			pNext = (COXRollup*)m_ArrangedRollups.GetNext(posCur);
			pNext->GetWindowRect(&rcWndNewPos);
			pNext->SetWindowPos(NULL, nLeft, nNewTop, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
			nNewTop += rcWndNewPos.Height() - 1;
			}
		
		m_ArrangedRollups.RemoveAt(pos);		// now we delete the element from the list
		}
	}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions