Update-Installer/external/win32cpp/include/docking.h
Robert Knight d16da069e9 Add Win++ library to external
This is a thin wrapper around the Win32 API used in the Win32
Updater Dialog implementation.
2011-08-23 19:54:52 +01:00

4214 lines
122 KiB
C++

// Win32++ Version 7.2
// Released: 5th AUgust 2011
//
// David Nash
// email: dnash@bigpond.net.au
// url: https://sourceforge.net/projects/win32-framework
//
//
// Copyright (c) 2005-2011 David Nash
//
// Permission is hereby granted, free of charge, to
// any person obtaining a copy of this software and
// associated documentation files (the "Software"),
// to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify,
// merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom
// the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
//
////////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// docking.h
// Declaration of the CDocker class
#ifndef _WIN32XX_DOCKING_H_
#define _WIN32XX_DOCKING_H_
#include "wincore.h"
#include "gdi.h"
#include "toolbar.h"
#include "tab.h"
#include "frame.h"
#include "default_resource.h"
// Docking Styles
#define DS_DOCKED_LEFT 0x0001 // Dock the child left
#define DS_DOCKED_RIGHT 0x0002 // Dock the child right
#define DS_DOCKED_TOP 0x0004 // Dock the child top
#define DS_DOCKED_BOTTOM 0x0008 // Dock the child bottom
#define DS_NO_DOCKCHILD_LEFT 0x0010 // Prevent a child docking left
#define DS_NO_DOCKCHILD_RIGHT 0x0020 // Prevent a child docking right
#define DS_NO_DOCKCHILD_TOP 0x0040 // Prevent a child docking at the top
#define DS_NO_DOCKCHILD_BOTTOM 0x0080 // Prevent a child docking at the bottom
#define DS_NO_RESIZE 0x0100 // Prevent resizing
#define DS_NO_CAPTION 0x0200 // Prevent display of caption when docked
#define DS_NO_CLOSE 0x0400 // Prevent closing of a docker while docked
#define DS_NO_UNDOCK 0x0800 // Prevent undocking and dock closing
#define DS_CLIENTEDGE 0x1000 // Has a 3D border when docked
#define DS_FIXED_RESIZE 0x2000 // Perfomed a fixed resize instead of a proportional resize on dock children
#define DS_DOCKED_CONTAINER 0x4000 // Dock a container within a container
#define DS_DOCKED_LEFTMOST 0x10000 // Leftmost outer docking
#define DS_DOCKED_RIGHTMOST 0x20000 // Rightmost outer docking
#define DS_DOCKED_TOPMOST 0x40000 // Topmost outer docking
#define DS_DOCKED_BOTTOMMOST 0x80000 // Bottommost outer docking
// Required for Dev-C++
#ifndef TME_NONCLIENT
#define TME_NONCLIENT 0x00000010
#endif
#ifndef TME_LEAVE
#define TME_LEAVE 0x000000002
#endif
#ifndef WM_NCMOUSELEAVE
#define WM_NCMOUSELEAVE 0x000002A2
#endif
namespace Win32xx
{
// Class declarations
class CDockContainer;
class CDocker;
typedef Shared_Ptr<CDocker> DockPtr;
struct ContainerInfo
{
TCHAR szTitle[MAX_MENU_STRING];
int iImage;
CDockContainer* pContainer;
};
///////////////////////////////////////
// Declaration of the CDockContainer class
// A CDockContainer is a CTab window. A CTab has a view window, and optionally a toolbar control.
// A top level CDockContainer can contain other CDockContainers. The view for each container
// (including the top level container) along with possibly its toolbar, is displayed
// within the container parent's view page.
class CDockContainer : public CTab
{
public:
// Nested class. This is the Wnd for the window displayed over the client area
// of the tab control. The toolbar and view window are child windows of the
// viewpage window. Only the ViewPage of the parent CDockContainer is displayed. It's
// contents are updated with the view window of the relevant container whenever
// a different tab is selected.
class CViewPage : public CWnd
{
public:
CViewPage() : m_pView(NULL), m_pTab(NULL) {}
virtual ~CViewPage() {}
virtual CToolBar& GetToolBar() const {return (CToolBar&)m_ToolBar;}
virtual CWnd* GetView() const {return m_pView;}
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
virtual void OnCreate();
virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);
virtual void PreRegisterClass(WNDCLASS &wc);
virtual void RecalcLayout();
virtual void SetView(CWnd& wndView);
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
CWnd* GetTabCtrl() const { return m_pTab;}
private:
CToolBar m_ToolBar;
tString m_tsTooltip;
CWnd* m_pView;
CWnd* m_pTab;
};
public:
CDockContainer();
virtual ~CDockContainer();
virtual void AddContainer(CDockContainer* pContainer);
virtual void AddToolBarButton(UINT nID, BOOL bEnabled = TRUE);
virtual CDockContainer* GetContainerFromIndex(UINT nPage);
virtual CDockContainer* GetContainerFromView(CWnd* pView) const;
virtual int GetContainerIndex(CDockContainer* pContainer);
virtual SIZE GetMaxTabTextSize();
virtual CViewPage& GetViewPage() const { return (CViewPage&)m_ViewPage; }
virtual void RecalcLayout();
virtual void RemoveContainer(CDockContainer* pWnd);
virtual void SelectPage(int nPage);
virtual void SetTabSize();
virtual void SetupToolBar();
// Attributes
CDockContainer* GetActiveContainer() const {return GetContainerFromView(GetActiveView());}
CWnd* GetActiveView() const;
std::vector<ContainerInfo>& GetAllContainers() const {return m_pContainerParent->m_vContainerInfo;}
CDockContainer* GetContainerParent() const { return m_pContainerParent; }
CString& GetDockCaption() const { return (CString&)m_csCaption; }
HICON GetTabIcon() const { return m_hTabIcon; }
LPCTSTR GetTabText() const { return m_tsTabText.c_str(); }
virtual CToolBar& GetToolBar() const { return GetViewPage().GetToolBar(); }
CWnd* GetView() const { return GetViewPage().GetView(); }
void SetActiveContainer(CDockContainer* pContainer);
void SetDockCaption(LPCTSTR szCaption) { m_csCaption = szCaption; }
void SetTabIcon(HICON hTabIcon) { m_hTabIcon = hTabIcon; }
void SetTabIcon(UINT nID_Icon);
void SetTabIcon(int i, HICON hIcon) { CTab::SetTabIcon(i, hIcon); }
void SetTabText(LPCTSTR szText) { m_tsTabText = szText; }
void SetTabText(UINT nTab, LPCTSTR szText);
void SetView(CWnd& Wnd);
protected:
virtual void OnCreate();
virtual void OnLButtonDown(WPARAM wParam, LPARAM lParam);
virtual void OnLButtonUp(WPARAM wParam, LPARAM lParam);
virtual void OnMouseLeave(WPARAM wParam, LPARAM lParam);
virtual LRESULT OnNotifyReflect(WPARAM wParam, LPARAM lParam);
virtual void PreCreate(CREATESTRUCT &cs);
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
std::vector<ContainerInfo> m_vContainerInfo;
tString m_tsTabText;
CString m_csCaption;
CViewPage m_ViewPage;
int m_iCurrentPage;
CDockContainer* m_pContainerParent;
HICON m_hTabIcon;
int m_nTabPressed;
};
typedef struct DRAGPOS
{
NMHDR hdr;
POINT ptPos;
UINT DockZone;
} *LPDRAGPOS;
/////////////////////////////////////////
// Declaration of the CDocker class
// A CDocker window allows other CDocker windows to be "docked" inside it.
// A CDocker can dock on the top, left, right or bottom side of a parent CDocker.
// There is no theoretical limit to the number of CDockers within CDockers.
class CDocker : public CWnd
{
public:
// A nested class for the splitter bar that seperates the docked panes.
class CDockBar : public CWnd
{
public:
CDockBar();
virtual ~CDockBar();
virtual void OnDraw(CDC* pDC);
virtual void PreCreate(CREATESTRUCT &cs);
virtual void PreRegisterClass(WNDCLASS& wc);
virtual void SendNotify(UINT nMessageID);
virtual void SetColor(COLORREF color);
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
CDocker* GetDock() {return m_pDock;}
int GetWidth() {return m_DockBarWidth;}
void SetDock(CDocker* pDock) {m_pDock = pDock;}
void SetWidth(int nWidth) {m_DockBarWidth = nWidth;}
private:
CDockBar(const CDockBar&); // Disable copy construction
CDockBar& operator = (const CDockBar&); // Disable assignment operator
CDocker* m_pDock;
DRAGPOS m_DragPos;
CBrush m_brBackground;
int m_DockBarWidth;
};
// A nested class for the window inside a CDocker which includes all of this docked client.
// It's the remaining part of the CDocker that doesn't belong to the CDocker's children.
// The Docker's view window is a child window of CDockClient.
class CDockClient : public CWnd
{
public:
CDockClient();
virtual ~CDockClient() {}
virtual void Draw3DBorder(RECT& Rect);
virtual void DrawCaption(WPARAM wParam);
virtual void DrawCloseButton(CDC& DrawDC, BOOL bFocus);
virtual CRect GetCloseRect();
virtual void SendNotify(UINT nMessageID);
CString& GetCaption() const { return (CString&)m_csCaption; }
CWnd* GetView() const { return m_pView; }
void SetDock(CDocker* pDock) { m_pDock = pDock;}
void SetCaption(LPCTSTR szCaption) { m_csCaption = szCaption; }
void SetCaptionColors(COLORREF Foregnd1, COLORREF Backgnd1, COLORREF ForeGnd2, COLORREF BackGnd2);
void SetClosePressed() { m_IsClosePressed = TRUE; }
void SetView(CWnd& Wnd) { m_pView = &Wnd; }
protected:
virtual void OnLButtonDown(WPARAM wParam, LPARAM lParam);
virtual void OnLButtonUp(WPARAM wParam, LPARAM lParam);
virtual void OnMouseActivate(WPARAM wParam, LPARAM lParam);
virtual void OnMouseMove(WPARAM wParam, LPARAM lParam);
virtual void OnNCCalcSize(WPARAM& wParam, LPARAM& lParam);
virtual LRESULT OnNCHitTest(WPARAM wParam, LPARAM lParam);
virtual LRESULT OnNCLButtonDown(WPARAM wParam, LPARAM lParam);
virtual void OnNCMouseLeave(WPARAM wParam, LPARAM lParam);
virtual LRESULT OnNCMouseMove(WPARAM wParam, LPARAM lParam);
virtual LRESULT OnNCPaint(WPARAM wParam, LPARAM lParam);
virtual void OnWindowPosChanged(WPARAM wParam, LPARAM lParam);
virtual void PreRegisterClass(WNDCLASS& wc);
virtual void PreCreate(CREATESTRUCT& cs);
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
CDockClient(const CDockClient&); // Disable copy construction
CDockClient& operator = (const CDockClient&); // Disable assignment operator
CString m_csCaption;
CPoint m_Oldpt;
CDocker* m_pDock;
CWnd* m_pView;
BOOL m_IsClosePressed;
BOOL m_bOldFocus;
BOOL m_bCaptionPressed;
BOOL m_IsTracking;
COLORREF m_Foregnd1;
COLORREF m_Backgnd1;
COLORREF m_Foregnd2;
COLORREF m_Backgnd2;
};
// This nested class is used to indicate where a window could dock by
// displaying a blue tinted window.
class CDockHint : public CWnd
{
public:
CDockHint();
virtual ~CDockHint();
virtual RECT CalcHintRectContainer(CDocker* pDockTarget);
virtual RECT CalcHintRectInner(CDocker* pDockTarget, CDocker* pDockDrag, UINT uDockSide);
virtual RECT CalcHintRectOuter(CDocker* pDockDrag, UINT uDockSide);
virtual void DisplayHint(CDocker* pDockTarget, CDocker* pDockDrag, UINT uDockSide);
virtual void OnDraw(CDC* pDC);
virtual void PreCreate(CREATESTRUCT &cs);
virtual void ShowHintWindow(CDocker* pDockTarget, CRect rcHint);
private:
CDockHint(const CDockHint&); // Disable copy construction
CDockHint& operator = (const CDockHint&); // Disable assignment operator
CBitmap m_bmBlueTint;
UINT m_uDockSideOld;
};
class CTarget : public CWnd
{
public:
CTarget() {}
virtual ~CTarget();
virtual void OnDraw(CDC* pDC);
virtual void PreCreate(CREATESTRUCT &cs);
protected:
CBitmap m_bmImage;
private:
CTarget(const CTarget&); // Disable copy construction
CTarget& operator = (const CTarget&); // Disable assignment operator
};
class CTargetCentre : public CTarget
{
public:
CTargetCentre();
virtual ~CTargetCentre();
virtual void OnDraw(CDC* pDC);
virtual void OnCreate();
virtual BOOL CheckTarget(LPDRAGPOS pDragPos);
BOOL IsOverContainer() { return m_bIsOverContainer; }
private:
CTargetCentre(const CTargetCentre&); // Disable copy construction
CTargetCentre& operator = (const CTargetCentre&); // Disable assignment operator
BOOL m_bIsOverContainer;
CDocker* m_pOldDockTarget;
};
class CTargetLeft : public CTarget
{
public:
CTargetLeft() {m_bmImage.LoadImage(IDW_SDLEFT,0,0,0);}
virtual BOOL CheckTarget(LPDRAGPOS pDragPos);
private:
CTargetLeft(const CTargetLeft&); // Disable copy construction
CTargetLeft& operator = (const CTargetLeft&); // Disable assignment operator
};
class CTargetTop : public CTarget
{
public:
CTargetTop() {m_bmImage.LoadImage(IDW_SDTOP,0,0,0);}
virtual BOOL CheckTarget(LPDRAGPOS pDragPos);
private:
CTargetTop(const CTargetTop&); // Disable copy construction
CTargetTop& operator = (const CTargetTop&); // Disable assignment operator
};
class CTargetRight : public CTarget
{
public:
CTargetRight() {m_bmImage.LoadImage(IDW_SDRIGHT,0,0,0);}
virtual BOOL CheckTarget(LPDRAGPOS pDragPos);
private:
CTargetRight(const CTargetRight&); // Disable copy construction
CTargetRight& operator = (const CTargetRight&); // Disable assignment operator
};
class CTargetBottom : public CTarget
{
public:
CTargetBottom() {m_bmImage.LoadImage(IDW_SDBOTTOM,0,0,0);}
virtual BOOL CheckTarget(LPDRAGPOS pDragPos);
};
friend class CTargetCentre;
friend class CTargetLeft;
friend class CTargetTop;
friend class CTargetRight;
friend class CTargetBottom;
friend class CDockClient;
friend class CDockContainer;
public:
// Operations
CDocker();
virtual ~CDocker();
virtual CDocker* AddDockedChild(CDocker* pDocker, DWORD dwDockStyle, int DockSize, int nDockID = 0);
virtual CDocker* AddUndockedChild(CDocker* pDocker, DWORD dwDockStyle, int DockSize, RECT rc, int nDockID = 0);
virtual void Close();
virtual void CloseAllDockers();
virtual void Dock(CDocker* pDocker, UINT uDockSide);
virtual void DockInContainer(CDocker* pDock, DWORD dwDockStyle);
virtual CDockContainer* GetContainer() const;
virtual CDocker* GetActiveDocker() const;
virtual CDocker* GetDockAncestor() const;
virtual CDocker* GetDockFromID(int n_DockID) const;
virtual CDocker* GetDockFromPoint(POINT pt) const;
virtual CDocker* GetDockFromView(CWnd* pView) const;
virtual CDocker* GetTopmostDocker() const;
virtual int GetDockSize() const;
virtual CTabbedMDI* GetTabbedMDI() const;
virtual int GetTextHeight();
virtual void Hide();
virtual BOOL LoadRegistrySettings(tString tsRegistryKeyName);
virtual void RecalcDockLayout();
virtual BOOL SaveRegistrySettings(tString tsRegistryKeyName);
virtual void Undock(CPoint pt, BOOL bShowUndocked = TRUE);
virtual void UndockContainer(CDockContainer* pContainer, CPoint pt, BOOL bShowUndocked);
virtual BOOL VerifyDockers();
// Attributes
virtual CDockBar& GetDockBar() const {return (CDockBar&)m_DockBar;}
virtual CDockClient& GetDockClient() const {return (CDockClient&)m_DockClient;}
virtual CDockHint& GetDockHint() const {return m_pDockAncestor->m_DockHint;}
std::vector <DockPtr> & GetAllDockers() const {return GetDockAncestor()->m_vAllDockers;}
int GetBarWidth() const {return GetDockBar().GetWidth();}
CString& GetCaption() const {return GetDockClient().GetCaption();}
std::vector <CDocker*> & GetDockChildren() const {return (std::vector <CDocker*> &)m_vDockChildren;}
int GetDockID() const {return m_nDockID;}
CDocker* GetDockParent() const {return m_pDockParent;}
DWORD GetDockStyle() const {return m_DockStyle;}
CWnd* GetView() const {return GetDockClient().GetView();}
BOOL IsChildOfDocker(CWnd* pWnd) const;
BOOL IsDocked() const;
BOOL IsDragAutoResize();
BOOL IsRelated(CWnd* pWnd) const;
BOOL IsUndocked() const;
void SetBarColor(COLORREF color) {GetDockBar().SetColor(color);}
void SetBarWidth(int nWidth) {GetDockBar().SetWidth(nWidth);}
void SetCaption(LPCTSTR szCaption);
void SetCaptionColors(COLORREF Foregnd1, COLORREF Backgnd1, COLORREF ForeGnd2, COLORREF BackGnd2);
void SetCaptionHeight(int nHeight);
void SetDockStyle(DWORD dwDockStyle);
void SetDockSize(int DockSize);
void SetDragAutoResize(BOOL bAutoResize);
void SetView(CWnd& wndView);
protected:
virtual CDocker* NewDockerFromID(int idDock);
virtual void OnActivate(WPARAM wParam, LPARAM lParam);
virtual void OnCaptionTimer(WPARAM wParam, LPARAM lParam);
virtual void OnCreate();
virtual void OnDestroy(WPARAM wParam, LPARAM lParam);
virtual void OnDockDestroyed(WPARAM wParam, LPARAM lParam);
virtual void OnExitSizeMove(WPARAM wParam, LPARAM lParam);
virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);
virtual void OnSetFocus(WPARAM wParam, LPARAM lParam);
virtual void OnSysColorChange(WPARAM wParam, LPARAM lParam);
virtual LRESULT OnSysCommand(WPARAM wParam, LPARAM lParam);
virtual LRESULT OnWindowPosChanging(WPARAM wParam, LPARAM lParam);
virtual void OnWindowPosChanged(WPARAM wParam, LPARAM lParam);
virtual void PreCreate(CREATESTRUCT &cs);
virtual void PreRegisterClass(WNDCLASS &wc);
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
CDocker(const CDocker&); // Disable copy construction
CDocker& operator = (const CDocker&); // Disable assignment operator
void CheckAllTargets(LPDRAGPOS pDragPos);
void CloseAllTargets();
void DockOuter(CDocker* pDocker, DWORD dwDockStyle);
void DrawAllCaptions();
void DrawHashBar(HWND hBar, POINT Pos);
void ConvertToChild(HWND hWndParent);
void ConvertToPopup(RECT rc);
void MoveDockChildren(CDocker* pDockTarget);
void PromoteFirstChild();
void RecalcDockChildLayout(CRect rc);
void ResizeDockers(LPDRAGPOS pdp);
CDocker* SeparateFromDock();
void SendNotify(UINT nMessageID);
void SetUndockPosition(CPoint pt);
std::vector<CDocker*> SortDockers();
CDockBar m_DockBar;
CDockHint m_DockHint;
CDockClient m_DockClient;
CTargetCentre m_TargetCentre;
CTargetLeft m_TargetLeft;
CTargetTop m_TargetTop;
CTargetRight m_TargetRight;
CPoint m_OldPoint;
CTargetBottom m_TargetBottom;
CDocker* m_pDockParent;
CDocker* m_pDockAncestor;
CDocker* m_pDockActive;
std::vector <CDocker*> m_vDockChildren;
std::vector <DockPtr> m_vAllDockers; // Only used in DockAncestor
CRect m_rcBar;
CRect m_rcChild;
BOOL m_BlockMove;
BOOL m_Undocking;
BOOL m_bIsClosing;
BOOL m_bIsDragging;
BOOL m_bDragAutoResize;
int m_DockStartSize;
int m_nDockID;
int m_nTimerCount;
int m_NCHeight;
DWORD m_dwDockZone;
double m_DockSizeRatio;
DWORD m_DockStyle;
HWND m_hOldFocus;
}; // class CDocker
struct DockInfo
{
DWORD DockStyle;
int DockSize;
int DockID;
int DockParentID;
RECT Rect;
};
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
namespace Win32xx
{
/////////////////////////////////////////////////////////////
// Definitions for the CDockBar class nested within CDocker
//
inline CDocker::CDockBar::CDockBar() : m_pDock(NULL), m_DockBarWidth(4)
{
m_brBackground.CreateSolidBrush(RGB(192,192,192));
}
inline CDocker::CDockBar::~CDockBar()
{
}
inline void CDocker::CDockBar::OnDraw(CDC* pDC)
{
CRect rcClient = GetClientRect();
pDC->SelectObject(&m_brBackground);
pDC->PatBlt(0, 0, rcClient.Width(), rcClient.Height(), PATCOPY);
}
inline void CDocker::CDockBar::PreCreate(CREATESTRUCT &cs)
{
// Create a child window, initially hidden
cs.style = WS_CHILD;
}
inline void CDocker::CDockBar::PreRegisterClass(WNDCLASS& wc)
{
wc.lpszClassName = _T("Win32++ Bar");
wc.hbrBackground = m_brBackground;
}
inline void CDocker::CDockBar::SendNotify(UINT nMessageID)
{
// Send a splitter bar notification to the parent
m_DragPos.hdr.code = nMessageID;
m_DragPos.hdr.hwndFrom = m_hWnd;
m_DragPos.ptPos = GetCursorPos();
m_DragPos.ptPos.x += 1;
GetParent()->SendMessage(WM_NOTIFY, 0L, (LPARAM)&m_DragPos);
}
inline void CDocker::CDockBar::SetColor(COLORREF color)
{
// Useful colors:
// GetSysColor(COLOR_BTNFACE) // Default Grey
// RGB(196, 215, 250) // Default Blue
m_brBackground.CreateSolidBrush(color);
}
inline LRESULT CDocker::CDockBar::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
{
switch (uMsg)
{
case WM_SETCURSOR:
{
if (!(m_pDock->GetDockStyle() & DS_NO_RESIZE))
{
HCURSOR hCursor;
DWORD dwSide = GetDock()->GetDockStyle() & 0xF;
if ((dwSide == DS_DOCKED_LEFT) || (dwSide == DS_DOCKED_RIGHT))
hCursor = LoadCursor(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(IDW_SPLITH));
else
hCursor = LoadCursor(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(IDW_SPLITV));
if (hCursor) SetCursor(hCursor);
else TRACE(_T("**WARNING** Missing cursor resource for slider bar\n"));
return TRUE;
}
else
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
break;
case WM_ERASEBKGND:
return 0;
case WM_LBUTTONDOWN:
{
if (!(m_pDock->GetDockStyle() & DS_NO_RESIZE))
{
SendNotify(UWM_BAR_START);
SetCapture();
}
}
break;
case WM_LBUTTONUP:
if (!(m_pDock->GetDockStyle() & DS_NO_RESIZE) && (GetCapture() == this))
{
SendNotify(UWM_BAR_END);
ReleaseCapture();
}
break;
case WM_MOUSEMOVE:
if (!(m_pDock->GetDockStyle() & DS_NO_RESIZE) && (GetCapture() == this))
{
SendNotify(UWM_BAR_MOVE);
}
break;
}
}
// pass unhandled messages on for default processing
return CWnd::WndProcDefault(uMsg, wParam, lParam);
}
////////////////////////////////////////////////////////////////
// Definitions for the CDockClient class nested within CDocker
//
inline CDocker::CDockClient::CDockClient() : m_pView(0), m_IsClosePressed(FALSE),
m_bOldFocus(FALSE), m_bCaptionPressed(FALSE), m_IsTracking(FALSE)
{
m_Foregnd1 = RGB(32,32,32);
m_Backgnd1 = RGB(190,207,227);
m_Foregnd2 = GetSysColor(COLOR_BTNTEXT);
m_Backgnd2 = GetSysColor(COLOR_BTNFACE);
}
inline void CDocker::CDockClient::Draw3DBorder(RECT& Rect)
{
// Imitates the drawing of the WS_EX_CLIENTEDGE extended style
// This draws a 2 pixel border around the specified Rect
CWindowDC dc(this);
CRect rcw = Rect;
dc.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
dc.MoveTo(0, rcw.Height());
dc.LineTo(0, 0);
dc.LineTo(rcw.Width(), 0);
dc.CreatePen(PS_SOLID,1, GetSysColor(COLOR_3DDKSHADOW));
dc.MoveTo(1, rcw.Height()-2);
dc.LineTo(1, 1);
dc.LineTo(rcw.Width()-2, 1);
dc.CreatePen(PS_SOLID,1, GetSysColor(COLOR_3DHILIGHT));
dc.MoveTo(rcw.Width()-1, 0);
dc.LineTo(rcw.Width()-1, rcw.Height()-1);
dc.LineTo(0, rcw.Height()-1);
dc.CreatePen(PS_SOLID,1, GetSysColor(COLOR_3DLIGHT));
dc.MoveTo(rcw.Width()-2, 1);
dc.LineTo(rcw.Width()-2, rcw.Height()-2);
dc.LineTo(1, rcw.Height()-2);
}
inline CRect CDocker::CDockClient::GetCloseRect()
{
// Calculate the close rect position in screen co-ordinates
CRect rcClose;
int gap = 4;
CRect rc = GetWindowRect();
int cx = GetSystemMetrics(SM_CXSMICON);
int cy = GetSystemMetrics(SM_CYSMICON);
rcClose.top = 2 + rc.top + m_pDock->m_NCHeight/2 - cy/2;
rcClose.bottom = 2 + rc.top + m_pDock->m_NCHeight/2 + cy/2;
rcClose.right = rc.right - gap;
rcClose.left = rcClose.right - cx;
#if defined(WINVER) && defined (WS_EX_LAYOUTRTL) && (WINVER >= 0x0500)
if (GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
{
rcClose.left = rc.left + gap;
rcClose.right = rcClose.left + cx;
}
#endif
return rcClose;
}
inline void CDocker::CDockClient::DrawCaption(WPARAM wParam)
{
if (IsWindow() && m_pDock->IsDocked() && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
BOOL bFocus = m_pDock->IsChildOfDocker(GetFocus());
m_bOldFocus = FALSE;
// Acquire the DC for our NonClient painting
CDC* pDC;
if ((wParam != 1) && (bFocus == m_bOldFocus))
pDC = GetDCEx((HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN|DCX_PARENTCLIP);
else
pDC = GetWindowDC();
// Create and set up our memory DC
CRect rc = GetWindowRect();
CMemDC dcMem(pDC);
int rcAdjust = (GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_CLIENTEDGE)? 2 : 0;
int Width = MAX(rc.Width() -rcAdjust, 0);
int Height = m_pDock->m_NCHeight + rcAdjust;
dcMem.CreateCompatibleBitmap(pDC, Width, Height);
m_bOldFocus = bFocus;
// Set the font for the title
NONCLIENTMETRICS info = {0};
info.cbSize = GetSizeofNonClientMetrics();
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
dcMem.CreateFontIndirect(&info.lfStatusFont);
// Set the Colours
if (bFocus)
{
dcMem.SetTextColor(m_Foregnd1);
dcMem.CreateSolidBrush(m_Backgnd1);
dcMem.SetBkColor(m_Backgnd1);
}
else
{
dcMem.SetTextColor(m_Foregnd2);
dcMem.CreateSolidBrush(m_Backgnd2);
dcMem.SetBkColor(m_Backgnd2);
}
// Draw the rectangle
dcMem.CreatePen(PS_SOLID, 1, RGB(160, 150, 140));
dcMem.Rectangle(rcAdjust, rcAdjust, rc.Width() -rcAdjust, m_pDock->m_NCHeight +rcAdjust);
// Display the caption
int cx = (m_pDock->GetDockStyle() & DS_NO_CLOSE)? 0 : GetSystemMetrics(SM_CXSMICON);
CRect rcText(4 +rcAdjust, rcAdjust, rc.Width() -4 - cx -rcAdjust, m_pDock->m_NCHeight +rcAdjust);
dcMem.DrawText(m_csCaption, m_csCaption.GetLength(), rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS);
// Draw the close button
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CLOSE))
DrawCloseButton(dcMem, bFocus);
// Draw the 3D border
if (GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_CLIENTEDGE)
Draw3DBorder(rc);
// Copy the Memory DC to the window's DC
pDC->BitBlt(rcAdjust, rcAdjust, Width, Height, &dcMem, rcAdjust, rcAdjust, SRCCOPY);
// Required for Win98/WinME
pDC->Destroy();
}
}
inline void CDocker::CDockClient::DrawCloseButton(CDC& DrawDC, BOOL bFocus)
{
// The close button isn't displayed on Win95
if (GetWinVersion() == 1400) return;
if (m_pDock->IsDocked() && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
// Determine the close button's drawing position relative to the window
CRect rcClose = GetCloseRect();
UINT uState = GetCloseRect().PtInRect(GetCursorPos())? m_IsClosePressed && IsLeftButtonDown()? 2 : 1 : 0;
ScreenToClient(rcClose);
if (GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_CLIENTEDGE)
{
rcClose.OffsetRect(2, m_pDock->m_NCHeight+2);
if (GetWindowRect().Height() < (m_pDock->m_NCHeight+4))
rcClose.OffsetRect(-2, -2);
}
else
rcClose.OffsetRect(0, m_pDock->m_NCHeight-2);
// Draw the outer highlight for the close button
if (!IsRectEmpty(&rcClose))
{
switch (uState)
{
case 0:
{
// Normal button
DrawDC.CreatePen(PS_SOLID, 1, RGB(232, 228, 220));
DrawDC.MoveTo(rcClose.left, rcClose.bottom);
DrawDC.LineTo(rcClose.right, rcClose.bottom);
DrawDC.LineTo(rcClose.right, rcClose.top);
DrawDC.LineTo(rcClose.left, rcClose.top);
DrawDC.LineTo(rcClose.left, rcClose.bottom);
break;
}
case 1:
{
// Popped up button
// Draw outline, white at top, black on bottom
DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
DrawDC.MoveTo(rcClose.left, rcClose.bottom);
DrawDC.LineTo(rcClose.right, rcClose.bottom);
DrawDC.LineTo(rcClose.right, rcClose.top);
DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
DrawDC.LineTo(rcClose.left, rcClose.top);
DrawDC.LineTo(rcClose.left, rcClose.bottom);
}
break;
case 2:
{
// Pressed button
// Draw outline, black on top, white on bottom
DrawDC.CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
DrawDC.MoveTo(rcClose.left, rcClose.bottom);
DrawDC.LineTo(rcClose.right, rcClose.bottom);
DrawDC.LineTo(rcClose.right, rcClose.top);
DrawDC.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
DrawDC.LineTo(rcClose.left, rcClose.top);
DrawDC.LineTo(rcClose.left, rcClose.bottom);
}
break;
}
// Manually Draw Close Button
if (bFocus)
DrawDC.CreatePen(PS_SOLID, 1, m_Foregnd1);
else
DrawDC.CreatePen(PS_SOLID, 1, m_Foregnd2);
DrawDC.MoveTo(rcClose.left + 3, rcClose.top +3);
DrawDC.LineTo(rcClose.right - 2, rcClose.bottom -2);
DrawDC.MoveTo(rcClose.left + 4, rcClose.top +3);
DrawDC.LineTo(rcClose.right - 2, rcClose.bottom -3);
DrawDC.MoveTo(rcClose.left + 3, rcClose.top +4);
DrawDC.LineTo(rcClose.right - 3, rcClose.bottom -2);
DrawDC.MoveTo(rcClose.right -3, rcClose.top +3);
DrawDC.LineTo(rcClose.left + 2, rcClose.bottom -2);
DrawDC.MoveTo(rcClose.right -3, rcClose.top +4);
DrawDC.LineTo(rcClose.left + 3, rcClose.bottom -2);
DrawDC.MoveTo(rcClose.right -4, rcClose.top +3);
DrawDC.LineTo(rcClose.left + 2, rcClose.bottom -3);
}
}
}
inline void CDocker::CDockClient::OnNCCalcSize(WPARAM& wParam, LPARAM& lParam)
{
// Sets the non-client area (and hence sets the client area)
// This function modifies lParam
UNREFERENCED_PARAMETER(wParam);
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
if (m_pDock->IsDocked())
{
LPRECT rc = (LPRECT)lParam;
rc->top += m_pDock->m_NCHeight;
}
}
}
inline LRESULT CDocker::CDockClient::OnNCHitTest(WPARAM wParam, LPARAM lParam)
{
// Identify which part of the non-client area the cursor is over
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
if (m_pDock->IsDocked())
{
CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
// Indicate if the point is in the close button (except for Win95)
if ((GetWinVersion() > 1400) && (GetCloseRect().PtInRect(pt)))
return HTCLOSE;
ScreenToClient(pt);
// Indicate if the point is in the caption
if (pt.y < 0)
return HTCAPTION;
}
}
return CWnd::WndProcDefault(WM_NCHITTEST, wParam, lParam);
}
inline LRESULT CDocker::CDockClient::OnNCLButtonDown(WPARAM wParam, LPARAM lParam)
{
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
if ((HTCLOSE == wParam) && !(m_pDock->GetDockStyle() & DS_NO_CLOSE))
{
m_IsClosePressed = TRUE;
SetCapture();
}
m_bCaptionPressed = TRUE;
m_Oldpt.x = GET_X_LPARAM(lParam);
m_Oldpt.y = GET_Y_LPARAM(lParam);
if (m_pDock->IsDocked())
{
CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
ScreenToClient(pt);
m_pView->SetFocus();
// Update the close button
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CLOSE))
{
CWindowDC dc(this);
DrawCloseButton(dc, m_bOldFocus);
}
return 0L;
}
}
return CWnd::WndProcDefault(WM_NCLBUTTONDOWN, wParam, lParam);
}
inline void CDocker::CDockClient::OnLButtonUp(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & (DS_NO_CAPTION|DS_NO_CLOSE)))
{
m_bCaptionPressed = FALSE;
if (m_IsClosePressed && GetCloseRect().PtInRect(GetCursorPos()))
{
// Destroy the docker
if (dynamic_cast<CDockContainer*>(m_pDock->GetView()))
{
CDockContainer* pContainer = ((CDockContainer*)m_pDock->GetView())->GetActiveContainer();
CDocker* pDock = m_pDock->GetDockFromView(pContainer);
pDock->GetDockClient().SetClosePressed();
m_pDock->UndockContainer(pContainer, GetCursorPos(), FALSE);
pDock->Destroy();
}
else
{
m_pDock->Hide();
m_pDock->Destroy();
}
}
}
}
inline void CDocker::CDockClient::OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
m_IsClosePressed = FALSE;
ReleaseCapture();
CWindowDC dc(this);
DrawCloseButton(dc, m_bOldFocus);
}
inline void CDocker::CDockClient::OnMouseActivate(WPARAM wParam, LPARAM lParam)
// Focus changed, so redraw the captions
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
m_pDock->GetDockAncestor()->PostMessage(UWM_DOCK_ACTIVATED, 0, 0);
}
}
inline void CDocker::CDockClient::OnMouseMove(WPARAM wParam, LPARAM lParam)
{
OnNCMouseMove(wParam, lParam);
}
inline void CDocker::CDockClient::OnNCMouseLeave(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
m_IsTracking = FALSE;
CWindowDC dc(this);
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & (DS_NO_CAPTION|DS_NO_CLOSE)) && m_pDock->IsDocked())
DrawCloseButton(dc, m_bOldFocus);
m_IsTracking = FALSE;
}
inline LRESULT CDocker::CDockClient::OnNCMouseMove(WPARAM wParam, LPARAM lParam)
{
if (!m_IsTracking)
{
TRACKMOUSEEVENT TrackMouseEventStruct = {0};
TrackMouseEventStruct.cbSize = sizeof(TrackMouseEventStruct);
TrackMouseEventStruct.dwFlags = TME_LEAVE|TME_NONCLIENT;
TrackMouseEventStruct.hwndTrack = m_hWnd;
_TrackMouseEvent(&TrackMouseEventStruct);
m_IsTracking = TRUE;
}
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
if (m_pDock->IsDocked())
{
// Discard phantom mouse move messages
if ( (m_Oldpt.x == GET_X_LPARAM(lParam) ) && (m_Oldpt.y == GET_Y_LPARAM(lParam)))
return 0L;
if (IsLeftButtonDown() && (wParam == HTCAPTION) && (m_bCaptionPressed))
{
CDocker* pDock = (CDocker*)GetParent();
if (pDock)
pDock->Undock(GetCursorPos());
}
// Update the close button
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CLOSE))
{
CWindowDC dc(this);
DrawCloseButton(dc, m_bOldFocus);
}
}
m_bCaptionPressed = FALSE;
}
return CWnd::WndProcDefault(WM_MOUSEMOVE, wParam, lParam);
}
inline LRESULT CDocker::CDockClient::OnNCPaint(WPARAM wParam, LPARAM lParam)
{
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CAPTION))
{
if (m_pDock->IsDocked())
{
DefWindowProc(WM_NCPAINT, wParam, lParam);
DrawCaption(wParam);
return 0;
}
}
return CWnd::WndProcDefault(WM_NCPAINT, wParam, lParam);
}
inline void CDocker::CDockClient::OnWindowPosChanged(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
// Reposition the View window to cover the DockClient's client area
CRect rc = GetClientRect();
m_pView->SetWindowPos(NULL, rc, SWP_SHOWWINDOW);
}
inline void CDocker::CDockClient::PreRegisterClass(WNDCLASS& wc)
{
wc.lpszClassName = _T("Win32++ DockClient");
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
}
inline void CDocker::CDockClient::PreCreate(CREATESTRUCT& cs)
{
DWORD dwStyle = m_pDock->GetDockStyle();
if (dwStyle & DS_CLIENTEDGE)
cs.dwExStyle = WS_EX_CLIENTEDGE;
#if defined(WINVER) && defined (WS_EX_LAYOUTRTL) && (WINVER >= 0x0500)
if (m_pDock->GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
cs.dwExStyle |= WS_EX_LAYOUTRTL;
#endif
}
inline void CDocker::CDockClient::SendNotify(UINT nMessageID)
{
// Fill the DragPos structure with data
DRAGPOS DragPos;
DragPos.hdr.code = nMessageID;
DragPos.hdr.hwndFrom = m_hWnd;
DragPos.ptPos = GetCursorPos();
// Send a DragPos notification to the docker
GetParent()->SendMessage(WM_NOTIFY, 0L, (LPARAM)&DragPos);
}
inline void CDocker::CDockClient::SetCaptionColors(COLORREF Foregnd1, COLORREF Backgnd1, COLORREF Foregnd2, COLORREF Backgnd2)
{
// Set the colors used when drawing the caption
// m_Foregnd1 Foreground colour (focused). m_Backgnd1 Background colour (focused)
// m_Foregnd2 Foreground colour (not focused). m_Backgnd2 Foreground colour (not focused)
m_Foregnd1 = Foregnd1;
m_Backgnd1 = Backgnd1;
m_Foregnd2 = Foregnd2;
m_Backgnd2 = Backgnd2;
}
inline LRESULT CDocker::CDockClient::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_LBUTTONUP:
{
ReleaseCapture();
if ((0 != m_pDock) && !(m_pDock->GetDockStyle() & DS_NO_CLOSE))
{
CWindowDC dc(this);
DrawCloseButton(dc, m_bOldFocus);
OnLButtonUp(wParam, lParam);
}
}
break;
case WM_MOUSEACTIVATE:
OnMouseActivate(wParam, lParam);
break;
case WM_MOUSEMOVE:
OnMouseMove(wParam, lParam);
break;
case WM_NCCALCSIZE:
OnNCCalcSize(wParam, lParam);
break;
case WM_NCHITTEST:
return OnNCHitTest(wParam, lParam);
case WM_NCLBUTTONDOWN:
return OnNCLButtonDown(wParam, lParam);
case WM_NCMOUSEMOVE:
return OnNCMouseMove(wParam, lParam);
case WM_NCPAINT:
return OnNCPaint(wParam, lParam);
case WM_NCMOUSELEAVE:
OnNCMouseLeave(wParam, lParam);
break;
case WM_WINDOWPOSCHANGED:
OnWindowPosChanged(wParam, lParam);
break;
}
return CWnd::WndProcDefault(uMsg, wParam, lParam);
}
//////////////////////////////////////////////////////////////
// Definitions for the CDockHint class nested within CDocker
//
inline CDocker::CDockHint::CDockHint() : m_uDockSideOld(0)
{
}
inline CDocker::CDockHint::~CDockHint()
{
}
inline RECT CDocker::CDockHint::CalcHintRectContainer(CDocker* pDockTarget)
{
// Calculate the hint window's position for container docking
CRect rcHint = pDockTarget->GetDockClient().GetWindowRect();
if (pDockTarget->GetDockClient().GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_CLIENTEDGE)
rcHint.InflateRect(-2, -2);
pDockTarget->ScreenToClient(rcHint);
return rcHint;
}
inline RECT CDocker::CDockHint::CalcHintRectInner(CDocker* pDockTarget, CDocker* pDockDrag, UINT uDockSide)
{
// Calculate the hint window's position for inner docking
CRect rcHint = pDockTarget->GetDockClient().GetWindowRect();
if (pDockTarget->GetDockClient().GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_CLIENTEDGE)
rcHint.InflateRect(-2, -2);
pDockTarget->ScreenToClient(rcHint);
int Width;
CRect rcDockDrag = pDockDrag->GetWindowRect();
CRect rcDockTarget = pDockTarget->GetDockClient().GetWindowRect();
if ((uDockSide == DS_DOCKED_LEFT) || (uDockSide == DS_DOCKED_RIGHT))
{
Width = rcDockDrag.Width();
if (Width >= (rcDockTarget.Width() - pDockDrag->GetBarWidth()))
Width = MAX(rcDockTarget.Width()/2 - pDockDrag->GetBarWidth(), pDockDrag->GetBarWidth());
}
else
{
Width = rcDockDrag.Height();
if (Width >= (rcDockTarget.Height() - pDockDrag->GetBarWidth()))
Width = MAX(rcDockTarget.Height()/2 - pDockDrag->GetBarWidth(), pDockDrag->GetBarWidth());
}
switch (uDockSide)
{
case DS_DOCKED_LEFT:
rcHint.right = rcHint.left + Width;
break;
case DS_DOCKED_RIGHT:
rcHint.left = rcHint.right - Width;
break;
case DS_DOCKED_TOP:
rcHint.bottom = rcHint.top + Width;
break;
case DS_DOCKED_BOTTOM:
rcHint.top = rcHint.bottom - Width;
break;
}
return rcHint;
}
inline RECT CDocker::CDockHint::CalcHintRectOuter(CDocker* pDockDrag, UINT uDockSide)
{
// Calculate the hint window's position for outer docking
CDocker* pDockTarget = pDockDrag->GetDockAncestor();
CRect rcHint = pDockTarget->GetClientRect();
if (pDockTarget->GetDockClient().GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_CLIENTEDGE)
rcHint.InflateRect(-2, -2);
int Width;
CRect rcDockDrag = pDockDrag->GetWindowRect();
CRect rcDockTarget = pDockTarget->GetDockClient().GetWindowRect();
// Limit the docked size to half the parent's size if it won't fit inside parent
if ((uDockSide == DS_DOCKED_LEFTMOST) || (uDockSide == DS_DOCKED_RIGHTMOST))
{
Width = rcDockDrag.Width();
int BarWidth = pDockDrag->GetBarWidth();
if (Width >= pDockTarget->GetDockClient().GetClientRect().Width() - pDockDrag->GetBarWidth())
Width = MAX(pDockTarget->GetDockClient().GetClientRect().Width()/2 - BarWidth, BarWidth);
}
else
{
Width = rcDockDrag.Height();
int BarWidth = pDockDrag->GetBarWidth();
if (Width >= pDockTarget->GetDockClient().GetClientRect().Height() - pDockDrag->GetBarWidth())
Width = MAX(pDockTarget->GetDockClient().GetClientRect().Height()/2 - BarWidth, BarWidth);
}
switch (uDockSide)
{
case DS_DOCKED_LEFTMOST:
rcHint.right = rcHint.left + Width;
break;
case DS_DOCKED_RIGHTMOST:
rcHint.left = rcHint.right - Width;
break;
case DS_DOCKED_TOPMOST:
rcHint.bottom = rcHint.top + Width;
break;
case DS_DOCKED_BOTTOMMOST:
rcHint.top = rcHint.bottom - Width;
break;
}
return rcHint;
}
inline void CDocker::CDockHint::DisplayHint(CDocker* pDockTarget, CDocker* pDockDrag, UINT uDockSide)
{
// Ensure a new hint window is created if dock side changes
if (uDockSide != m_uDockSideOld)
{
Destroy();
pDockTarget->RedrawWindow( NULL, NULL, RDW_NOERASE | RDW_UPDATENOW );
pDockDrag->RedrawWindow();
}
m_uDockSideOld = uDockSide;
if (!IsWindow())
{
CRect rcHint;
if (uDockSide & 0xF)
rcHint = CalcHintRectInner(pDockTarget, pDockDrag, uDockSide);
else if (uDockSide & 0xF0000)
rcHint = CalcHintRectOuter(pDockDrag, uDockSide);
else if (uDockSide & DS_DOCKED_CONTAINER)
rcHint = CalcHintRectContainer(pDockTarget);
else
return;
ShowHintWindow(pDockTarget, rcHint);
}
}
inline void CDocker::CDockHint::OnDraw(CDC* pDC)
{
// Display the blue tinted bitmap
CRect rc = GetClientRect();
CMemDC MemDC(pDC);
MemDC.SelectObject(&m_bmBlueTint);
pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &MemDC, 0, 0, SRCCOPY);
}
inline void CDocker::CDockHint::PreCreate(CREATESTRUCT &cs)
{
cs.style = WS_POPUP;
// WS_EX_TOOLWINDOW prevents the window being displayed on the taskbar
cs.dwExStyle = WS_EX_TOOLWINDOW;
cs.lpszClass = _T("Win32++ DockHint");
}
inline void CDocker::CDockHint::ShowHintWindow(CDocker* pDockTarget, CRect rcHint)
{
// Save the Dock window's blue tinted bitmap
CClientDC dcDesktop(NULL);
CMemDC dcMem(&dcDesktop);
CRect rcBitmap = rcHint;
CRect rcTarget = rcHint;
pDockTarget->ClientToScreen(rcTarget);
m_bmBlueTint.CreateCompatibleBitmap(&dcDesktop, rcBitmap.Width(), rcBitmap.Height());
CBitmap* pOldBitmap = dcMem.SelectObject(&m_bmBlueTint);
dcMem.BitBlt(0, 0, rcBitmap.Width(), rcBitmap.Height(), &dcDesktop, rcTarget.left, rcTarget.top, SRCCOPY);
dcMem.SelectObject(pOldBitmap);
TintBitmap(&m_bmBlueTint, -64, -24, +128);
// Create the Hint window
if (!IsWindow())
{
Create(pDockTarget);
}
pDockTarget->ClientToScreen(rcHint);
SetWindowPos(NULL, rcHint, SWP_SHOWWINDOW|SWP_NOZORDER|SWP_NOACTIVATE);
}
////////////////////////////////////////////////////////////////
// Definitions for the CTargetCentre class nested within CDocker
//
inline CDocker::CTargetCentre::CTargetCentre() : m_bIsOverContainer(FALSE), m_pOldDockTarget(0)
{
}
inline CDocker::CTargetCentre::~CTargetCentre()
{
}
inline void CDocker::CTargetCentre::OnDraw(CDC* pDC)
{
CBitmap bmCentre(IDW_SDCENTER);
CBitmap bmLeft(IDW_SDLEFT);
CBitmap bmRight(IDW_SDRIGHT);
CBitmap bmTop(IDW_SDTOP);
CBitmap bmBottom(IDW_SDBOTTOM);
if (bmCentre.GetHandle()) pDC->DrawBitmap(0, 0, 88, 88, bmCentre, RGB(255,0,255));
else TRACE(_T("Missing docking resource: Target Centre\n"));
if (bmLeft.GetHandle()) pDC->DrawBitmap(0, 29, 31, 29, bmLeft, RGB(255,0,255));
else TRACE(_T("Missing docking resource: Target Left\n"));
if (bmTop.GetHandle()) pDC->DrawBitmap(29, 0, 29, 31, bmTop, RGB(255,0,255));
else TRACE(_T("Missing docking resource: Target Top\n"));
if (bmRight.GetHandle()) pDC->DrawBitmap(55, 29, 31, 29, bmRight, RGB(255,0,255));
else TRACE(_T("Missing docking resource: Target Right\n"));
if (bmBottom.GetHandle()) pDC->DrawBitmap(29, 55, 29, 31, bmBottom, RGB(255,0,255));
else TRACE(_T("Missing docking resource: Target Bottom\n"));
if (IsOverContainer())
{
CBitmap bmMiddle(IDW_SDMIDDLE);
pDC->DrawBitmap(31, 31, 25, 26, bmMiddle, RGB(255,0,255));
}
}
inline void CDocker::CTargetCentre::OnCreate()
{
// Use a region to create an irregularly shapped window
POINT ptArray[16] = { {0,29}, {22, 29}, {29, 22}, {29, 0},
{58, 0}, {58, 22}, {64, 29}, {87, 29},
{87, 58}, {64, 58}, {58, 64}, {58, 87},
{29, 87}, {29, 64}, {23, 58}, {0, 58} };
CRgn rgnPoly;
rgnPoly.CreatePolygonRgn(ptArray, 16, WINDING);
SetWindowRgn(&rgnPoly, FALSE);
}
inline BOOL CDocker::CTargetCentre::CheckTarget(LPDRAGPOS pDragPos)
{
CDocker* pDockDrag = (CDocker*)FromHandle(pDragPos->hdr.hwndFrom);
if (NULL == pDockDrag) return FALSE;
CDocker* pDockTarget = pDockDrag->GetDockFromPoint(pDragPos->ptPos);
if (NULL == pDockTarget) return FALSE;
if (!IsWindow()) Create();
m_bIsOverContainer = (dynamic_cast<CDockContainer*>(pDockTarget->GetView()) != NULL);
// Redraw the target if the dock target changes
if (m_pOldDockTarget != pDockTarget) Invalidate();
m_pOldDockTarget = pDockTarget;
int cxImage = 88;
int cyImage = 88;
CRect rcTarget = pDockTarget->GetDockClient().GetWindowRect();
int xMid = rcTarget.left + (rcTarget.Width() - cxImage)/2;
int yMid = rcTarget.top + (rcTarget.Height() - cyImage)/2;
SetWindowPos(HWND_TOPMOST, xMid, yMid, cxImage, cyImage, SWP_NOACTIVATE|SWP_SHOWWINDOW);
// Create the docking zone rectangles
CPoint pt = pDragPos->ptPos;
ScreenToClient(pt);
CRect rcLeft(0, 29, 31, 58);
CRect rcTop(29, 0, 58, 31);
CRect rcRight(55, 29, 87, 58);
CRect rcBottom(29, 55, 58, 87);
CRect rcMiddle(31, 31, 56, 57);
// Test if our cursor is in one of the docking zones
if ((rcLeft.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_LEFT))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_LEFT);
pDockDrag->m_dwDockZone = DS_DOCKED_LEFT;
return TRUE;
}
else if ((rcTop.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_TOP))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_TOP);
pDockDrag->m_dwDockZone = DS_DOCKED_TOP;
return TRUE;
}
else if ((rcRight.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_RIGHT))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_RIGHT);
pDockDrag->m_dwDockZone = DS_DOCKED_RIGHT;
return TRUE;
}
else if ((rcBottom.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_BOTTOM))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_BOTTOM);
pDockDrag->m_dwDockZone = DS_DOCKED_BOTTOM;
return TRUE;
}
else if ((rcMiddle.PtInRect(pt)) && (IsOverContainer()))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_CONTAINER);
pDockDrag->m_dwDockZone = DS_DOCKED_CONTAINER;
return TRUE;
}
else
return FALSE;
}
////////////////////////////////////////////////////////////////
// Definitions for the CTarget class nested within CDocker
// CTarget is the base class for a number of CTargetXXX classes
inline CDocker::CTarget::~CTarget()
{
}
inline void CDocker::CTarget::OnDraw(CDC* pDC)
{
BITMAP bm = m_bmImage.GetBitmapData();
int cxImage = bm.bmWidth;
int cyImage = bm.bmHeight;
if (m_bmImage)
pDC->DrawBitmap(0, 0, cxImage, cyImage, m_bmImage, RGB(255,0,255));
else
TRACE(_T("Missing docking resource\n"));
}
inline void CDocker::CTarget::PreCreate(CREATESTRUCT &cs)
{
cs.style = WS_POPUP;
cs.dwExStyle = WS_EX_TOPMOST|WS_EX_TOOLWINDOW;
cs.lpszClass = _T("Win32++ DockTargeting");
}
////////////////////////////////////////////////////////////////
// Definitions for the CTargetLeft class nested within CDocker
//
inline BOOL CDocker::CTargetLeft::CheckTarget(LPDRAGPOS pDragPos)
{
CDocker* pDockDrag = (CDocker*)FromHandle(pDragPos->hdr.hwndFrom);
if (NULL == pDockDrag) return FALSE;
CPoint pt = pDragPos->ptPos;
CDocker* pDockTarget = pDockDrag->GetDockFromPoint(pt)->GetTopmostDocker();
if (pDockTarget != pDockDrag->GetDockAncestor())
{
Destroy();
return FALSE;
}
BITMAP bm = m_bmImage.GetBitmapData();
int cxImage = bm.bmWidth;
int cyImage = bm.bmHeight;
if (!IsWindow())
{
Create();
CRect rc = pDockTarget->GetWindowRect();
int yMid = rc.top + (rc.Height() - cyImage)/2;
SetWindowPos(HWND_TOPMOST, rc.left + 10, yMid, cxImage, cyImage, SWP_NOACTIVATE|SWP_SHOWWINDOW);
}
CRect rcLeft(0, 0, cxImage, cyImage);
ScreenToClient(pt);
// Test if our cursor is in one of the docking zones
if ((rcLeft.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_LEFT))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_LEFTMOST);
pDockDrag->m_dwDockZone = DS_DOCKED_LEFTMOST;
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////
// Definitions for the CTargetTop class nested within CDocker
//
inline BOOL CDocker::CTargetTop::CheckTarget(LPDRAGPOS pDragPos)
{
CDocker* pDockDrag = (CDocker*)FromHandle(pDragPos->hdr.hwndFrom);
if (NULL == pDockDrag) return FALSE;
CPoint pt = pDragPos->ptPos;
CDocker* pDockTarget = pDockDrag->GetDockFromPoint(pt)->GetTopmostDocker();
if (pDockTarget != pDockDrag->GetDockAncestor())
{
Destroy();
return FALSE;
}
BITMAP bm = m_bmImage.GetBitmapData();
int cxImage = bm.bmWidth;
int cyImage = bm.bmHeight;
if (!IsWindow())
{
Create();
CRect rc = pDockTarget->GetWindowRect();
int xMid = rc.left + (rc.Width() - cxImage)/2;
SetWindowPos(HWND_TOPMOST, xMid, rc.top + 10, cxImage, cyImage, SWP_NOACTIVATE|SWP_SHOWWINDOW);
}
CRect rcTop(0, 0, cxImage, cyImage);
ScreenToClient(pt);
// Test if our cursor is in one of the docking zones
if ((rcTop.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_TOP))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_TOPMOST);
pDockDrag->m_dwDockZone = DS_DOCKED_TOPMOST;
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////
// Definitions for the CTargetRight class nested within CDocker
//
inline BOOL CDocker::CTargetRight::CheckTarget(LPDRAGPOS pDragPos)
{
CDocker* pDockDrag = (CDocker*)FromHandle(pDragPos->hdr.hwndFrom);
if (NULL == pDockDrag) return FALSE;
CPoint pt = pDragPos->ptPos;
CDocker* pDockTarget = pDockDrag->GetDockFromPoint(pt)->GetTopmostDocker();
if (pDockTarget != pDockDrag->GetDockAncestor())
{
Destroy();
return FALSE;
}
BITMAP bm = m_bmImage.GetBitmapData();
int cxImage = bm.bmWidth;
int cyImage = bm.bmHeight;
if (!IsWindow())
{
Create();
CRect rc = pDockTarget->GetWindowRect();
int yMid = rc.top + (rc.Height() - cyImage)/2;
SetWindowPos(HWND_TOPMOST, rc.right - 10 - cxImage, yMid, cxImage, cyImage, SWP_NOACTIVATE|SWP_SHOWWINDOW);
}
CRect rcRight(0, 0, cxImage, cyImage);
ScreenToClient(pt);
// Test if our cursor is in one of the docking zones
if ((rcRight.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_RIGHT))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_RIGHTMOST);
pDockDrag->m_dwDockZone = DS_DOCKED_RIGHTMOST;
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////
// Definitions for the CTargetBottom class nested within CDocker
//
inline BOOL CDocker::CTargetBottom::CheckTarget(LPDRAGPOS pDragPos)
{
CDocker* pDockDrag = (CDocker*)FromHandle(pDragPos->hdr.hwndFrom);
if (NULL == pDockDrag) return FALSE;
CPoint pt = pDragPos->ptPos;
CDocker* pDockTarget = pDockDrag->GetDockFromPoint(pt)->GetTopmostDocker();
if (pDockTarget != pDockDrag->GetDockAncestor())
{
Destroy();
return FALSE;
}
BITMAP bm = m_bmImage.GetBitmapData();
int cxImage = bm.bmWidth;
int cyImage = bm.bmHeight;
if (!IsWindow())
{
Create();
CRect rc = pDockTarget->GetWindowRect();
int xMid = rc.left + (rc.Width() - cxImage)/2;
SetWindowPos(HWND_TOPMOST, xMid, rc.bottom - 10 - cyImage, cxImage, cyImage, SWP_NOACTIVATE|SWP_SHOWWINDOW);
}
CRect rcBottom(0, 0, cxImage, cyImage);
ScreenToClient(pt);
// Test if our cursor is in one of the docking zones
if ((rcBottom.PtInRect(pt)) && !(pDockTarget->GetDockStyle() & DS_NO_DOCKCHILD_BOTTOM))
{
pDockDrag->m_BlockMove = TRUE;
pDockTarget->GetDockHint().DisplayHint(pDockTarget, pDockDrag, DS_DOCKED_BOTTOMMOST);
pDockDrag->m_dwDockZone = DS_DOCKED_BOTTOMMOST;
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////
// Definitions for the CDocker class
//
inline CDocker::CDocker() : m_pDockParent(NULL), m_pDockActive(NULL), m_BlockMove(FALSE), m_Undocking(FALSE),
m_bIsClosing(FALSE), m_bIsDragging(FALSE), m_bDragAutoResize(TRUE), m_DockStartSize(0), m_nDockID(0),
m_nTimerCount(0), m_NCHeight(0), m_dwDockZone(0), m_DockSizeRatio(1.0), m_DockStyle(0), m_hOldFocus(0)
{
// Assume this docker is the DockAncestor for now.
m_pDockAncestor = this;
}
inline CDocker::~CDocker()
{
GetDockBar().Destroy();
std::vector <DockPtr>::iterator iter;
if (GetDockAncestor() == this)
{
// Destroy all dock descendants of this dock ancestor
for (iter = GetAllDockers().begin(); iter < GetAllDockers().end(); ++iter)
{
(*iter)->Destroy();
}
}
}
inline CDocker* CDocker::AddDockedChild(CDocker* pDocker, DWORD dwDockStyle, int DockSize, int nDockID /* = 0*/)
// This function creates the docker, and adds it to the docker heirachy as docked
{
// Create the docker window as a child of the frame window.
// This pernamently sets the frame window as the docker window's owner,
// even when its parent is subsequently changed.
assert(pDocker);
// Store the Docker's pointer in the DockAncestor's vector for later deletion
GetDockAncestor()->m_vAllDockers.push_back(DockPtr(pDocker));
pDocker->SetDockStyle(dwDockStyle);
pDocker->m_nDockID = nDockID;
pDocker->m_pDockAncestor = GetDockAncestor();
pDocker->m_pDockParent = this;
pDocker->SetDockSize(DockSize);
CWnd* pFrame = GetDockAncestor()->GetAncestor();
pDocker->Create(pFrame);
pDocker->SetParent(this);
// Dock the docker window
if (dwDockStyle & DS_DOCKED_CONTAINER)
DockInContainer(pDocker, dwDockStyle);
else
Dock(pDocker, dwDockStyle);
// Issue TRACE warnings for any missing resources
HMODULE hMod= GetApp()->GetResourceHandle();
if (!(dwDockStyle & DS_NO_RESIZE))
{
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SPLITH), RT_GROUP_CURSOR))
TRACE(_T("**WARNING** Horizontal cursor resource missing\n"));
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SPLITV), RT_GROUP_CURSOR))
TRACE(_T("**WARNING** Vertical cursor resource missing\n"));
}
if (!(dwDockStyle & DS_NO_UNDOCK))
{
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SDCENTER), RT_BITMAP))
TRACE(_T("**WARNING** Docking center bitmap resource missing\n"));
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SDLEFT), RT_BITMAP))
TRACE(_T("**WARNING** Docking left bitmap resource missing\n"));
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SDRIGHT), RT_BITMAP))
TRACE(_T("**WARNING** Docking right bitmap resource missing\n"));
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SDTOP), RT_BITMAP))
TRACE(_T("**WARNING** Docking top bitmap resource missing\n"));
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SDBOTTOM), RT_BITMAP))
TRACE(_T("**WARNING** Docking center bottom resource missing\n"));
}
if (dwDockStyle & DS_DOCKED_CONTAINER)
{
if (!FindResource(hMod, MAKEINTRESOURCE(IDW_SDMIDDLE), RT_BITMAP))
TRACE(_T("**WARNING** Docking container bitmap resource missing\n"));
}
return pDocker;
}
inline CDocker* CDocker::AddUndockedChild(CDocker* pDocker, DWORD dwDockStyle, int DockSize, RECT rc, int nDockID /* = 0*/)
// This function creates the docker, and adds it to the docker heirachy as undocked
{
assert(pDocker);
// Store the Docker's pointer in the DockAncestor's vector for later deletion
GetDockAncestor()->m_vAllDockers.push_back(DockPtr(pDocker));
pDocker->SetDockSize(DockSize);
pDocker->SetDockStyle(dwDockStyle & 0XFFFFFF0);
pDocker->m_nDockID = nDockID;
pDocker->m_pDockAncestor = GetDockAncestor();
// Initially create the as a child window of the frame
// This makes the frame window the owner of our docker
CWnd* pFrame = GetDockAncestor()->GetAncestor();
pDocker->Create(pFrame);
pDocker->SetParent(this);
// Change the Docker to a POPUP window
DWORD dwStyle = WS_POPUP| WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_VISIBLE;
pDocker->SetWindowLongPtr(GWL_STYLE, dwStyle);
pDocker->SetRedraw(FALSE);
pDocker->SetParent(0);
pDocker->SetWindowPos(HWND_TOP, rc, SWP_SHOWWINDOW|SWP_FRAMECHANGED);
pDocker->SetRedraw(TRUE);
pDocker->RedrawWindow(0, 0, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_ALLCHILDREN);
pDocker->SetWindowText(pDocker->GetCaption().c_str());
return pDocker;
}
inline void CDocker::CheckAllTargets(LPDRAGPOS pDragPos)
// Calls CheckTarget for each possible target zone
{
if (!GetDockAncestor()->m_TargetCentre.CheckTarget(pDragPos))
{
if (!GetDockAncestor()->m_TargetLeft.CheckTarget(pDragPos))
{
if(!GetDockAncestor()->m_TargetTop.CheckTarget(pDragPos))
{
if(!GetDockAncestor()->m_TargetRight.CheckTarget(pDragPos))
{
if(!GetDockAncestor()->m_TargetBottom.CheckTarget(pDragPos))
{
// Not in a docking zone, so clean up
NMHDR nmhdr = pDragPos->hdr;
CDocker* pDockDrag = (CDocker*)FromHandle(nmhdr.hwndFrom);
if (pDockDrag)
{
if (pDockDrag->m_BlockMove)
pDockDrag->RedrawWindow(0, 0, RDW_FRAME|RDW_INVALIDATE);
GetDockHint().Destroy();
pDockDrag->m_dwDockZone = 0;
pDockDrag->m_BlockMove = FALSE;
}
}
}
}
}
}
}
inline BOOL CDocker::VerifyDockers()
// A diagnostic routine which verifies the integrity of the docking layout
{
BOOL bResult = TRUE;
// Check dock ancestor
std::vector<DockPtr>::iterator iter;
for (iter = GetAllDockers().begin(); iter != GetAllDockers().end(); ++iter)
{
if (GetDockAncestor() != (*iter)->m_pDockAncestor)
{
TRACE(_T("Invalid Dock Ancestor\n"));
bResult = FALSE;
}
}
// Check presence of dock parent
for (iter = GetAllDockers().begin(); iter != GetAllDockers().end(); ++iter)
{
if ((*iter)->IsUndocked() && (*iter)->m_pDockParent != 0)
{
TRACE(_T("Error: Undocked dockers should not have a dock parent\n"));
bResult = FALSE;
}
if ((*iter)->IsDocked() && (*iter)->m_pDockParent == 0)
{
TRACE(_T("Error: Docked dockers should have a dock parent\n"));
bResult = FALSE;
}
}
// Check dock parent/child relationship
for (iter = GetAllDockers().begin(); iter != GetAllDockers().end(); ++iter)
{
std::vector<CDocker*>::iterator iterChild;
for (iterChild = (*iter)->GetDockChildren().begin(); iterChild != (*iter)->GetDockChildren().end(); ++iterChild)
{
if ((*iterChild)->m_pDockParent != (*iter).get())
{
TRACE(_T("Error: Docking parent/Child information mismatch\n"));
bResult = FALSE;
}
if ((*iterChild)->GetParent() != (*iter).get())
{
TRACE(_T("Error: Incorrect windows child parent relationship\n"));
bResult = FALSE;
}
}
}
// Check dock parent chain
for (iter = GetAllDockers().begin(); iter != GetAllDockers().end(); ++iter)
{
CDocker* pDockTopLevel = (*iter)->GetTopmostDocker();
if (pDockTopLevel->IsDocked())
TRACE(_T("Error: Top level parent should be undocked\n"));
}
return bResult;
}
inline void CDocker::Close()
{
// Destroy the docker
Hide();
Destroy();
}
inline void CDocker::CloseAllDockers()
{
assert(this == GetDockAncestor()); // Must call CloseAllDockers from the DockAncestor
std::vector <DockPtr>::iterator v;
SetRedraw(FALSE);
std::vector<DockPtr> AllDockers = GetAllDockers();
for (v = AllDockers.begin(); v != AllDockers.end(); ++v)
{
// The CDocker is destroyed when the window is destroyed
(*v)->m_bIsClosing = TRUE;
(*v)->Destroy(); // Destroy the window
}
GetDockChildren().clear();
SetRedraw(TRUE);
RecalcDockLayout();
}
inline void CDocker::CloseAllTargets()
{
GetDockAncestor()->m_TargetCentre.Destroy();
GetDockAncestor()->m_TargetLeft.Destroy();
GetDockAncestor()->m_TargetTop.Destroy();
GetDockAncestor()->m_TargetRight.Destroy();
GetDockAncestor()->m_TargetBottom.Destroy();
}
inline void CDocker::Dock(CDocker* pDocker, UINT DockStyle)
// Docks the specified docker inside this docker
{
assert(pDocker);
pDocker->m_pDockParent = this;
pDocker->m_BlockMove = FALSE;
pDocker->SetDockStyle(DockStyle);
m_vDockChildren.push_back(pDocker);
pDocker->ConvertToChild(m_hWnd);
// Limit the docked size to half the parent's size if it won't fit inside parent
if (((DockStyle & 0xF) == DS_DOCKED_LEFT) || ((DockStyle &0xF) == DS_DOCKED_RIGHT))
{
int Width = GetDockClient().GetWindowRect().Width();
int BarWidth = pDocker->GetBarWidth();
if (pDocker->m_DockStartSize >= (Width - BarWidth))
pDocker->SetDockSize(MAX(Width/2 - BarWidth, BarWidth));
pDocker->m_DockSizeRatio = ((double)pDocker->m_DockStartSize) / (double)GetWindowRect().Width();
}
else
{
int Height = GetDockClient().GetWindowRect().Height();
int BarWidth = pDocker->GetBarWidth();
if (pDocker->m_DockStartSize >= (Height - BarWidth))
pDocker->SetDockSize(MAX(Height/2 - BarWidth, BarWidth));
pDocker->m_DockSizeRatio = ((double)pDocker->m_DockStartSize) / (double)GetWindowRect().Height();
}
// Redraw the docked windows
GetAncestor()->SetForegroundWindow();
GetTopmostDocker()->m_hOldFocus = pDocker->GetView()->GetHwnd();
pDocker->GetView()->SetFocus();
GetTopmostDocker()->SetRedraw(FALSE);
RecalcDockLayout();
GetTopmostDocker()->SetRedraw(TRUE);
GetTopmostDocker()->RedrawWindow();
}
inline void CDocker::DockInContainer(CDocker* pDock, DWORD dwDockStyle)
// Add a container to an existing container
{
if ((dwDockStyle & DS_DOCKED_CONTAINER) && (dynamic_cast<CDockContainer*>(pDock->GetView())))
{
// Transfer any dock children to this docker
pDock->MoveDockChildren(this);
// Transfer container children to the target container
CDockContainer* pContainer = (CDockContainer*)GetView();
CDockContainer* pContainerSource = (CDockContainer*)pDock->GetView();
if (pContainerSource->GetAllContainers().size() > 1)
{
// The container we're about to add has children, so transfer those first
std::vector<ContainerInfo>::reverse_iterator riter;
std::vector<ContainerInfo> AllContainers = pContainerSource->GetAllContainers();
for ( riter = AllContainers.rbegin() ; riter < AllContainers.rend() -1; ++riter )
{
// Remove child container from pContainerSource
CDockContainer* pContainerChild = (*riter).pContainer;
pContainerChild->ShowWindow(SW_HIDE);
pContainerSource->RemoveContainer(pContainerChild);
// Add child container to this container
pContainer->AddContainer(pContainerChild);
CDocker* pDockChild = GetDockFromView(pContainerChild);
pDockChild->SetParent(this);
pDockChild->m_pDockParent = this;
}
}
pContainer->AddContainer((CDockContainer*)pDock->GetView());
pDock->m_pDockParent = this;
pDock->m_BlockMove = FALSE;
pDock->ShowWindow(SW_HIDE);
pDock->SetWindowLongPtr(GWL_STYLE, WS_CHILD);
pDock->SetDockStyle(dwDockStyle);
pDock->SetParent(this);
}
}
inline void CDocker::DockOuter(CDocker* pDocker, DWORD dwDockStyle)
// Docks the specified docker inside the dock ancestor
{
assert(pDocker);
pDocker->m_pDockParent = GetDockAncestor();
DWORD OuterDocking = dwDockStyle & 0xF0000;
DWORD DockSide = OuterDocking / 0x10000;
dwDockStyle &= 0xFFF0FFFF;
dwDockStyle |= DockSide;
// Set the dock styles
DWORD dwStyle = WS_CHILD | WS_VISIBLE;
pDocker->m_BlockMove = FALSE;
pDocker->SetWindowLongPtr(GWL_STYLE, dwStyle);
pDocker->ShowWindow(SW_HIDE);
pDocker->SetDockStyle(dwDockStyle);
// Set the docking relationships
std::vector<CDocker*>::iterator iter = GetDockAncestor()->m_vDockChildren.begin();
GetDockAncestor()->m_vDockChildren.insert(iter, pDocker);
pDocker->SetParent(GetDockAncestor());
pDocker->GetDockBar().SetParent(GetDockAncestor());
// Limit the docked size to half the parent's size if it won't fit inside parent
if (((dwDockStyle & 0xF) == DS_DOCKED_LEFT) || ((dwDockStyle &0xF) == DS_DOCKED_RIGHT))
{
int Width = GetDockAncestor()->GetDockClient().GetWindowRect().Width();
int BarWidth = pDocker->GetBarWidth();
if (pDocker->m_DockStartSize >= (Width - BarWidth))
pDocker->SetDockSize(MAX(Width/2 - BarWidth, BarWidth));
pDocker->m_DockSizeRatio = ((double)pDocker->m_DockStartSize) / (double)GetDockAncestor()->GetWindowRect().Width();
}
else
{
int Height = GetDockAncestor()->GetDockClient().GetWindowRect().Height();
int BarWidth = pDocker->GetBarWidth();
if (pDocker->m_DockStartSize >= (Height - BarWidth))
pDocker->SetDockSize(MAX(Height/2 - BarWidth, BarWidth));
pDocker->m_DockSizeRatio = ((double)pDocker->m_DockStartSize) / (double)GetDockAncestor()->GetWindowRect().Height();
}
// Redraw the docked windows
GetAncestor()->SetFocus();
pDocker->GetView()->SetFocus();
RecalcDockLayout();
}
inline void CDocker::DrawAllCaptions()
{
std::vector<DockPtr>::iterator iter;
for (iter = GetAllDockers().begin(); iter != GetAllDockers().end(); iter++)
{
if ((*iter)->IsDocked())
(*iter)->GetDockClient().DrawCaption((WPARAM)1);
}
}
inline void CDocker::DrawHashBar(HWND hBar, POINT Pos)
// Draws a hashed bar while the splitter bar is being dragged
{
CDocker* pDock = ((CDockBar*)FromHandle(hBar))->GetDock();
if (NULL == pDock) return;
BOOL bVertical = ((pDock->GetDockStyle() & 0xF) == DS_DOCKED_LEFT) || ((pDock->GetDockStyle() & 0xF) == DS_DOCKED_RIGHT);
CClientDC dcBar(this);
WORD HashPattern[] = {0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA};
CBitmap bmHash;
CBrush brDithered;
bmHash.CreateBitmap(8, 8, 1, 1, HashPattern);
brDithered.CreatePatternBrush(&bmHash);
dcBar.SelectObject(&brDithered);
CRect rc = FromHandle(hBar)->GetWindowRect();
ScreenToClient(rc);
int cx = rc.Width();
int cy = rc.Height();
int BarWidth = pDock->GetDockBar().GetWidth();
if (bVertical)
dcBar.PatBlt(Pos.x - BarWidth/2, rc.top, BarWidth, cy, PATINVERT);
else
dcBar.PatBlt(rc.left, Pos.y - BarWidth/2, cx, BarWidth, PATINVERT);
}
inline CDockContainer* CDocker::GetContainer() const
{
CDockContainer* pContainer = NULL;
if (dynamic_cast<CDockContainer*>(GetView()))
pContainer = (CDockContainer*)GetView();
return pContainer;
}
inline CDocker* CDocker::GetActiveDocker() const
// Returns the docker whose child window has focus
{
CWnd* pWnd = GetFocus();
CDocker* pDock= NULL;
while (pWnd && (pDock == NULL))
{
if (IsRelated(pWnd))
pDock = (CDocker*)pWnd;
pWnd = pWnd->GetParent();
}
return pDock;
}
inline CDocker* CDocker::GetDockAncestor() const
// The GetDockAncestor function retrieves the pointer to the
// ancestor (root docker parent) of the Docker.
{
return m_pDockAncestor;
}
inline CDocker* CDocker::GetDockFromPoint(POINT pt) const
// Retrieves the Docker whose view window contains the specified point
{
// Step 1: Find the top level Docker the point is over
CDocker* pDockTop = NULL;
CWnd* pAncestor = GetDockAncestor()->GetAncestor();
// Iterate through all top level windows
CWnd* pWnd = GetWindow(GW_HWNDFIRST);
while(pWnd)
{
if (IsRelated(pWnd) || pWnd == pAncestor)
{
CDocker* pDockTest;
if (pWnd == pAncestor)
pDockTest = GetDockAncestor();
else
pDockTest = (CDocker*)pWnd;
CRect rc = pDockTest->GetClientRect();
pDockTest->ClientToScreen(rc);
if ((this != pDockTest) && rc.PtInRect(pt))
{
pDockTop = pDockTest;
break;
}
}
pWnd = pWnd->GetWindow(GW_HWNDNEXT);
}
// Step 2: Find the docker child whose view window has the point
CDocker* pDockTarget = NULL;
if (pDockTop)
{
CDocker* pDockParent = pDockTop;
CDocker* pDockTest = pDockParent;
while (IsRelated(pDockTest))
{
pDockParent = pDockTest;
CPoint ptLocal = pt;
pDockParent->ScreenToClient(ptLocal);
pDockTest = (CDocker*)pDockParent->ChildWindowFromPoint(ptLocal);
assert (pDockTest != pDockParent);
}
CRect rc = pDockParent->GetDockClient().GetWindowRect();
if (rc.PtInRect(pt)) pDockTarget = pDockParent;
}
return pDockTarget;
}
inline CDocker* CDocker::GetDockFromID(int n_DockID) const
{
std::vector <DockPtr>::iterator v;
if (GetDockAncestor())
{
for (v = GetDockAncestor()->m_vAllDockers.begin(); v != GetDockAncestor()->m_vAllDockers.end(); v++)
{
if (n_DockID == (*v)->GetDockID())
return (*v).get();
}
}
return 0;
}
inline CDocker* CDocker::GetDockFromView(CWnd* pView) const
{
CDocker* pDock = 0;
std::vector<DockPtr>::iterator iter;
std::vector<DockPtr> AllDockers = GetAllDockers();
for (iter = AllDockers.begin(); iter != AllDockers.end(); ++iter)
{
if ((*iter)->GetView() == pView)
pDock = (*iter).get();
}
return pDock;
}
inline int CDocker::GetDockSize() const
{
// Returns the size of the docker to be used if it is redocked
// Note: This function returns 0 if the docker has the DS_DOCKED_CONTAINER style
CRect rcParent;
if (GetDockParent())
rcParent = GetDockParent()->GetWindowRect();
else
rcParent = GetDockAncestor()->GetWindowRect();
double DockSize = 0;
if ((GetDockStyle() & DS_DOCKED_LEFT) || (GetDockStyle() & DS_DOCKED_RIGHT))
DockSize = (double)(rcParent.Width()*m_DockSizeRatio);
else if ((GetDockStyle() & DS_DOCKED_TOP) || (GetDockStyle() & DS_DOCKED_BOTTOM))
DockSize = (double)(rcParent.Height()*m_DockSizeRatio);
else if ((GetDockStyle() & DS_DOCKED_CONTAINER))
DockSize = 0;
return (int)DockSize;
}
inline CDocker* CDocker::GetTopmostDocker() const
// Returns the docker's parent at the top of the Z order.
// Could be the dock ancestor or an undocked docker.
{
CDocker* pDockTopLevel = (CDocker* const)this;
while(pDockTopLevel->GetDockParent())
{
assert (pDockTopLevel != pDockTopLevel->GetDockParent());
pDockTopLevel = pDockTopLevel->GetDockParent();
}
return pDockTopLevel;
}
inline CTabbedMDI* CDocker::GetTabbedMDI() const
{
CTabbedMDI* pTabbedMDI = NULL;
if (dynamic_cast<CTabbedMDI*>(GetView()))
pTabbedMDI = (CTabbedMDI*)GetView();
return pTabbedMDI;
}
inline int CDocker::GetTextHeight()
{
NONCLIENTMETRICS nm = {0};
nm.cbSize = GetSizeofNonClientMetrics();
SystemParametersInfo (SPI_GETNONCLIENTMETRICS, 0, &nm, 0);
LOGFONT lf = nm.lfStatusFont;
CClientDC dc(this);
dc.CreateFontIndirect(&lf);
CSize szText = dc.GetTextExtentPoint32(_T("Text"), lstrlen(_T("Text")));
return szText.cy;
}
inline void CDocker::Hide()
{
// Undocks a docker (if needed) and hides it.
// Do unhide the docker, dock it.
if (IsDocked())
{
if (dynamic_cast<CDockContainer*>(GetView()))
{
CDockContainer* pContainer = GetContainer();
CDocker* pDock = GetDockFromView(pContainer->GetContainerParent());
pDock->UndockContainer(pContainer, GetCursorPos(), FALSE);
}
else
{
CDocker* pDockUndockedFrom = SeparateFromDock();
pDockUndockedFrom->RecalcDockLayout();
}
}
ShowWindow(SW_HIDE);
}
inline BOOL CDocker::IsChildOfDocker(CWnd* pWnd) const
// returns true if the specified window is a child of this docker
{
while ((pWnd != NULL) && (pWnd != GetDockAncestor()))
{
if (pWnd == (CWnd*)this) return TRUE;
if (IsRelated(pWnd)) break;
pWnd = pWnd->GetParent();
}
return FALSE;
}
inline BOOL CDocker::IsDocked() const
{
return (((m_DockStyle&0xF) || (m_DockStyle & DS_DOCKED_CONTAINER)) && !m_Undocking); // Boolean expression
}
inline BOOL CDocker::IsDragAutoResize()
{
return m_bDragAutoResize;
}
inline BOOL CDocker::IsRelated(CWnd* pWnd) const
// Returns TRUE if the hWnd is a docker within this dock family
{
if (GetDockAncestor() == pWnd) return TRUE;
std::vector<DockPtr>::iterator iter;
for (iter = GetAllDockers().begin(); iter < GetAllDockers().end(); ++iter)
{
if ((*iter).get() == pWnd) return TRUE;
}
return FALSE;
}
inline BOOL CDocker::IsUndocked() const
{
return (!((m_DockStyle&0xF)|| (m_DockStyle & DS_DOCKED_CONTAINER)) && !m_Undocking); // Boolean expression
}
inline BOOL CDocker::LoadRegistrySettings(tString tsRegistryKeyName)
// Recreates the docker layout based on information stored in the registry.
// Assumes the DockAncestor window is already created.
{
BOOL bResult = FALSE;
if (0 != tsRegistryKeyName.size())
{
std::vector<DockInfo> vDockList;
std::vector<int> vActiveContainers;
tString tsKey = _T("Software\\") + tsRegistryKeyName + _T("\\Dock Windows");
HKEY hKey = 0;
RegOpenKeyEx(HKEY_CURRENT_USER, tsKey.c_str(), 0, KEY_READ, &hKey);
if (hKey)
{
DWORD dwType = REG_BINARY;
DWORD BufferSize = sizeof(DockInfo);
DockInfo di;
int i = 0;
TCHAR szNumber[20];
tString tsSubKey = _T("DockChild");
tsSubKey += _itot(i, szNumber, 10);
// Fill the DockList vector from the registry
while (0 == RegQueryValueEx(hKey, tsSubKey.c_str(), NULL, &dwType, (LPBYTE)&di, &BufferSize))
{
vDockList.push_back(di);
i++;
tsSubKey = _T("DockChild");
tsSubKey += _itot(i, szNumber, 10);
}
dwType = REG_DWORD;
BufferSize = sizeof(int);
int nID;
i = 0;
tsSubKey = _T("ActiveContainer");
tsSubKey += _itot(i, szNumber, 10);
// Fill the DockList vector from the registry
while (0 == RegQueryValueEx(hKey, tsSubKey.c_str(), NULL, &dwType, (LPBYTE)&nID, &BufferSize))
{
vActiveContainers.push_back(nID);
i++;
tsSubKey = _T("ActiveContainer");
tsSubKey += _itot(i, szNumber, 10);
}
RegCloseKey(hKey);
if (vDockList.size() > 0) bResult = TRUE;
}
// Add dockers without parents first
std::vector<DockInfo>::iterator iter;
for (iter = vDockList.begin(); iter < vDockList.end() ; ++iter)
{
DockInfo di = (*iter);
if (di.DockParentID == 0)
{
CDocker* pDocker = NewDockerFromID(di.DockID);
if (pDocker)
{
if (di.DockStyle & 0xF)
AddDockedChild(pDocker, di.DockStyle, di.DockSize, di.DockID);
else
AddUndockedChild(pDocker, di.DockStyle, di.DockSize, di.Rect, di.DockID);
}
else
{
TRACE(_T("Failed to add dockers without parents from registry"));
bResult = FALSE;
}
}
}
// Remove dockers without parents from vDockList
for (UINT n = (UINT)vDockList.size(); n > 0; --n)
{
iter = vDockList.begin() + n-1;
if ((*iter).DockParentID == 0)
vDockList.erase(iter);
}
// Add remaining dockers
while (vDockList.size() > 0)
{
bool bFound = false;
std::vector<DockInfo>::iterator iter;
for (iter = vDockList.begin(); iter < vDockList.end(); ++iter)
{
DockInfo di = *iter;
CDocker* pDockParent = GetDockFromID(di.DockParentID);
if (pDockParent != 0)
{
CDocker* pDock = NewDockerFromID(di.DockID);
if(pDock)
{
pDockParent->AddDockedChild(pDock, di.DockStyle, di.DockSize, di.DockID);
bFound = true;
}
else
{
TRACE(_T("Failed to add dockers with parents from registry"));
bResult = FALSE;
}
vDockList.erase(iter);
break;
}
}
if (!bFound)
{
TRACE(_T("Orphaned dockers stored in registry "));
bResult = FALSE;
break;
}
}
std::vector<int>::iterator iterID;
for (iterID = vActiveContainers.begin(); iterID < vActiveContainers.end(); ++iterID)
{
CDocker* pDocker = GetDockFromID(*iterID);
if (pDocker)
{
CDockContainer* pContainer = pDocker->GetContainer();
if (pContainer)
{
int nPage = pContainer->GetContainerIndex(pContainer);
if (nPage >= 0)
pContainer->SelectPage(nPage);
}
}
}
}
if (!bResult) CloseAllDockers();
return bResult;
}
inline void CDocker::MoveDockChildren(CDocker* pDockTarget)
// Used internally by Dock and Undock
{
assert(pDockTarget);
// Transfer any dock children from the current docker to the target docker
std::vector<CDocker*>::iterator iter;
for (iter = GetDockChildren().begin(); iter < GetDockChildren().end(); ++iter)
{
pDockTarget->GetDockChildren().push_back(*iter);
(*iter)->m_pDockParent = pDockTarget;
(*iter)->SetParent(pDockTarget);
(*iter)->GetDockBar().SetParent(pDockTarget);
}
GetDockChildren().clear();
}
inline CDocker* CDocker::NewDockerFromID(int nID)
// Used in LoadRegistrySettings. Creates a new Docker from the specified ID
{
UNREFERENCED_PARAMETER(nID);
// Override this function to create the Docker objects as shown below
CDocker* pDock = NULL;
/* switch(nID)
{
case ID_CLASSES:
pDock = new CDockClasses;
break;
case ID_FILES:
pDock = new CDockFiles;
break;
default:
TRACE(_T("Unknown Dock ID\n"));
break;
} */
return pDock;
}
inline void CDocker::OnActivate(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
// Only top level undocked dockers get this message
if (LOWORD(wParam) == WA_INACTIVE)
{
GetTopmostDocker()->m_hOldFocus = ::GetFocus();
// Send a notification of focus lost
int idCtrl = ::GetDlgCtrlID(m_hOldFocus);
NMHDR nhdr={0};
nhdr.hwndFrom = m_hOldFocus;
nhdr.idFrom = idCtrl;
nhdr.code = UWM_FRAMELOSTFOCUS;
SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nhdr);
}
}
inline void CDocker::OnCaptionTimer(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
if (this == GetDockAncestor())
{
if (wParam == 1)
{
DrawAllCaptions();
m_nTimerCount++;
if (m_nTimerCount == 10)
{
KillTimer(wParam);
m_nTimerCount = 0;
}
}
}
}
inline void CDocker::OnCreate()
{
#if defined(WINVER) && defined (WS_EX_LAYOUTRTL) && (WINVER >= 0x0500)
if (GetParent()->GetWindowLongPtr(GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
{
DWORD dwExStyle = GetWindowLongPtr(GWL_EXSTYLE);
SetWindowLongPtr(GWL_EXSTYLE, dwExStyle | WS_EX_LAYOUTRTL);
}
#endif
// Create the various child windows
GetDockClient().SetDock(this);
GetDockClient().Create(this);
assert(GetView()); // Use SetView in CMainFrame's constructor to set the view window
GetView()->Create(&GetDockClient());
// Create the slider bar belonging to this docker
GetDockBar().SetDock(this);
if (GetDockAncestor() != this)
GetDockBar().Create(GetParent());
// Now remove the WS_POPUP style. It was required to allow this window
// to be owned by the frame window.
SetWindowLongPtr(GWL_STYLE, WS_CHILD);
SetParent(GetParent()); // Reinstate the window's parent
// Set the default colour for the splitter bar
COLORREF rgbColour = GetSysColor(COLOR_BTNFACE);
CWnd* pFrame = GetDockAncestor()->GetAncestor();
ReBarTheme* pTheme = (ReBarTheme*)pFrame->SendMessage(UWM_GETREBARTHEME, 0, 0);
if (pTheme && pTheme->UseThemes && pTheme->clrBkgnd2 != 0)
rgbColour =pTheme->clrBkgnd2;
SetBarColor(rgbColour);
// Set the caption height based on text height
m_NCHeight = MAX(20, GetTextHeight() + 5);
}
inline void CDocker::OnDestroy(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
// Destroy any dock children first
std::vector<CDocker*>::iterator iter;
for (iter = GetDockChildren().begin(); iter < GetDockChildren().end(); ++iter)
{
(*iter)->Destroy();
}
if (dynamic_cast<CDockContainer*>(GetView()) && IsUndocked())
{
CDockContainer* pContainer = (CDockContainer*)GetView();
if (pContainer->GetAllContainers().size() > 1)
{
// This container has children, so destroy them now
std::vector<ContainerInfo> AllContainers = pContainer->GetAllContainers();
std::vector<ContainerInfo>::iterator iter;
for (iter = AllContainers.begin(); iter < AllContainers.end(); ++iter)
{
if ((*iter).pContainer != pContainer)
{
// Reset container parent before destroying the dock window
CDocker* pDock = GetDockFromView((*iter).pContainer);
if (pContainer->IsWindow())
pContainer->SetParent(&pDock->GetDockClient());
pDock->Destroy();
}
}
}
}
GetDockBar().Destroy();
// Post a destroy docker message
if ( GetDockAncestor()->IsWindow() )
GetDockAncestor()->PostMessage(UWM_DOCK_DESTROYED, (WPARAM)this, 0L);
}
inline void CDocker::OnDockDestroyed(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
CDocker* pDock = (CDocker*)wParam;
assert( this == GetDockAncestor() );
std::vector<DockPtr>::iterator iter;
for (iter = GetAllDockers().begin(); iter < GetAllDockers().end(); ++iter)
{
if ((*iter).get() == pDock)
{
GetAllDockers().erase(iter);
break;
}
}
}
inline void CDocker::OnExitSizeMove(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
m_BlockMove = FALSE;
m_bIsDragging = FALSE;
SendNotify(UWM_DOCK_END);
}
inline LRESULT CDocker::OnNotify(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
LPDRAGPOS pdp = (LPDRAGPOS)lParam;
switch (((LPNMHDR)lParam)->code)
{
case UWM_DOCK_START:
{
if (IsDocked())
{
Undock(GetCursorPos());
SendMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(pdp->ptPos.x, pdp->ptPos.y));
}
}
break;
case UWM_DOCK_MOVE:
{
CheckAllTargets((LPDRAGPOS)lParam);
}
break;
case UWM_DOCK_END:
{
CDocker* pDock = (CDocker*)FromHandle(pdp->hdr.hwndFrom);
if (NULL == pDock) break;
UINT DockZone = pdp->DockZone;
CRect rc = pDock->GetWindowRect();
switch(DockZone)
{
case DS_DOCKED_LEFT:
case DS_DOCKED_RIGHT:
pDock->SetDockSize(rc.Width());
Dock(pDock, pDock->GetDockStyle() | DockZone);
break;
case DS_DOCKED_TOP:
case DS_DOCKED_BOTTOM:
pDock->SetDockSize(rc.Height());
Dock(pDock, pDock->GetDockStyle() | DockZone);
break;
case DS_DOCKED_CONTAINER:
{
DockInContainer(pDock, pDock->GetDockStyle() | DockZone);
CDockContainer* pContainer = (CDockContainer*)GetView();
int nPage = pContainer->GetContainerIndex((CDockContainer*)pDock->GetView());
pContainer->SelectPage(nPage);
}
break;
case DS_DOCKED_LEFTMOST:
case DS_DOCKED_RIGHTMOST:
pDock->SetDockSize(rc.Width());
DockOuter(pDock, pDock->GetDockStyle() | DockZone);
break;
case DS_DOCKED_TOPMOST:
case DS_DOCKED_BOTTOMMOST:
pDock->SetDockSize(rc.Height());
DockOuter(pDock, pDock->GetDockStyle() | DockZone);
break;
}
GetDockHint().Destroy();
CloseAllTargets();
}
break;
case UWM_BAR_START:
{
CPoint pt = pdp->ptPos;
ScreenToClient(pt);
if (!IsDragAutoResize())
DrawHashBar(pdp->hdr.hwndFrom, pt);
m_OldPoint = pt;
}
break;
case UWM_BAR_MOVE:
{
CPoint pt = pdp->ptPos;
ScreenToClient(pt);
if (pt != m_OldPoint)
{
if (IsDragAutoResize())
ResizeDockers(pdp);
else
{
DrawHashBar(pdp->hdr.hwndFrom, m_OldPoint);
DrawHashBar(pdp->hdr.hwndFrom, pt);
}
m_OldPoint = pt;
}
}
break;
case UWM_BAR_END:
{
POINT pt = pdp->ptPos;
ScreenToClient(pt);
if (!IsDragAutoResize())
DrawHashBar(pdp->hdr.hwndFrom, pt);
ResizeDockers(pdp);
}
break;
case NM_SETFOCUS:
if (GetDockAncestor()->IsWindow())
GetDockAncestor()->PostMessage(UWM_DOCK_ACTIVATED, 0, 0);
break;
case UWM_FRAMEGOTFOCUS:
if (GetDockAncestor()->IsWindow())
GetDockAncestor()->PostMessage(UWM_DOCK_ACTIVATED, 0, 0);
if (GetView()->IsWindow())
GetView()->SendMessage(WM_NOTIFY, wParam, lParam);
break;
case UWM_FRAMELOSTFOCUS:
if (GetDockAncestor()->IsWindow())
GetDockAncestor()->PostMessage(UWM_DOCK_ACTIVATED, 0, 0);
if (GetView()->IsWindow())
GetView()->SendMessage(WM_NOTIFY, wParam, lParam);
break;
}
return 0L;
}
inline void CDocker::ResizeDockers(LPDRAGPOS pdp)
// Called when the docker's splitter bar is dragged
{
assert(pdp);
POINT pt = pdp->ptPos;
ScreenToClient(pt);
CDocker* pDock = ((CDockBar*)FromHandle(pdp->hdr.hwndFrom))->GetDock();
if (NULL == pDock) return;
RECT rcDock = pDock->GetWindowRect();
ScreenToClient(rcDock);
double dBarWidth = pDock->GetDockBar().GetWidth();
int iBarWidth = pDock->GetDockBar().GetWidth();
int DockSize;
switch (pDock->GetDockStyle() & 0xF)
{
case DS_DOCKED_LEFT:
DockSize = MAX(pt.x, iBarWidth/2) - rcDock.left - (int)(.5* dBarWidth);
DockSize = MAX(-iBarWidth, DockSize);
pDock->SetDockSize(DockSize);
pDock->m_DockSizeRatio = ((double)pDock->m_DockStartSize)/((double)pDock->m_pDockParent->GetWindowRect().Width());
break;
case DS_DOCKED_RIGHT:
DockSize = rcDock.right - MAX(pt.x, iBarWidth/2) - (int)(.5* dBarWidth);
DockSize = MAX(-iBarWidth, DockSize);
pDock->SetDockSize(DockSize);
pDock->m_DockSizeRatio = ((double)pDock->m_DockStartSize)/((double)pDock->m_pDockParent->GetWindowRect().Width());
break;
case DS_DOCKED_TOP:
DockSize = MAX(pt.y, iBarWidth/2) - rcDock.top - (int)(.5* dBarWidth);
DockSize = MAX(-iBarWidth, DockSize);
pDock->SetDockSize(DockSize);
pDock->m_DockSizeRatio = ((double)pDock->m_DockStartSize)/((double)pDock->m_pDockParent->GetWindowRect().Height());
break;
case DS_DOCKED_BOTTOM:
DockSize = rcDock.bottom - MAX(pt.y, iBarWidth/2) - (int)(.5* dBarWidth);
DockSize = MAX(-iBarWidth, DockSize);
pDock->SetDockSize(DockSize);
pDock->m_DockSizeRatio = ((double)pDock->m_DockStartSize)/((double)pDock->m_pDockParent->GetWindowRect().Height());
break;
}
RecalcDockLayout();
}
inline void CDocker::OnSetFocus(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
if (IsUndocked() && m_hOldFocus)
::SetFocus(m_hOldFocus);
else
// Pass focus on the the view window
GetView()->SetFocus();
if ((this == GetTopmostDocker()) && (this != GetDockAncestor()))
{
// Send a notification to top level window
int idCtrl = ::GetDlgCtrlID(m_hOldFocus);
NMHDR nhdr={0};
nhdr.hwndFrom = m_hOldFocus;
nhdr.idFrom = idCtrl;
nhdr.code = NM_SETFOCUS;
SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nhdr);
}
}
inline void CDocker::OnSysColorChange(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
if (this == GetDockAncestor())
{
COLORREF rgbColour = GetSysColor(COLOR_BTNFACE);
CWnd* pFrame = GetDockAncestor()->GetAncestor();
ReBarTheme* pTheme = (ReBarTheme*)pFrame->SendMessage(UWM_GETREBARTHEME, 0, 0);
if (pTheme && pTheme->UseThemes && pTheme->clrBand2 != 0)
rgbColour = pTheme->clrBkgnd2;
else
rgbColour = GetSysColor(COLOR_BTNFACE);
// Set the splitter bar colour for each docker decendant
std::vector<DockPtr>::iterator iter;
for (iter = GetAllDockers().begin(); iter < GetAllDockers().end(); ++iter)
(*iter)->SetBarColor(rgbColour);
// Set the splitter bar colour for the docker ancestor
SetBarColor(rgbColour);
}
}
inline LRESULT CDocker::OnSysCommand(WPARAM wParam, LPARAM lParam)
{
switch(wParam&0xFFF0)
{
case SC_MOVE:
// An undocked docker is being moved
{
BOOL bResult = FALSE;
m_bIsDragging = TRUE;
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &bResult, 0))
{
// Turn on DragFullWindows for this move
SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, 0, 0);
// Process this message
DefWindowProc(WM_SYSCOMMAND, wParam, lParam);
// Return DragFullWindows to its previous state
SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, bResult, 0, 0);
return 0L;
}
}
break;
case SC_CLOSE:
// The close button is pressed on an undocked docker
m_bIsClosing = TRUE;
break;
}
return CWnd::WndProcDefault(WM_SYSCOMMAND, wParam, lParam);
}
inline LRESULT CDocker::OnWindowPosChanging(WPARAM wParam, LPARAM lParam)
{
// Suspend dock drag moving while over dock zone
if (m_BlockMove)
{
LPWINDOWPOS pWndPos = (LPWINDOWPOS)lParam;
pWndPos->flags |= SWP_NOMOVE|SWP_FRAMECHANGED;
return 0;
}
return CWnd::WndProcDefault(WM_WINDOWPOSCHANGING, wParam, lParam);
}
inline void CDocker::OnWindowPosChanged(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
if (m_bIsDragging)
{
// Send a Move notification to the parent
if ( IsLeftButtonDown() )
{
LPWINDOWPOS wPos = (LPWINDOWPOS)lParam;
if ((!(wPos->flags & SWP_NOMOVE)) || m_BlockMove)
SendNotify(UWM_DOCK_MOVE);
}
else
{
CloseAllTargets();
m_BlockMove = FALSE;
}
}
else if (this == GetTopmostDocker())
{
// Reposition the dock children
if (IsUndocked() && IsWindowVisible() && !m_bIsClosing) RecalcDockLayout();
}
}
inline void CDocker::PreCreate(CREATESTRUCT &cs)
{
// Specify the WS_POPUP style to have this window owned
if (this != GetDockAncestor())
cs.style = WS_POPUP;
cs.dwExStyle = WS_EX_TOOLWINDOW;
}
inline void CDocker::PreRegisterClass(WNDCLASS &wc)
{
wc.lpszClassName = _T("Win32++ Docker");
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
}
inline void CDocker::RecalcDockChildLayout(CRect rc)
{
// This function positions the Docker's dock children, the Dockers client area
// and draws the dockbar bars.
// Notes:
// 1) This function is called recursively.
// 2) The client area and child dockers are positioned simultaneously with
// DeferWindowPos to avoid drawing errors in complex docker arrangements.
// 3) The docker's client area contains the docker's caption (if any) and the docker's view window.
// Note: All top level dockers are undocked, including the dock ancestor.
if (IsDocked())
{
rc.OffsetRect(-rc.left, -rc.top);
}
HDWP hdwp = BeginDeferWindowPos((int)m_vDockChildren.size() +2);
// Step 1: Calculate the position of each Docker child, DockBar, and Client window.
// The Client area = the docker rect minus the area of dock children and the dock bar (splitter bar).
for (UINT u = 0; u < m_vDockChildren.size(); ++u)
{
CRect rcChild = rc;
double DockSize = m_vDockChildren[u]->m_DockStartSize;;
// Calculate the size of the Docker children
switch (m_vDockChildren[u]->GetDockStyle() & 0xF)
{
case DS_DOCKED_LEFT:
if (!(GetDockStyle() & DS_FIXED_RESIZE))
DockSize = MIN(m_vDockChildren[u]->m_DockSizeRatio*(GetWindowRect().Width()), rcChild.Width());
rcChild.right = rcChild.left + (int)DockSize;
break;
case DS_DOCKED_RIGHT:
if (!(GetDockStyle() & DS_FIXED_RESIZE))
DockSize = MIN(m_vDockChildren[u]->m_DockSizeRatio*(GetWindowRect().Width()), rcChild.Width());
rcChild.left = rcChild.right - (int)DockSize;
break;
case DS_DOCKED_TOP:
if (!(GetDockStyle() & DS_FIXED_RESIZE))
DockSize = MIN(m_vDockChildren[u]->m_DockSizeRatio*(GetWindowRect().Height()), rcChild.Height());
rcChild.bottom = rcChild.top + (int)DockSize;
break;
case DS_DOCKED_BOTTOM:
if (!(GetDockStyle() & DS_FIXED_RESIZE))
DockSize = MIN(m_vDockChildren[u]->m_DockSizeRatio*(GetWindowRect().Height()), rcChild.Height());
rcChild.top = rcChild.bottom - (int)DockSize;
break;
}
if (m_vDockChildren[u]->IsDocked())
{
// Position this docker's children
hdwp = m_vDockChildren[u]->DeferWindowPos(hdwp, NULL, rcChild, SWP_SHOWWINDOW|SWP_FRAMECHANGED);
m_vDockChildren[u]->m_rcChild = rcChild;
rc.SubtractRect(rc, rcChild);
// Calculate the dimensions of the splitter bar
CRect rcBar = rc;
DWORD DockSide = m_vDockChildren[u]->GetDockStyle() & 0xF;
if (DS_DOCKED_LEFT == DockSide) rcBar.right = rcBar.left + m_vDockChildren[u]->GetBarWidth();
if (DS_DOCKED_RIGHT == DockSide) rcBar.left = rcBar.right - m_vDockChildren[u]->GetBarWidth();
if (DS_DOCKED_TOP == DockSide) rcBar.bottom = rcBar.top + m_vDockChildren[u]->GetBarWidth();
if (DS_DOCKED_BOTTOM == DockSide) rcBar.top = rcBar.bottom - m_vDockChildren[u]->GetBarWidth();
// Save the splitter bar position. We will reposition it later.
m_vDockChildren[u]->m_rcBar = rcBar;
rc.SubtractRect(rc, rcBar);
}
}
// Step 2: Position the Dock client and dock bar
hdwp = GetDockClient().DeferWindowPos(hdwp, NULL, rc, SWP_SHOWWINDOW |SWP_FRAMECHANGED);
EndDeferWindowPos(hdwp);
// Position the dockbar. Only docked dockers have a dock bar.
if (IsDocked())
{
// The SWP_NOCOPYBITS forces a redraw of the dock bar.
GetDockBar().SetWindowPos(NULL, m_rcBar, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS );
}
// Step 3: Now recurse through the docker's children. They might have children of their own.
for (UINT v = 0; v < m_vDockChildren.size(); ++v)
{
m_vDockChildren[v]->RecalcDockChildLayout(m_vDockChildren[v]->m_rcChild);
}
}
inline void CDocker::RecalcDockLayout()
// Repositions the dock children of a top level docker
{
if (GetDockAncestor()->IsWindow())
{
CRect rc = GetTopmostDocker()->GetClientRect();
GetTopmostDocker()->RecalcDockChildLayout(rc);
GetTopmostDocker()->UpdateWindow();
}
}
inline std::vector<CDocker*> CDocker::SortDockers()
// Returns a vector of sorted dockers, used by SaveRegistrySettings.
{
std::vector<CDocker*> vSorted;
std::vector<CDocker*>::iterator itSort;
std::vector<DockPtr>::iterator itAll;
// Add undocked top level dockers
for (itAll = GetAllDockers().begin(); itAll < GetAllDockers().end(); ++itAll)
{
if (!(*itAll)->GetDockParent())
vSorted.push_back((*itAll).get());
}
// Add dock ancestor's children
vSorted.insert(vSorted.end(), GetDockAncestor()->GetDockChildren().begin(), GetDockAncestor()->GetDockChildren().end());
// Add other dock children
int index = 0;
itSort = vSorted.begin();
while (itSort < vSorted.end())
{
vSorted.insert(vSorted.end(), (*itSort)->GetDockChildren().begin(), (*itSort)->GetDockChildren().end());
itSort = vSorted.begin() + (++index);
}
// Add dockers docked in containers
std::vector<CDocker*> vDockContainers;
for (itSort = vSorted.begin(); itSort< vSorted.end(); ++itSort)
{
if ((*itSort)->GetContainer())
vDockContainers.push_back(*itSort);
}
for (itSort = vDockContainers.begin(); itSort < vDockContainers.end(); ++itSort)
{
CDockContainer* pContainer = (*itSort)->GetContainer();
for (UINT i = 1; i < pContainer->GetAllContainers().size(); ++i)
{
CDockContainer* pChild = pContainer->GetContainerFromIndex(i);
CDocker* pDock = GetDockFromView(pChild);
vSorted.push_back(pDock);
}
}
return vSorted;
}
inline BOOL CDocker::SaveRegistrySettings(tString tsRegistryKeyName)
// Stores the docking configuration in the registry
// NOTE: This function assumes that each docker has a unique DockID
{
assert(VerifyDockers());
std::vector<CDocker*> vSorted = SortDockers();
std::vector<CDocker*>::iterator iter;
std::vector<DockInfo> vDockInfo;
if (0 != tsRegistryKeyName.size())
{
// Fill the DockInfo vector with the docking information
for (iter = vSorted.begin(); iter < vSorted.end(); ++iter)
{
DockInfo di = {0};
di.DockID = (*iter)->GetDockID();
di.DockStyle = (*iter)->GetDockStyle();
di.DockSize = (*iter)->GetDockSize();
di.Rect = (*iter)->GetWindowRect();
if ((*iter)->GetDockParent())
di.DockParentID = (*iter)->GetDockParent()->GetDockID();
vDockInfo.push_back(di);
}
tString tsKeyName = _T("Software\\") + tsRegistryKeyName;
HKEY hKey = NULL;
HKEY hKeyDock = NULL;
try
{
if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, tsKeyName.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL))
throw (CWinException(_T("RegCreateKeyEx Failed")));
RegDeleteKey(hKey, _T("Dock Windows"));
if (ERROR_SUCCESS != RegCreateKeyEx(hKey, _T("Dock Windows"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyDock, NULL))
throw (CWinException(_T("RegCreateKeyEx Failed")));
// Add the Dock windows information to the registry
for (UINT u = 0; u < vDockInfo.size(); ++u)
{
DockInfo di = vDockInfo[u];
TCHAR szNumber[16];
tString tsSubKey = _T("DockChild");
tsSubKey += _itot((int)u, szNumber, 10);
if(ERROR_SUCCESS != RegSetValueEx(hKeyDock, tsSubKey.c_str(), 0, REG_BINARY, (LPBYTE)&di, sizeof(DockInfo)))
throw (CWinException(_T("RegSetValueEx failed")));
}
// Add Active Container to the registry
int i = 0;
for (iter = vSorted.begin(); iter < vSorted.end(); ++iter)
{
CDockContainer* pContainer = (*iter)->GetContainer();
if (pContainer && (pContainer == pContainer->GetActiveContainer()))
{
TCHAR szNumber[20];
tString tsSubKey = _T("ActiveContainer");
tsSubKey += _itot(i++, szNumber, 10);
int nID = GetDockFromView(pContainer)->GetDockID();
if(ERROR_SUCCESS != RegSetValueEx(hKeyDock, tsSubKey.c_str(), 0, REG_DWORD, (LPBYTE)&nID, sizeof(int)))
throw (CWinException(_T("RegSetValueEx failed")));
}
}
RegCloseKey(hKeyDock);
RegCloseKey(hKey);
}
catch (const CWinException& e)
{
// Roll back the registry changes by deleting the subkeys
if (hKey)
{
if (hKeyDock)
{
RegDeleteKey(hKeyDock, _T("Dock Windows"));
RegCloseKey(hKeyDock);
}
RegDeleteKey(HKEY_CURRENT_USER ,tsKeyName.c_str());
RegCloseKey(hKey);
}
e.what();
return FALSE;
}
}
return TRUE;
}
inline void CDocker::SendNotify(UINT nMessageID)
// Sends a docking notification to the docker below the cursor
{
DRAGPOS DragPos;
DragPos.hdr.code = nMessageID;
DragPos.hdr.hwndFrom = m_hWnd;
DragPos.ptPos = GetCursorPos();
DragPos.DockZone = m_dwDockZone;
m_dwDockZone = 0;
CDocker* pDock = GetDockFromPoint(DragPos.ptPos);
if (pDock)
pDock->SendMessage(WM_NOTIFY, 0L, (LPARAM)&DragPos);
else
{
if (GetDockHint().IsWindow()) GetDockHint().Destroy();
CloseAllTargets();
m_BlockMove = FALSE;
}
}
inline void CDocker::SetDockStyle(DWORD dwDockStyle)
{
if (IsWindow())
{
if ((dwDockStyle & DS_CLIENTEDGE) != (m_DockStyle & DS_CLIENTEDGE))
{
if (dwDockStyle & DS_CLIENTEDGE)
{
DWORD dwExStyle = (DWORD)GetDockClient().GetWindowLongPtr(GWL_EXSTYLE)|WS_EX_CLIENTEDGE;
GetDockClient().SetWindowLongPtr(GWL_EXSTYLE, dwExStyle);
GetDockClient().RedrawWindow(0, 0, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
else
{
DWORD dwExStyle = (DWORD)GetDockClient().GetWindowLongPtr(GWL_EXSTYLE);
dwExStyle &= ~WS_EX_CLIENTEDGE;
GetDockClient().SetWindowLongPtr(GWL_EXSTYLE, dwExStyle);
GetDockClient().RedrawWindow(0, 0, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
}
RecalcDockLayout();
}
m_DockStyle = dwDockStyle;
}
inline void CDocker::SetCaption(LPCTSTR szCaption)
// Sets the caption text
{
GetDockClient().SetCaption(szCaption);
if (IsWindow())
SetWindowText(szCaption);
}
inline void CDocker::SetCaptionColors(COLORREF Foregnd1, COLORREF Backgnd1, COLORREF ForeGnd2, COLORREF BackGnd2)
{
GetDockClient().SetCaptionColors(Foregnd1, Backgnd1, ForeGnd2, BackGnd2);
}
inline void CDocker::SetCaptionHeight(int nHeight)
// Sets the height of the caption
{
m_NCHeight = nHeight;
RedrawWindow();
RecalcDockLayout();
}
inline void CDocker::SetDockSize(int DockSize)
// Sets the size of a docked docker
{
if (IsDocked())
{
assert (m_pDockParent);
switch (GetDockStyle() & 0xF)
{
case DS_DOCKED_LEFT:
m_DockStartSize = MIN(DockSize,m_pDockParent->GetWindowRect().Width());
m_DockSizeRatio = ((double)m_DockStartSize)/((double)m_pDockParent->GetWindowRect().Width());
break;
case DS_DOCKED_RIGHT:
m_DockStartSize = MIN(DockSize,m_pDockParent->GetWindowRect().Width());
m_DockSizeRatio = ((double)m_DockStartSize)/((double)m_pDockParent->GetWindowRect().Width());
break;
case DS_DOCKED_TOP:
m_DockStartSize = MIN(DockSize,m_pDockParent->GetWindowRect().Height());
m_DockSizeRatio = ((double)m_DockStartSize)/((double)m_pDockParent->GetWindowRect().Height());
break;
case DS_DOCKED_BOTTOM:
m_DockStartSize = MIN(DockSize,m_pDockParent->GetWindowRect().Height());
m_DockSizeRatio = ((double)m_DockStartSize)/((double)m_pDockParent->GetWindowRect().Height());
break;
}
RecalcDockLayout();
}
else
{
m_DockStartSize = DockSize;
m_DockSizeRatio = 1.0;
}
}
inline void CDocker::SetDragAutoResize(BOOL bAutoResize)
{
m_bDragAutoResize = bAutoResize;
}
inline void CDocker::SetView(CWnd& wndView)
// Assigns the view window to the docker
{
CWnd* pWnd = &wndView;
GetDockClient().SetView(wndView);
if (dynamic_cast<CDockContainer*>(pWnd))
{
CDockContainer* pContainer = (CDockContainer*)&wndView;
SetCaption(pContainer->GetDockCaption().c_str());
}
}
inline void CDocker::PromoteFirstChild()
// One of the steps required for undocking
{
// Promote our first child to replace ourself
if (m_pDockParent)
{
for (UINT u = 0 ; u < m_pDockParent->m_vDockChildren.size(); ++u)
{
if (m_pDockParent->m_vDockChildren[u] == this)
{
if (m_vDockChildren.size() > 0)
// swap our first child for ourself as a child of the parent
m_pDockParent->m_vDockChildren[u] = m_vDockChildren[0];
else
// remove ourself as a child of the parent
m_pDockParent->m_vDockChildren.erase(m_pDockParent->m_vDockChildren.begin() + u);
break;
}
}
}
// Transfer styles and data and children to the child docker
CDocker* pDockFirstChild = NULL;
if (m_vDockChildren.size() > 0)
{
pDockFirstChild = m_vDockChildren[0];
pDockFirstChild->m_DockStyle = (pDockFirstChild->m_DockStyle & 0xFFFFFFF0 ) | (m_DockStyle & 0xF);
pDockFirstChild->m_DockStartSize = m_DockStartSize;
pDockFirstChild->m_DockSizeRatio = m_DockSizeRatio;
if (m_pDockParent)
{
pDockFirstChild->m_pDockParent = m_pDockParent;
pDockFirstChild->SetParent(m_pDockParent);
pDockFirstChild->GetDockBar().SetParent(m_pDockParent);
}
else
{
std::vector<CDocker*>::iterator iter;
for (iter = GetDockChildren().begin() + 1; iter < GetDockChildren().end(); ++iter)
(*iter)->ShowWindow(SW_HIDE);
pDockFirstChild->ConvertToPopup(GetWindowRect());
pDockFirstChild->GetDockBar().ShowWindow(SW_HIDE);
}
m_vDockChildren.erase(m_vDockChildren.begin());
MoveDockChildren(pDockFirstChild);
}
}
inline void CDocker::ConvertToChild(HWND hWndParent)
{
DWORD dwStyle = WS_CHILD | WS_VISIBLE;
SetWindowLongPtr(GWL_STYLE, dwStyle);
SetParent(FromHandle(hWndParent));
GetDockBar().SetParent(FromHandle(hWndParent));
}
inline void CDocker::ConvertToPopup(RECT rc)
{
// Change the window to an "undocked" style
ShowWindow(SW_HIDE);
DWORD dwStyle = WS_POPUP| WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;
SetWindowLongPtr(GWL_STYLE, dwStyle);
// Change the window's parent and reposition it
GetDockBar().ShowWindow(SW_HIDE);
SetWindowPos(0, 0, 0, 0, 0, SWP_NOSENDCHANGING|SWP_HIDEWINDOW|SWP_NOREDRAW);
m_pDockParent = 0;
SetParent(0);
SetWindowPos(NULL, rc, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOOWNERZORDER);
GetDockClient().SetWindowPos(NULL, GetClientRect(), SWP_SHOWWINDOW);
SetWindowText(GetCaption().c_str());
}
inline CDocker* CDocker::SeparateFromDock()
{
// This performs some of the tasks required for undocking.
// It is also used when a docker is hidden.
CDocker* pDockUndockedFrom = GetDockParent();
if (!pDockUndockedFrom && (GetDockChildren().size() > 0))
pDockUndockedFrom = GetDockChildren()[0];
GetTopmostDocker()->m_hOldFocus = 0;
PromoteFirstChild();
m_pDockParent = 0;
GetDockBar().ShowWindow(SW_HIDE);
m_DockStyle = m_DockStyle & 0xFFFFFFF0;
m_DockStyle &= ~DS_DOCKED_CONTAINER;
return pDockUndockedFrom;
}
inline void CDocker::SetUndockPosition(CPoint pt)
{
m_Undocking = TRUE;
CRect rc;
rc = GetDockClient().GetWindowRect();
CRect rcTest = rc;
rcTest.bottom = MIN(rcTest.bottom, rcTest.top + m_NCHeight);
if ( !rcTest.PtInRect(pt))
rc.SetRect(pt.x - rc.Width()/2, pt.y - m_NCHeight/2, pt.x + rc.Width()/2, pt.y - m_NCHeight/2 + rc.Height());
ConvertToPopup(rc);
m_Undocking = FALSE;
// Send the undock notification to the frame
NMHDR nmhdr = {0};
nmhdr.hwndFrom = m_hWnd;
nmhdr.code = UWM_UNDOCKED;
nmhdr.idFrom = m_nDockID;
CWnd* pFrame = GetDockAncestor()->GetAncestor();
pFrame->SendMessage(WM_NOTIFY, m_nDockID, (LPARAM)&nmhdr);
// Initiate the window move
SetCursorPos(pt.x, pt.y);
ScreenToClient(pt);
PostMessage(WM_SYSCOMMAND, (WPARAM)(SC_MOVE|0x0002), MAKELPARAM(pt.x, pt.y));
}
inline void CDocker::Undock(CPoint pt, BOOL bShowUndocked)
{
// Return if we shouldn't undock
if (GetDockStyle() & DS_NO_UNDOCK) return;
// Undocking isn't supported on Win95
if (1400 == GetWinVersion()) return;
CDocker* pDockUndockedFrom = SeparateFromDock();
// Position and draw the undocked window, unless it is about to be closed
if (bShowUndocked)
{
SetUndockPosition(pt);
}
RecalcDockLayout();
if ((pDockUndockedFrom) && (pDockUndockedFrom->GetTopmostDocker() != GetTopmostDocker()))
pDockUndockedFrom->RecalcDockLayout();
}
inline void CDocker::UndockContainer(CDockContainer* pContainer, CPoint pt, BOOL bShowUndocked)
{
assert(pContainer);
assert(this == GetDockFromView(pContainer->GetContainerParent()));
// Return if we shouldn't undock
if (GetDockFromView(pContainer)->GetDockStyle() & DS_NO_UNDOCK) return;
// Undocking isn't supported on Win95
if (1400 == GetWinVersion()) return;
GetTopmostDocker()->m_hOldFocus = 0;
CDocker* pDockUndockedFrom = GetDockFromView(pContainer->GetContainerParent());
pDockUndockedFrom->ShowWindow(SW_HIDE);
if (GetView() == pContainer)
{
// The parent container is being undocked, so we need
// to transfer our child containers to a different docker
// Choose a new docker from among the dockers for child containers
CDocker* pDockNew = 0;
CDocker* pDockOld = GetDockFromView(pContainer);
std::vector<ContainerInfo> AllContainers = pContainer->GetAllContainers();
std::vector<ContainerInfo>::iterator iter = AllContainers.begin();
while ((0 == pDockNew) && (iter < AllContainers.end()))
{
if ((*iter).pContainer != pContainer)
pDockNew = (CDocker*)FromHandle(::GetParent((*iter).pContainer->GetParent()->GetHwnd()));
++iter;
}
if (pDockNew)
{
// Move containers from the old docker to the new docker
CDockContainer* pContainerNew = (CDockContainer*)pDockNew->GetView();
for (iter = AllContainers.begin(); iter != AllContainers.end(); ++iter)
{
if ((*iter).pContainer != pContainer)
{
CDockContainer* pChildContainer = (CDockContainer*)(*iter).pContainer;
pContainer->RemoveContainer(pChildContainer);
if (pContainerNew != pChildContainer)
{
pContainerNew->AddContainer(pChildContainer);
CDocker* pDock = GetDockFromView(pChildContainer);
pDock->SetParent(pDockNew);
pDock->m_pDockParent = pDockNew;
}
}
}
// Now transfer the old docker's settings to the new one.
pDockUndockedFrom = pDockNew;
pDockNew->m_DockStyle = pDockOld->m_DockStyle;
pDockNew->m_DockStartSize = pDockOld->m_DockStartSize;
pDockNew->m_DockSizeRatio = pDockOld->m_DockSizeRatio;
if (pDockOld->IsDocked())
{
pDockNew->m_pDockParent = pDockOld->m_pDockParent;
pDockNew->SetParent(pDockOld->GetParent());
}
else
{
CRect rc = pDockOld->GetWindowRect();
pDockNew->ShowWindow(SW_HIDE);
DWORD dwStyle = WS_POPUP| WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_VISIBLE;
pDockNew->SetWindowLongPtr(GWL_STYLE, dwStyle);
pDockNew->m_pDockParent = 0;
pDockNew->SetParent(0);
pDockNew->SetWindowPos(NULL, rc, SWP_SHOWWINDOW|SWP_FRAMECHANGED| SWP_NOOWNERZORDER);
}
pDockNew->GetDockBar().SetParent(pDockOld->GetParent());
pDockNew->GetView()->SetFocus();
// Transfer the Dock children to the new docker
pDockOld->MoveDockChildren(pDockNew);
// insert pDockNew into its DockParent's DockChildren vector
if (pDockNew->m_pDockParent)
{
std::vector<CDocker*>::iterator p;
for (p = pDockNew->m_pDockParent->m_vDockChildren.begin(); p != pDockNew->m_pDockParent->m_vDockChildren.end(); ++p)
{
if (*p == this)
{
pDockNew->m_pDockParent->m_vDockChildren.insert(p, pDockNew);
break;
}
}
}
}
}
else
{
// This is a child container, so simply remove it from the parent
CDockContainer* pContainerParent = (CDockContainer*)GetView();
pContainerParent->RemoveContainer(pContainer);
pContainerParent->SetTabSize();
pContainerParent->SetFocus();
pContainerParent->GetViewPage().SetParent(pContainerParent);
}
// Finally do the actual undocking
CDocker* pDock = GetDockFromView(pContainer);
CRect rc = GetDockClient().GetWindowRect();
ScreenToClient(rc);
pDock->GetDockClient().SetWindowPos(NULL, rc, SWP_SHOWWINDOW);
pDock->Undock(pt, bShowUndocked);
pDockUndockedFrom->ShowWindow();
pDockUndockedFrom->RecalcDockLayout();
pDock->BringWindowToTop();
}
inline LRESULT CDocker::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_ACTIVATE:
OnActivate(wParam, lParam);
break;
case WM_SYSCOMMAND:
return OnSysCommand(wParam, lParam);
case WM_EXITSIZEMOVE:
OnExitSizeMove(wParam, lParam);
break;
case WM_WINDOWPOSCHANGING:
return OnWindowPosChanging(wParam, lParam);
case WM_WINDOWPOSCHANGED:
OnWindowPosChanged(wParam, lParam);
break;
case WM_DESTROY:
OnDestroy(wParam, lParam);
break;
case WM_SETFOCUS:
OnSetFocus(wParam, lParam);
break;
case WM_TIMER:
OnCaptionTimer(wParam, lParam);
break;
case UWM_DOCK_DESTROYED:
OnDockDestroyed(wParam, lParam);
break;
case UWM_DOCK_ACTIVATED:
DrawAllCaptions();
SetTimer(1, 100, NULL);
break;
case WM_SYSCOLORCHANGE:
OnSysColorChange(wParam, lParam);
break;
case WM_NCLBUTTONDBLCLK :
m_bIsDragging = FALSE;
break;
}
return CWnd::WndProcDefault(uMsg, wParam, lParam);
}
//////////////////////////////////////
// Declaration of the CDockContainer class
inline CDockContainer::CDockContainer() : m_iCurrentPage(0), m_hTabIcon(0), m_nTabPressed(-1)
{
m_pContainerParent = this;
}
inline CDockContainer::~CDockContainer()
{
if (m_hTabIcon)
DestroyIcon(m_hTabIcon);
}
inline void CDockContainer::AddContainer(CDockContainer* pContainer)
{
assert(pContainer);
if (this == m_pContainerParent)
{
ContainerInfo ci = {0};
ci.pContainer = pContainer;
lstrcpy(ci.szTitle, pContainer->GetTabText());
ci.iImage = ImageList_AddIcon(GetImageList(), pContainer->GetTabIcon());
int iNewPage = (int)m_vContainerInfo.size();
m_vContainerInfo.push_back(ci);
if (m_hWnd)
{
TCITEM tie = {0};
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = ci.iImage;
tie.pszText = m_vContainerInfo[iNewPage].szTitle;
TabCtrl_InsertItem(m_hWnd, iNewPage, &tie);
SetTabSize();
}
pContainer->m_pContainerParent = this;
if (pContainer->IsWindow())
{
// Set the parent container relationships
pContainer->GetViewPage().SetParent(this);
pContainer->GetViewPage().ShowWindow(SW_HIDE);
}
}
}
inline void CDockContainer::AddToolBarButton(UINT nID, BOOL bEnabled /* = TRUE */)
// Adds Resource IDs to toolbar buttons.
// A resource ID of 0 is a separator
{
GetToolBar().AddButton(nID, bEnabled);
}
inline CDockContainer* CDockContainer::GetContainerFromIndex(UINT nPage)
{
CDockContainer* pContainer = NULL;
if (nPage < m_vContainerInfo.size())
pContainer = (CDockContainer*)m_vContainerInfo[nPage].pContainer;
return pContainer;
}
inline CWnd* CDockContainer::GetActiveView() const
// Returns a pointer to the active view window, or NULL if there is no active veiw.
{
CWnd* pWnd = NULL;
if (m_pContainerParent->m_vContainerInfo.size() > 0)
{
CDockContainer* pActiveContainer = m_pContainerParent->m_vContainerInfo[m_pContainerParent->m_iCurrentPage].pContainer;
if (pActiveContainer->GetViewPage().GetView()->IsWindow())
pWnd = pActiveContainer->GetViewPage().GetView();
}
return pWnd;
}
inline CDockContainer* CDockContainer::GetContainerFromView(CWnd* pView) const
{
assert(pView);
std::vector<ContainerInfo>::iterator iter;
CDockContainer* pViewContainer = 0;
for (iter = GetAllContainers().begin(); iter != GetAllContainers().end(); ++iter)
{
CDockContainer* pContainer = (*iter).pContainer;
if (pContainer->GetView() == pView)
pViewContainer = pContainer;
}
return pViewContainer;
}
inline int CDockContainer::GetContainerIndex(CDockContainer* pContainer)
{
assert(pContainer);
int iReturn = -1;
for (int i = 0; i < (int)m_pContainerParent->m_vContainerInfo.size(); ++i)
{
if (m_pContainerParent->m_vContainerInfo[i].pContainer == pContainer)
iReturn = i;
}
return iReturn;
}
inline SIZE CDockContainer::GetMaxTabTextSize()
{
CSize Size;
// Allocate an iterator for the ContainerInfo vector
std::vector<ContainerInfo>::iterator iter;
for (iter = m_vContainerInfo.begin(); iter != m_vContainerInfo.end(); ++iter)
{
CSize TempSize;
CClientDC dc(this);
NONCLIENTMETRICS info = {0};
info.cbSize = GetSizeofNonClientMetrics();
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
dc.CreateFontIndirect(&info.lfStatusFont);
TempSize = dc.GetTextExtentPoint32(iter->szTitle, lstrlen(iter->szTitle));
if (TempSize.cx > Size.cx)
Size = TempSize;
}
return Size;
}
inline void CDockContainer::SetupToolBar()
{
// Use this function to set the Resource IDs for the toolbar(s).
/* // Set the Resource IDs for the toolbar buttons
AddToolBarButton( IDM_FILE_NEW );
AddToolBarButton( IDM_FILE_OPEN );
AddToolBarButton( IDM_FILE_SAVE );
AddToolBarButton( 0 ); // Separator
AddToolBarButton( IDM_EDIT_CUT );
AddToolBarButton( IDM_EDIT_COPY );
AddToolBarButton( IDM_EDIT_PASTE );
AddToolBarButton( 0 ); // Separator
AddToolBarButton( IDM_FILE_PRINT );
AddToolBarButton( 0 ); // Separator
AddToolBarButton( IDM_HELP_ABOUT );
*/
}
inline void CDockContainer::OnCreate()
{
assert(GetView()); // Use SetView in CMainFrame's constructor to set the view window
ContainerInfo ci = {0};
ci.pContainer = this;
lstrcpy(ci.szTitle, GetTabText());
ci.iImage = ImageList_AddIcon(GetImageList(), GetTabIcon());
m_vContainerInfo.push_back(ci);
// Create the page window
GetViewPage().Create(this);
// Create the toolbar
GetToolBar().Create(&GetViewPage());
DWORD style = (DWORD)GetToolBar().GetWindowLongPtr(GWL_STYLE);
style |= CCS_NODIVIDER ;
GetToolBar().SetWindowLongPtr(GWL_STYLE, style);
SetupToolBar();
if (GetToolBar().GetToolBarData().size() > 0)
{
// Set the toolbar images
// A mask of 192,192,192 is compatible with AddBitmap (for Win95)
if (!GetToolBar().SendMessage(TB_GETIMAGELIST, 0L, 0L))
GetToolBar().SetImages(RGB(192,192,192), IDW_MAIN, 0, 0);
GetToolBar().SendMessage(TB_AUTOSIZE, 0L, 0L);
}
else
GetToolBar().Destroy();
SetFixedWidth(TRUE);
SetOwnerDraw(TRUE);
// Add tabs for each container.
for (int i = 0; i < (int)m_vContainerInfo.size(); ++i)
{
// Add tabs for each view.
TCITEM tie = {0};
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = i;
tie.pszText = m_vContainerInfo[i].szTitle;
TabCtrl_InsertItem(m_hWnd, i, &tie);
}
}
inline void CDockContainer::OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
// Overrides CTab::OnLButtonDown
UNREFERENCED_PARAMETER(wParam);
CPoint pt((DWORD)lParam);
TCHITTESTINFO info = {0};
info.pt = pt;
m_nTabPressed = HitTest(info);
}
inline void CDockContainer::OnLButtonUp(WPARAM wParam, LPARAM lParam)
{
// Overrides CTab::OnLButtonUp and takes no action
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
}
inline void CDockContainer::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
// Overrides CTab::OnMouseLeave
if (IsLeftButtonDown() && (m_nTabPressed >= 0))
{
CDocker* pDock = (CDocker*)FromHandle(::GetParent(GetParent()->GetHwnd()));
if (dynamic_cast<CDocker*>(pDock))
{
CDockContainer* pContainer = GetContainerFromIndex(m_iCurrentPage);
pDock->UndockContainer(pContainer, GetCursorPos(), TRUE);
}
}
m_nTabPressed = -1;
CTab::OnMouseLeave(wParam, lParam);
}
inline LRESULT CDockContainer::OnNotifyReflect(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
switch (((LPNMHDR)lParam)->code)
{
case TCN_SELCHANGE:
{
// Display the newly selected tab page
int nPage = GetCurSel();
SelectPage(nPage);
}
break;
}
return 0L;
}
inline void CDockContainer::PreCreate(CREATESTRUCT &cs)
{
// For Tabs on the bottom, add the TCS_BOTTOM style
CTab::PreCreate(cs);
cs.style |= TCS_BOTTOM;
}
inline void CDockContainer::RecalcLayout()
{
if (GetContainerParent() == this)
{
// Set the tab sizes
SetTabSize();
// Position the View over the tab control's display area
CRect rc = GetClientRect();
AdjustRect(FALSE, &rc);
CDockContainer* pContainer = m_vContainerInfo[m_iCurrentPage].pContainer;
pContainer->GetViewPage().SetWindowPos(HWND_TOP, rc, SWP_SHOWWINDOW);
}
}
inline void CDockContainer::RemoveContainer(CDockContainer* pWnd)
{
assert(pWnd);
// Remove the tab
int iTab = GetContainerIndex(pWnd);
if (iTab > 0)
{
// DeleteItem(iTab);
TabCtrl_DeleteItem(m_hWnd, iTab);
}
// Remove the ContainerInfo entry
std::vector<ContainerInfo>::iterator iter;
int iImage = -1;
for (iter = m_vContainerInfo.begin(); iter != m_vContainerInfo.end(); ++iter)
{
if (iter->pContainer == pWnd)
{
iImage = (*iter).iImage;
if (iImage >= 0)
TabCtrl_RemoveImage(m_hWnd, iImage);
m_vContainerInfo.erase(iter);
break;
}
}
// Set the parent container relationships
pWnd->GetViewPage().SetParent(pWnd);
pWnd->m_pContainerParent = pWnd;
// Display the first page
m_iCurrentPage = 0;
if (IsWindow())
SelectPage(0);
}
inline void CDockContainer::SelectPage(int nPage)
{
if (this != m_pContainerParent)
m_pContainerParent->SelectPage(nPage);
else
{
if ((nPage >= 0) && (nPage < (int)m_vContainerInfo.size() ))
{
if (GetCurSel() != nPage)
SetCurSel(nPage);
// Create the new container window if required
if (!m_vContainerInfo[nPage].pContainer->IsWindow())
{
CDockContainer* pContainer = m_vContainerInfo[nPage].pContainer;
pContainer->Create(GetParent());
pContainer->GetViewPage().SetParent(this);
}
// Determine the size of the tab page's view area
CRect rc = GetClientRect();
AdjustRect(FALSE, &rc);
// Swap the pages over
CDockContainer* pOldContainer = m_vContainerInfo[m_iCurrentPage].pContainer;
CDockContainer* pNewContainer = m_vContainerInfo[nPage].pContainer;
pOldContainer->GetViewPage().ShowWindow(SW_HIDE);
pNewContainer->GetViewPage().SetWindowPos(HWND_TOP, rc, SWP_SHOWWINDOW);
pNewContainer->GetViewPage().GetView()->SetFocus();
// Adjust the docking caption
CDocker* pDock = (CDocker*)FromHandle(::GetParent(::GetParent(m_hWnd)));
if (dynamic_cast<CDocker*>(pDock))
{
pDock->SetCaption(pNewContainer->GetDockCaption().c_str());
pDock->RedrawWindow();
}
m_iCurrentPage = nPage;
}
}
}
inline void CDockContainer::SetActiveContainer(CDockContainer* pContainer)
{
int nPage = GetContainerIndex(pContainer);
assert (0 <= nPage);
SelectPage(nPage);
}
inline void CDockContainer::SetTabIcon(UINT nID_Icon)
{
HICON hIcon = (HICON)LoadImage(GetApp()->GetResourceHandle(), MAKEINTRESOURCE(nID_Icon), IMAGE_ICON, 0, 0, LR_SHARED);
SetTabIcon(hIcon);
}
inline void CDockContainer::SetTabSize()
{
CRect rc = GetClientRect();
AdjustRect(FALSE, &rc);
if (rc.Width() < 0 )
rc.SetRectEmpty();
int nItemWidth = MIN(25 + GetMaxTabTextSize().cx, (rc.Width()-2)/(int)m_vContainerInfo.size());
int nItemHeight = MAX(20, GetTextHeight() + 5);
SendMessage(TCM_SETITEMSIZE, 0L, MAKELPARAM(nItemWidth, nItemHeight));
}
inline void CDockContainer::SetTabText(UINT nTab, LPCTSTR szText)
{
CDockContainer* pContainer = GetContainerParent()->GetContainerFromIndex(nTab);
pContainer->SetTabText(szText);
CTab::SetTabText(nTab, szText);
}
inline void CDockContainer::SetView(CWnd& Wnd)
{
GetViewPage().SetView(Wnd);
}
inline LRESULT CDockContainer::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
RecalcLayout();
return 0;
// The following are called in CTab::WndProcDefault
// case WM_LBUTTONDOWN:
// OnLButtonDown(wParam, lParam);
// break;
// case WM_LBUTTONUP:
// OnLButtonUp(wParam, lParam);
// break;
// case WM_MOUSELEAVE:
// OnMouseLeave(wParam, lParam);
// break;
case WM_SETFOCUS:
{
// Pass focus on to the current view
GetActiveView()->SetFocus();
}
break;
}
// pass unhandled messages on to CTab for processing
return CTab::WndProcDefault(uMsg, wParam, lParam);
}
///////////////////////////////////////////
// Declaration of the nested CViewPage class
inline BOOL CDockContainer::CViewPage::OnCommand(WPARAM wParam, LPARAM lParam)
{
CDockContainer* pContainer = (CDockContainer*)GetParent();
BOOL bResult = FALSE;
if (pContainer && pContainer->GetActiveContainer())
bResult = (BOOL)pContainer->GetActiveContainer()->SendMessage(WM_COMMAND, wParam, lParam);
return bResult;
}
inline void CDockContainer::CViewPage::OnCreate()
{
if (m_pView)
m_pView->Create(this);
}
inline LRESULT CDockContainer::CViewPage::OnNotify(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
switch (((LPNMHDR)lParam)->code)
{
// Display tooltips for the toolbar
case TTN_GETDISPINFO:
{
int iIndex = GetToolBar().HitTest();
LPNMTTDISPINFO lpDispInfo = (LPNMTTDISPINFO)lParam;
if (iIndex >= 0)
{
int nID = GetToolBar().GetCommandID(iIndex);
if (nID > 0)
{
m_tsTooltip = LoadString(nID);
lpDispInfo->lpszText = (LPTSTR)m_tsTooltip.c_str();
}
else
m_tsTooltip = _T("");
}
}
break;
} // switch LPNMHDR
return 0L;
}
inline void CDockContainer::CViewPage::PreRegisterClass(WNDCLASS &wc)
{
wc.lpszClassName = _T("Win32++ TabPage");
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
}
inline void CDockContainer::CViewPage::RecalcLayout()
{
CRect rc = GetClientRect();
if (GetToolBar().IsWindow())
{
GetToolBar().SendMessage(TB_AUTOSIZE, 0L, 0L);
CRect rcToolBar = m_ToolBar.GetClientRect();
rc.top += rcToolBar.Height();
}
GetView()->SetWindowPos(NULL, rc, SWP_SHOWWINDOW);
}
inline void CDockContainer::CViewPage::SetView(CWnd& wndView)
// Sets or changes the View window displayed within the frame
{
// Assign the view window
m_pView = &wndView;
if (m_hWnd)
{
if (!m_pView->IsWindow())
{
// The container is already created, so create and position the new view too
GetView()->Create(this);
}
RecalcLayout();
}
}
inline LRESULT CDockContainer::CViewPage::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
RecalcLayout();
break;
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
// Send the focus change notifications to the grandparent
case NM_KILLFOCUS:
case NM_SETFOCUS:
case UWM_FRAMELOSTFOCUS:
::SendMessage(::GetParent(::GetParent(m_hWnd)), WM_NOTIFY, wParam, lParam);
break;
}
break;
}
// pass unhandled messages on for default processing
return CWnd::WndProcDefault(uMsg, wParam, lParam);
}
} // namespace Win32xx
#endif // _WIN32XX_DOCKING_H_