⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atldock.h

📁 这是一本学习 window编程的很好的参考教材
💻 H
📖 第 1 页 / 共 4 页
字号:
#ifndef __ATL_DOCK_H__
#define __ATL_DOCK_H__

/////////////////////////////////////////////////////////////////////////////
// atldock.h - Docking framework for the WTL library
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Thanks to Mike Simon for adding the ability to close a view.
// Copyright (c) 2000-2002 Bjarke Viksoe.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. 
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever. It's free, so don't hassle me about it.
//
// Beware of bugs.
//

#pragma once

#ifndef __cplusplus
   #error ATL requires C++ compilation (use a .cpp suffix)
#endif

#ifndef __ATLAPP_H__
   #error atldock.h requires atlapp.h to be included first
#endif


// Dock positions
#define DOCK_LEFT      0
#define DOCK_TOP       1
#define DOCK_RIGHT     2
#define DOCK_BOTTOM    3
#define DOCK_FLOAT     4
#define DOCK_HIDDEN    5
#define DOCK_LASTKNOWN 6

// Extended dock styles
#define DCK_EX_DESTROYONCLOSE 0x00000001
#define DCK_EX_REMEMBERSIZE   0x00000002

// Control style flags
#define DCK_NOLEFT      1<<DOCK_LEFT
#define DCK_NOTOP       1<<DOCK_TOP
#define DCK_NORIGHT     1<<DOCK_RIGHT
#define DCK_NOBOTTOM    1<<DOCK_BOTTOM
#define DCK_NOSPLITTER  0x00000100L
#define DCK_NOFLOAT     0x00000200L
#define DCK_NOHIDE      0x00000400L

#define ATL_SIMPLE_DOCKVIEW_STYLE \
   (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)

// Docked child command chaining macro
#define CHAIN_DOCK_CHILD_COMMANDS(hwnd) \
   if(uMsg == WM_COMMAND) \
   { \
      if(::IsWindowVisible(hwnd)) \
         ::SendMessage(hwnd, uMsg, wParam, lParam); \
   }

// Docking position helpers
inline bool IsDockedVertically(short Side) { return (Side == DOCK_LEFT) || (Side == DOCK_RIGHT); };
inline bool IsDocked(short Side) { return (Side == DOCK_TOP) || (Side == DOCK_BOTTOM) || (Side == DOCK_LEFT) || (Side == DOCK_RIGHT); };


#define DOCK_INFO_CHILD 0x1000

// Minimum size of docking pane
#define MIN_DOCKPANE_SIZE 28
// Default width/height of docking pane
#define DEFAULT_DOCKPANE_SIZE 90
// Default size of floating window rectangle
#define DEFAULT_FLOAT_SIZE 120
// The splitter size in pixels
#define DEFAULT_SPLITTER_SIZE 6

#define WM_DOCK_QUERYRECT         WM_USER+840
#define WM_DOCK_QUERYTRACK        WM_USER+841
#define WM_DOCK_UNDOCK            WM_USER+842
#define WM_DOCK_UNFLOAT           WM_USER+843
#define WM_DOCK_DOCK              WM_USER+844
#define WM_DOCK_FLOAT             WM_USER+845
#define WM_DOCK_UPDATELAYOUT      WM_USER+846
#define WM_DOCK_REPOSITIONWINDOW  WM_USER+847
#define WM_DOCK_SETSPLITTER       WM_USER+848
#define WM_DOCK_CLIENT_CLOSE      WM_USER+849

class CDockingPaneChildWindow;
class CFloatingWindow;

struct DOCKCONTEXT 
{
   HWND hwndDocked;   // The docked pane
   HWND hwndFloated;  // The floating pane
   HWND hwndChild;    // The view window
   HWND hwndOrigPrnt; // The original parent window
   short Side;        // Dock state
   short LastSide;    // Last dock state
   RECT rcWindow;     // Preferred window size
   SIZE sizeFloat;    // Last window size (floating)
   HWND hwndRoot;     // Main dock window
   //
   DWORD dwFlags;     // Extra flags
   bool bKeepSize;    // Recommend using current size and avoid rescale
};

