2025-11-27 16:46:48 +09:00

891 lines
24 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==========================================================================
// 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);
}
void COXRollup::OnTimer(UINT 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
}
}