// =================================================================================== // Class Implementation : COXSizableMiniDockFrameWnd // =================================================================================== // Header file : OXSzMiniDockFrmWnd.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. // Some portions Copyright (C)1994-5 Micro Focus Inc, 2465 East Bayshore Rd, Palo Alto, CA 94303. // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #ifndef __OXMFCIMPL_H__ #if _MFC_VER >= 0x0700 #if _MFC_VER >= 1400 #include #endif #include <..\src\mfc\afximpl.h> #else #include <..\src\afximpl.h> #endif #define __OXMFCIMPL_H__ #endif #include "OXSzMiniDockFrmWnd.h" #include "OXSizeCtrlBar.h" #include "OXSizeDockBar.h" #include "OXFrameWndDock.h" #include "OXSkins.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(COXSizableMiniDockFrameWnd, CMiniDockFrameWnd) #define new DEBUG_NEW // Helper function: used below void AdjustForBorders(CRect& rect, DWORD dwStyle); ///////////////////////////////////////////////////////////////////////////// // Definition of static members // Data members ------------------------------------------------------------- // protected: // private: // Member functions --------------------------------------------------------- // public: BEGIN_MESSAGE_MAP(COXSizableMiniDockFrameWnd, CMiniDockFrameWnd) //{{AFX_MSG_MAP(COXSizableMiniDockFrameWnd) ON_WM_CREATE() ON_WM_SIZE() ON_WM_CLOSE() ON_WM_NCLBUTTONDOWN() ON_WM_NCHITTEST() ON_WM_MOUSEACTIVATE() ON_WM_NCACTIVATE() ON_WM_PARENTNOTIFY() ON_WM_SYSCOMMAND() ON_WM_INITMENUPOPUP() ON_WM_ACTIVATE() ON_WM_NCPAINT() ON_WM_SETCURSOR() ON_WM_NCLBUTTONUP() ON_WM_DESTROY() ON_WM_NCRBUTTONDOWN() ON_WM_WINDOWPOSCHANGED() ON_WM_NCMOUSEMOVE() //}}AFX_MSG_MAP // Global help commands END_MESSAGE_MAP() HHOOK COXSizableMiniDockFrameWnd::m_hMouseHook = NULL; HWND COXSizableMiniDockFrameWnd::m_hwndPrevMouseMoveWnd = NULL; COXSizableMiniDockFrameWnd::COXSizableMiniDockFrameWnd() : m_pMiniFrameSkin(NULL) { } COXSizableMiniDockFrameWnd::~COXSizableMiniDockFrameWnd() { if ( m_pMiniFrameSkin != NULL ) delete m_pMiniFrameSkin; } int COXSizableMiniDockFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CMiniDockFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; m_nContainedBarType = Unknown; m_bBeingDestroyed=FALSE; // Hook the mouse if (m_hMouseHook == NULL) m_hMouseHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, 0, AfxGetApp()->m_nThreadID); return 1; } void COXSizableMiniDockFrameWnd::OnSysCommand(UINT nID, LPARAM lParam) { // Call DrawCaption to prevent the original caption from drawing GetMiniFrameSkin()->DrawCaption(this); // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1 // in the array CControlBar* pBar=((COXSizeDockBar *)&m_wndDockBar)->GetFirstControlBar(); if(pBar!=NULL) { ASSERT_KINDOF(CControlBar, pBar); ASSERT(pBar->m_pDockContext != NULL); if(pBar->IsKindOf(RUNTIME_CLASS(COXSizeViewBar))) { COXMDIChildWndSizeDock* pMDIChild=((COXSizeViewBar*)pBar)->m_pChildWnd; if(::IsWindow(pMDIChild->m_hWnd)) { if(nID==pMDIChild->m_nDockMessageID) { pMDIChild->OnMakeItDockable(); return; } } } } CMiniDockFrameWnd::OnSysCommand(nID, lParam); } // respond to the miniframe resizing. If we've got a sizeable control // bar in the window, then we set it's size. Need to adjust for the // window borders. The window will then get repositioned by a ReCalcLayout() void COXSizableMiniDockFrameWnd::OnSize(UINT /* nType */, int cx, int cy) { if (cx == 0 && cy == 0) return; // We don't support CBRS_FLOAT_MULTI if ((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0) { // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1 // in the array COXSizeControlBar* pBar = ((COXSizeDockBar*)(&m_wndDockBar))->GetFirstControlBar(); // ignore size request if not visible.... if (pBar != NULL && COXSizeDockBar::IsSizeable(pBar) && pBar->IsVisible()) { CRect rect(0, 0, cx, cy); AdjustForBorders(rect, pBar->m_dwStyle); pBar->m_FloatSize.cx = rect.Width(); pBar->m_FloatSize.cy = rect.Height(); } } RecalcLayout(); } BOOL COXSizableMiniDockFrameWnd::PreCreateWindow(CREATESTRUCT &cs) { // modify frame style so it is fully sizeable - we will modify this again later // if we discover that we have a standard MFC control bar inside the frame // turn on thick frame styles. MFS_THICKFRAME is what's expected, but also need WS_THICKFRAME, // as NT expects this to be able to do the resizing. cs.style |= MFS_THICKFRAME | WS_THICKFRAME; cs.style &= ~( MFS_MOVEFRAME | MFS_4THICKFRAME ); return CMiniDockFrameWnd::PreCreateWindow(cs); } // over-ridden so we can find out the type of the bar in this window #if _MSC_VER >= 1400 LRESULT COXSizableMiniDockFrameWnd::OnNcHitTest(CPoint point) #else UINT COXSizableMiniDockFrameWnd::OnNcHitTest(CPoint point) #endif { return CMiniDockFrameWnd::OnNcHitTest(point); } // if we've got a COXSizeControlBar inside this frame, and it's a resize, // then we can use the default window's sizing. void COXSizableMiniDockFrameWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) { enum ContainedBarType Type = GetContainedBarType(); if (Type == MRCSizeBar) { if (nHitTest >= HTSIZEFIRST && nHitTest <= HTSIZELAST) { // special activation for floating toolbars ActivateTopParent(); CMiniFrameWnd::OnNcLButtonDown(nHitTest, point); return; } else if (nHitTest == HTSYSMENU) { // do the system menu - ie give move,size,hide, etc options as would Win95. #if _MFC_VER < 0x0700 InvertSysMenu(); #endif CPoint pt(0,0); ClientToScreen(&pt); CRect rcSysIcon; GetWindowRect(&rcSysIcon); rcSysIcon.right = rcSysIcon.left + 12; // NB:hard-coded value for width of system icon rcSysIcon.bottom = pt.y; CMenu* pSysMenu = GetSystemMenu(FALSE); int nCmd = pSysMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RETURNCMD, pt.x, pt.y, this, & rcSysIcon); #if _MFC_VER < 0x0700 InvertSysMenu(); #endif if (nCmd != 0) { SendMessage(WM_SYSCOMMAND, nCmd, 0); } return; } } if (nHitTest == HTCLOSE) { if (!GetMiniFrameSkin()->DrawCaptionButtons(this)) CMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); else { // If the close button is hidden emulate a caption click if (GetSystemMenu(FALSE)->GetMenuItemCount() == 0) CMiniDockFrameWnd::OnNcLButtonDown(HTCAPTION, point); } } else { if (nHitTest == HTCAPTION) { // special activation for floating toolbars ActivateTopParent(); // initiate toolbar drag for non-CBRS_FLOAT_MULTI toolbars if ((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0) { // Get a pointer to the control bar int nPos = 1; CControlBar* pBar = NULL; while (pBar == NULL && nPos < m_wndDockBar.m_arrBars.GetSize()) pBar = (CControlBar*) m_wndDockBar.m_arrBars[nPos++]; if (AfxGetMainWnd()->SendMessage(WM_QUERYSNAPPING)) { // Snaping is enabled // Handle COXCoolToolBar COXCoolToolBar* pToolBar = DYNAMIC_DOWNCAST(COXCoolToolBar, pBar); if (pToolBar) { // We have a toolbar CRect rectThis, rectToolBar; GetWindowRect(rectThis); pToolBar->GetWindowRect(rectToolBar); CPoint ptClient(point); pToolBar->ScreenToClient(&ptClient); ptClient.x += rectToolBar.left - rectThis.left; ptClient.y += rectToolBar.top - rectThis.top; pToolBar->SaveMouseOffset(ptClient); pToolBar->SetCapture(); pToolBar->m_bDragging = true; ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL)); return; } // Handle COXSizeControlBar COXSizeControlBar* pControlBar = DYNAMIC_DOWNCAST(COXSizeControlBar, pBar); if (pControlBar) { // We have a docking window CRect rectThis, rectControlBar; GetWindowRect(rectThis); pControlBar->GetWindowRect(rectControlBar); CPoint ptClient(point); pControlBar->ScreenToClient(&ptClient); ptClient.x += rectControlBar.left - rectThis.left; ptClient.y += rectControlBar.top - rectThis.top; pControlBar->SaveMouseOffset(ptClient); pControlBar->SetCapture(); pControlBar->m_bDragging = true; ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL)); return; } } else // snaping is disabled { CMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); return; } } } else if (nHitTest >= HTSIZEFIRST && nHitTest <= HTSIZELAST) { // special activation for floating toolbars ActivateTopParent(); // Get a pointer to the control bar int nPos = 1; CControlBar* pBar = NULL; while (pBar == NULL && nPos < m_wndDockBar.m_arrBars.GetSize()) pBar = (CControlBar*) m_wndDockBar.m_arrBars[nPos++]; ASSERT(pBar != NULL); ASSERT_KINDOF(CControlBar, pBar); ASSERT(pBar->m_pDockContext != NULL); // CBRS_SIZE_DYNAMIC toolbars cannot have the CBRS_FLOAT_MULTI style ASSERT((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0); pBar->m_pDockContext->StartResize(nHitTest, point); return; } CMiniFrameWnd::OnNcLButtonDown(nHitTest, point); } } int COXSizableMiniDockFrameWnd::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) { // activate this window if necessary // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1 // in the array CControlBar* pBar = ((COXSizeDockBar *)&m_wndDockBar)->GetFirstControlBar(); if(pBar->IsKindOf(RUNTIME_CLASS(COXSizeViewBar))) { pBar->SendMessage(WM_ACTIVATEVIEWBAR,TRUE,ID_SOURCE_MINIDOCK); } enum ContainedBarType Type = GetContainedBarType(); if (Type == MRCSizeBar) { if (nHitTest >= HTSIZEFIRST && nHitTest <= HTSIZELAST) return CMiniFrameWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); } return CMiniDockFrameWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); } // returns the type of the contained bar // Floating frames are created from CFrameWnd::CreateFloatingFrame(), and at this point, // we don't know what type of control bar will eventually be in this frame. This routine // determines the type of control bar, and sets the neccessary styles. Generally this routine gets // called as soon as we do a WM_NCHITTEST on the window - ie before the user can get a chance to // manipulate it with the mouse // // COXSizeControlBar - default style of WS_THICKFRAME is ok (we've overridden the create too) // but we need to ensure "SC_SIZE" is on the menu, otherwise we can't // the default WM_NCLBUTTONDOWN won't generate an SC_SIZE. // // CControlBar, CBRS_SIZE_DYNAMIC // - set MFS_4THICKFRAME (disallow diagonal sizing) // // CControlBar, not CBRS_SIZE_DYNAMIC // - remove WS_THICKFRAME & add MFS_MOVEFRAME (we don't want sizing hit test values) enum COXSizableMiniDockFrameWnd::ContainedBarType COXSizableMiniDockFrameWnd::GetContainedBarType() { if (m_nContainedBarType == Unknown) { m_nContainedBarType = MFCBase; if ((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0) // don't handle this { COXSizeControlBar* pBar = ((COXSizeDockBar*)(&m_wndDockBar))->GetFirstControlBar(); if (pBar != NULL) { if (COXSizeDockBar::IsSizeable(pBar)) { m_nContainedBarType = MRCSizeBar; GetSystemMenu(TRUE); // reset the system menu // delete sys menu items that might be present.... CMenu* pSysMenu = GetSystemMenu(FALSE); if(pSysMenu!=NULL) { pSysMenu->DeleteMenu(SC_MAXIMIZE, MF_BYCOMMAND); pSysMenu->DeleteMenu(SC_MINIMIZE, MF_BYCOMMAND); pSysMenu->DeleteMenu(SC_RESTORE, MF_BYCOMMAND); pSysMenu->DeleteMenu(SC_TASKLIST, MF_BYCOMMAND); // remove anything with ID=0 while (pSysMenu->DeleteMenu(0, MF_BYCOMMAND)); } // if window is meant to close, ensure sysmenu has "Close" on it, not "Hide" // MFC4.0 replaces "Close" with "Hide" // extract close text from ID_FILE_CLOSE after the "\n" for the tooltip prompt if (!(pBar->m_Style & SZBARF_DESTROY_ON_CLOSE)) { CString strHide; if (strHide.LoadString(AFX_IDS_HIDE)) { // modify menu text to be "Hide" instrad of close VERIFY(pSysMenu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND | MF_STRING, SC_CLOSE, strHide)); } } } else { if ((pBar->m_dwStyle & CBRS_SIZE_DYNAMIC)) // dynamic bar - turn on MFS_4THICKFRAME { ModifyStyle(0, MFS_4THICKFRAME); return m_nContainedBarType; } } } } if (m_nContainedBarType == MFCBase) { ModifyStyle(WS_THICKFRAME, MFS_MOVEFRAME); } } // if bar is MFC bar (and not CBRS_SIZE_DYNAMIC, turn on MFS_MOVEFRAME) return m_nContainedBarType; } void COXSizableMiniDockFrameWnd::OnClose() { if(m_bBeingDestroyed) { return; } m_bBeingDestroyed=TRUE; if ((m_wndDockBar.m_dwStyle & CBRS_FLOAT_MULTI) == 0) { CControlBar* pBar = NULL; // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1 // in the array pBar = ((COXSizeDockBar *)&m_wndDockBar)->GetFirstControlBar(); if(pBar!=NULL && pBar->IsKindOf(RUNTIME_CLASS(COXSizeControlBar))) { if(((COXSizeControlBar*)pBar)->m_Style & SZBARF_DESTROY_ON_CLOSE) { // close the Frame Window CFrameWnd::OnClose(); // close the window delete pBar; // now explicitly delete the control bar return; } } ASSERT(pBar != NULL); ASSERT_KINDOF(CControlBar, pBar); ASSERT(pBar->m_pDockContext != NULL); if(pBar->IsKindOf(RUNTIME_CLASS(COXSizeViewBar))) { COXSizeViewBar* pViewBar=(COXSizeViewBar*)pBar; if(::IsWindow(pViewBar->m_hWnd) && !pViewBar->IsBeingDestroyed()) { if(!pViewBar->QueryCloseView()) { // document can't be closed right now -- don't close it m_bBeingDestroyed=FALSE; return; } pViewBar->m_pChildWnd->GetMDIFrame()-> ShowControlBar(pViewBar,FALSE,FALSE); pViewBar->m_pDockContext->ToggleDocking(); pViewBar->m_WrapperWnd.SendMessage(WM_CLOSE); return; } } } // otherwise just hide it. CMiniDockFrameWnd::OnClose(); m_bBeingDestroyed=FALSE; return; } BOOL COXSizableMiniDockFrameWnd::OnNcActivate(BOOL bActive) { return GetMiniFrameSkin()->OnNcActivate(bActive, this); } void COXSizableMiniDockFrameWnd::OnParentNotify(UINT message, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); if(message==WM_LBUTTONDOWN || message==WM_RBUTTONDOWN || message==WM_MBUTTONDOWN) { // activate this window if necessary // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1 // in the array CControlBar* pBar = ((COXSizeDockBar *)&m_wndDockBar)->GetFirstControlBar(); pBar->SendMessage(WM_ACTIVATEVIEWBAR,TRUE,ID_SOURCE_MINIDOCK); } } void COXSizableMiniDockFrameWnd::OnInitMenuPopup(CMenu* pMenu, UINT, BOOL bSysMenu) { AfxCancelModes(m_hWnd); if (bSysMenu) { // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at position 1 // in the array CControlBar* pBar=((COXSizeDockBar *)&m_wndDockBar)->GetFirstControlBar(); if(pBar!=NULL) { ASSERT_KINDOF(CControlBar, pBar); if(pBar->IsKindOf(RUNTIME_CLASS(COXSizeViewBar))) { COXMDIChildWndSizeDock* pMDIChild=((COXSizeViewBar*)pBar)->m_pChildWnd; if(::IsWindow(pMDIChild->m_hWnd)) { if(pMenu->GetMenuState(pMDIChild->m_nDockMessageID, MF_BYCOMMAND)==0xffffffff) { //HACK // pMenu->RemoveMenu(MF_BYPOSITION,2); pMenu->AppendMenu(MF_SEPARATOR); pMenu->AppendMenu(pMDIChild->m_bDockable ? MF_CHECKED : MF_UNCHECKED, pMDIChild->m_nDockMessageID, pMDIChild->m_sDockMenuItem); } } } } } } void COXSizableMiniDockFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CMiniDockFrameWnd::OnActivate(nState, pWndOther, bMinimized); // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at // position 1 in the array CControlBar* pBar=((COXSizeDockBar *)&m_wndDockBar)->GetFirstControlBar(); if(pBar!=NULL) { ASSERT_KINDOF(CControlBar, pBar); ASSERT(pBar->m_pDockContext != NULL); if(pBar->IsKindOf(RUNTIME_CLASS(COXSizeViewBar))) { pBar->SendMessage(WM_ACTIVATEVIEWBAR,nState==WA_INACTIVE ? FALSE : TRUE, ID_SOURCE_MINIDOCK); } } } BOOL COXSizableMiniDockFrameWnd::IsDockingViewBar() { ASSERT_VALID(this); // CMiniDockFrameWnd class assumes if there is only 1 bar, then it's at // position 1 in the array CControlBar* pBar=((COXSizeDockBar *)&m_wndDockBar)->GetFirstControlBar(); if(pBar!=NULL) { ASSERT_KINDOF(CControlBar, pBar); ASSERT(pBar->m_pDockContext != NULL); if(pBar->IsKindOf(RUNTIME_CLASS(COXSizeViewBar))) return TRUE; } return FALSE; } // convert MiniDock size to a client size.. or vice versa. void MiniDockToClient(CRect & rect, BOOL bConvertToClient) { static int nCaptionY = -1; static int nBorderX, nBorderY; // if not set up, create a temporary floating frame to see how big it is. if (nCaptionY == -1) { CFrameWnd* pMainFrame = (CFrameWnd*)AfxGetMainWnd(); CMiniDockFrameWnd* pTmpFloatFrame = pMainFrame->CreateFloatingFrame(0); // calculate frame dragging rectangle CRect rcFloat(0,0,0,0); pTmpFloatFrame->CalcWindowRect(&rcFloat); rcFloat.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2); nCaptionY = - rcFloat.top; nBorderY = rcFloat.bottom; nBorderX = rcFloat.right; pTmpFloatFrame->DestroyWindow(); } if (bConvertToClient) { rect.left += nBorderX; rect.right -= nBorderX; rect.top += nCaptionY; rect.bottom -= nBorderY; } else { rect.left -= nBorderX; rect.right += nBorderX; rect.top -= nCaptionY; rect.bottom += nBorderY; } } // Helper function: used below // adjusts the size, depending on the borders specified by the CControlBar style void AdjustForBorders(CRect& rect, DWORD dwStyle) { if (dwStyle & CBRS_BORDER_LEFT) rect.left -= afxData.cxBorder2; if (dwStyle & CBRS_BORDER_TOP) rect.top -= afxData.cyBorder2; if (dwStyle & CBRS_BORDER_RIGHT) rect.right += afxData.cxBorder2; if (dwStyle & CBRS_BORDER_BOTTOM) rect.bottom += afxData.cyBorder2; } void COXSizableMiniDockFrameWnd::OnNcPaint() { GetMiniFrameSkin()->OnNcPaint(this); } COXMiniFrameSkin* COXSizableMiniDockFrameWnd::GetMiniFrameSkin() { // Check if the app is derived from COXSkinnedApp COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp()); if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL) return pSkinnedApp->GetCurrentSkin()->GetMiniFrameSkin(); else { // Create a classic skin for this class if not created already if (m_pMiniFrameSkin == NULL) m_pMiniFrameSkin = new COXMiniFrameSkinClassic(); return m_pMiniFrameSkin; } } BOOL COXSizableMiniDockFrameWnd::OnSetCursor(CWnd* /*pWnd*/, UINT nHitTest, UINT /*message*/) { // Since the default implementation of CWnd::OnSetCursor(...) draws the close button // in the caption, we need to re-implement its logic here and not draw that button. // Code from CMiniDockFrameWnd::OnSetCursor(...) CFrameWnd* pFrameWnd = GetTopLevelFrame(); ASSERT_VALID(pFrameWnd); if (pFrameWnd->m_bHelpMode) { SetCursor(afxData.hcurHelp); return TRUE; } // End of code from CMiniDockFrameWnd::OnSetCursor(...) // Implementation of the logic of CWnd::OnSetCursor(...) // Get the appropriate cursor HCURSOR hCursor; if (nHitTest == HTBOTTOM || nHitTest == HTTOP) hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZENS); else if (nHitTest == HTBOTTOMLEFT || nHitTest == HTTOPRIGHT) hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZENESW); else if (nHitTest == HTBOTTOMRIGHT || nHitTest == HTTOPLEFT) hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE); else if (nHitTest == HTRIGHT || nHitTest == HTLEFT) hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE); else hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); ::SetCursor(hCursor); // End of implementation of the logic of CWnd::OnSetCursor(...) return TRUE; } void COXSizableMiniDockFrameWnd::OnNcLButtonUp(UINT nHitTest, CPoint point) { // TODO: Add your message handler code here and/or call default if (nHitTest == HTCLOSE && GetSystemMenu(FALSE)->GetMenuItemCount() > 0) { SendMessage(WM_SYSCOMMAND, SC_CLOSE, 0); } else CMiniDockFrameWnd::OnNcLButtonUp(nHitTest, point); } // Update the buttons of the mini frame window when the mouse leaves LRESULT CALLBACK COXSizableMiniDockFrameWnd::MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode < 0) return ::CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); if (nCode == HC_ACTION && (wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE)) { MOUSEHOOKSTRUCT* pMH = (MOUSEHOOKSTRUCT*) lParam; // If the previous message was for COXSizableMiniDockFrameWnd and the current is not // we need to update the caption buttons COXSizableMiniDockFrameWnd* pPrev = DYNAMIC_DOWNCAST(COXSizableMiniDockFrameWnd, CWnd::FromHandlePermanent(m_hwndPrevMouseMoveWnd)); COXSizableMiniDockFrameWnd* pCurrent = DYNAMIC_DOWNCAST(COXSizableMiniDockFrameWnd, CWnd::FromHandlePermanent(pMH->hwnd)); if (pPrev != NULL && pCurrent != pPrev) { // The mouse just left the mini frame window pPrev->GetMiniFrameSkin()->DrawCaptionButtons(pPrev); } m_hwndPrevMouseMoveWnd = pMH->hwnd; } return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam); } void COXSizableMiniDockFrameWnd::OnDestroy() { // Unhook the mouse if (m_hMouseHook) { ::UnhookWindowsHookEx(m_hMouseHook); m_hMouseHook = NULL; } CMiniDockFrameWnd::OnDestroy(); } void COXSizableMiniDockFrameWnd::OnNcRButtonDown(UINT /*nHitTest*/, CPoint point) { // Display the system menu #if _MFC_VER < 0x0700 InvertSysMenu(); #endif CMenu* pSysMenu = GetSystemMenu(FALSE); int nCmd = pSysMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RETURNCMD, point.x, point.y, this); #if _MFC_VER < 0x0700 InvertSysMenu(); #endif if (nCmd != 0) { SendMessage(WM_SYSCOMMAND, nCmd, 0); } return; } void COXSizableMiniDockFrameWnd::OnNcMouseMove(UINT nHitTest, CPoint point) { GetMiniFrameSkin()->DrawCaptionButtons(this); CMiniDockFrameWnd::OnNcMouseMove(nHitTest, point); }