// ========================================================================== // 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 #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 } }