typedef CSimpleValArray<DOCKCONTEXT*> CDockMap;

struct TRACKINFO 
{
   HWND hWnd;
   DOCKCONTEXT* pCtx;
   POINT ptPos;
   POINT ptStart;
   RECT rc;
   short Side;
};


///////////////////////////////////////////////////////
// CSplitterBar

#pragma warning(disable : 4100)

template< class T >
class CSplitterBar
{
public:
   LONG m_cxySplitter;
   bool m_bTracking;
   bool m_bDragging;
   static HCURSOR s_hVertCursor;
   static HCURSOR s_hHorizCursor;

   CDCHandle m_dc;
   POINT m_ptStartDragPoint;
   POINT m_ptEndDragPoint;
   POINT m_ptDeltaDragPoint;
   RECT  m_rcTracker;
   SIZE  m_sizeTracker;
   RECT  m_rcTrackerBounds;   

   CSplitterBar() :
      m_bTracking(false), m_bDragging(false)
   {
      if( s_hVertCursor == NULL ) {
         ::EnterCriticalSection(&_Module.m_csStaticDataInit);
         s_hVertCursor = ::LoadCursor(NULL, IDC_SIZENS);
         s_hHorizCursor = ::LoadCursor(NULL, IDC_SIZEWE);
         ::LeaveCriticalSection(&_Module.m_csStaticDataInit);
      }
      m_sizeTracker.cx = ::GetSystemMetrics(SM_CXFRAME);
      m_sizeTracker.cy = ::GetSystemMetrics(SM_CYFRAME);
      m_cxySplitter = DEFAULT_SPLITTER_SIZE;
   }

   LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {
      T* pT = static_cast<T*>(this);
      DWORD dwPos = ::GetMessagePos();
      POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
      pT->ScreenToClient(&ptPos);
      if( ::PtInRect(&pT->m_rcSplitter, ptPos) ) return 1;
      bHandled = FALSE;
      return 0;
   }

   void DrawGhostBar()
   {
      ATLASSERT(!m_dc.IsNull());
      RECT rect = m_rcTracker;
      if( !::IsRectEmpty(&rect) ) {
         // Invert the brush pattern (looks just like frame window sizing)
         CBrush brush = CDCHandle::GetHalftoneBrush();
         if( brush.m_hBrush != NULL ) {
            ATLASSERT(!m_dc.IsNull());
            CBrushHandle brushOld = m_dc.SelectBrush(brush);
            m_dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
            m_dc.SelectBrush(brushOld);
         }
      }
   }

   void DrawDragBar()
   {
      ATLASSERT(!m_dc.IsNull());
      RECT rect = m_rcTracker;
      if( !::IsRectEmpty(&rect) ) {
         // Invert the brush pattern (looks just like frame window sizing)
         CBrush brush = CDCHandle::GetHalftoneBrush();
         if( brush.m_hBrush != NULL ) {
            ATLASSERT(!m_dc.IsNull());
            CBrushHandle brushOld = m_dc.SelectBrush(brush);
            m_dc.PatBlt(rect.left + m_sizeTracker.cx, rect.top, rect.right - rect.left - (m_sizeTracker.cx * 2), m_sizeTracker.cy, PATINVERT);
            m_dc.PatBlt(rect.left, rect.bottom - m_sizeTracker.cy, rect.right - rect.left, m_sizeTracker.cy, PATINVERT);
            m_dc.PatBlt(rect.left, rect.top, m_sizeTracker.cx, rect.bottom - rect.top - m_sizeTracker.cy, PATINVERT);
            m_dc.PatBlt(rect.right - m_sizeTracker.cx, rect.top, m_sizeTracker.cx, rect.bottom - rect.top - m_sizeTracker.cy, PATINVERT);
            m_dc.SelectBrush(brushOld);
         }
      }
   }

   void DrawSplitterBar(CDCHandle dc, bool bVertical, RECT& rect)
   {      
      if( ::IsRectEmpty(&rect) ) return;
      dc.FillRect(&rect, ::GetSysColorBrush(COLOR_3DFACE));
      dc.DrawEdge(&rect, EDGE_RAISED, (bVertical ? (BF_TOP|BF_BOTTOM) : (BF_LEFT|BF_RIGHT)));
   }

   bool PtInSplitter(POINT& pt, short Side, DWORD dwFlags, RECT& rcSplitter)
   {
      if( !IsDocked(Side) ) return false;
      if( m_bTracking ) return false;
      if( (dwFlags & DCK_NOSPLITTER) != 0 ) return false;
      if( !::PtInRect(&rcSplitter, pt) ) return false;
      return true;
   }

   // Track loop

   bool Track(bool bDragging)
   {
      T* pT = static_cast<T*>(this);
      StartTracking(bDragging);
      // Get messages until capture lost or cancelled/accepted
      while( ::GetCapture() == pT->m_hWnd ) {
         MSG msg;
         if( !::GetMessage(&msg, NULL, 0, 0) ) {
            ::PostQuitMessage(msg.wParam);
            break;
         }
         switch( msg.message ) {
         case WM_LBUTTONUP:
            if( m_bDragging ) pT->OnEndDrag(); else pT->OnEndResize();
            CancelTracking();
            return true;
         case WM_MOUSEMOVE:
            if( m_bDragging ) pT->OnMove(msg.pt); else pT->OnStretch(msg.pt);
            break;
         case WM_KEYUP:
            if( m_bDragging ) pT->OnKey((int) msg.wParam, false) ;
            break;
         case WM_KEYDOWN:
            if( m_bDragging ) pT->OnKey((int) msg.wParam, true);
            if( msg.wParam == VK_ESCAPE ) {
               CancelTracking();
               return false;
            }
            break;
         case WM_SYSKEYDOWN:
         case WM_LBUTTONDOWN:
         case WM_RBUTTONDOWN:
            CancelTracking();
            return false;      
         default:
            // Just dispatch rest of the messages
            ::DispatchMessage(&msg);
            break;
         }
      }

      CancelTracking();
      return false;
   }

   void StartTracking(bool bDragging)
   {
      ATLASSERT(!m_bTracking);
      T* pT = static_cast<T*>(this);
      // Capture window
      m_bTracking = true;
      pT->SetCapture();
      // Make sure no updates are pending
      pT->RedrawWindow(NULL, NULL, RDW_ALLCHILDREN|RDW_UPDATENOW);
      // Lock Window update while dragging over desktop
      ATLASSERT(m_dc.IsNull());
      HWND hWnd = ::GetDesktopWindow();
      m_dc = ::GetDCEx(hWnd, NULL, ::LockWindowUpdate(hWnd) ? DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE : DCX_WINDOW|DCX_CACHE);
      ATLASSERT(!m_dc.IsNull());
      // Draw the initial focus rect
      m_bDragging = bDragging;
      if( m_bDragging ) DrawDragBar(); else DrawGhostBar();
      return;
   }

   void CancelTracking()
   {
      ATLASSERT(m_bTracking);
      if( !m_bTracking ) return;
      // Erase the focus rect
      if( m_bDragging ) DrawDragBar(); else DrawGhostBar();
      // Let window updates free
      ::LockWindowUpdate(NULL);
      HWND hWnd = ::GetDesktopWindow();
      if( !m_dc.IsNull() ) ::ReleaseDC(hWnd, m_dc.Detach());
      // Release the capture
      ::ReleaseCapture();
      m_bTracking = false;
   }

   // Overridables

   void OnEndDrag() { };
   void OnEndResize() { };
   void OnKey(int nCode, bool bDown) { };
   void OnMove(POINT& pt) { };
   void OnStretch(POINT& pt) { };
};

template<class T> HCURSOR CSplitterBar<T>::s_hVertCursor = NULL;
template<class T> HCURSOR CSplitterBar<T>::s_hHorizCursor = NULL;

#pragma warning(default : 4100)


///////////////////////////////////////////////////////
// CFloatingWindow

typedef CWinTraits<WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME|WS_SYSMENU, WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE> CFloatWinTraits;

template< class T, class TBase = CWindow, class TWinTraits = CFloatWinTraits >
class ATL_NO_VTABLE CFloatingWindowImpl : 
   public CWindowImpl< T, TBase, TWinTraits >,
   public CSplitterBar<CFloatingWindowImpl>
{
public:
   DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, NULL)

   typedef CFloatingWindowImpl< T , TBase, TWinTraits > thisClass;
   
   BEGIN_MSG_MAP(CFloatingWindowImpl)
      MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
      MESSAGE_HANDLER(WM_SIZE, OnSize)
      MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
      MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar)
      MESSAGE_HANDLER(WM_GETMINMAXINFO, OnMsgForward)
      MESSAGE_HANDLER(WM_DOCK_UPDATELAYOUT, OnSize)
      MESSAGE_HANDLER(WM_NCACTIVATE, OnNcActivate)
      MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnLeftButtonDown)
      MESSAGE_HANDLER(WM_NCRBUTTONDOWN, OnRightButtonDown)
      MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnButtonDblClick)
   END_MSG_MAP()

   DOCKCONTEXT* m_pCtx;

   CFloatingWindowImpl(DOCKCONTEXT* pCtx) :
      m_pCtx(pCtx)
   { 
   }

   HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
         DWORD dwStyle = 0, DWORD dwExStyle = 0,
         UINT nID = 0, LPVOID lpCreateParam = NULL)
   {
      ATLASSERT(m_pCtx);
      if( m_pCtx->dwFlags & DCK_NOHIDE ) dwStyle = T::GetWndStyle(dwStyle) & ~WS_SYSMENU;
      return CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
   }

   virtual void OnFinalMessage(HWND /*hWnd*/)
   {
      delete (T*) this;
   }

   // Message handlers

   LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      return 1; // handled, no background painting needed
   }

   LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      T* pT = static_cast<T*>(this);
      pT->UpdateLayout();
      return 0;
   }

   LRESULT OnNcActivate(UINT uMsg, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
   {
      return DefWindowProc(uMsg, IsWindowEnabled(), lParam);
   }

   LRESULT OnLeftButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
   {
      SetFocus();
      if( wParam == HTCAPTION ) {
         // Get cursor point and start a tracking look
         POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
         m_ptStartDragPoint = m_ptEndDragPoint = pt;
         GetWindowRect(&m_rcTracker);
         // Enter tracking loop
         bool res = Track(true);
         if( res ) {
            // Determine if we landed over a docking pane or just moved around...
            TRACKINFO ti = { m_hWnd, m_pCtx, m_ptEndDragPoint.x, m_ptEndDragPoint.y, m_ptStartDragPoint.x, m_ptStartDragPoint.y };
            ::SendMessage(m_pCtx->hwndRoot, WM_DOCK_QUERYTRACK, 0, (LPARAM) &ti);
            if( ti.Side == DOCK_FLOAT ) {
               MoveWindow(&ti.rc, TRUE);
            }
            else {
               ::SendMessage(m_pCtx->hwndRoot, WM_DOCK_UNFLOAT, 0, (LPARAM) m_pCtx);
               ::SendMessage(m_pCtx->hwndRoot, WM_DOCK_DOCK, ti.Side, (LPARAM) m_pCtx);
            }
            return 0;
         }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -