BOOL CXTPDockingPaneTabbedContainer::OnCaptionButtonDown(CXTPDockingPaneCaptionButton* pButton)
{
	switch (pButton->GetID())
	{
	case XTP_IDS_DOCKINGPANE_MENU:
		if (m_pSelectedPane)
		{
			InternalAddRef();

			CXTPDockingPaneManager* pManager = GetDockingPaneManager();
			XTP_DOCKINGPANE_CLICK menu;

			menu.pContainer = this;
			menu.rcExclude = pButton->GetRect();
			ClientToScreen(&menu.rcExclude);

			menu.pt = GetExStyle() & WS_EX_LAYOUTRTL ? CPoint(menu.rcExclude.right, menu.rcExclude.bottom) : CPoint(menu.rcExclude.left, menu.rcExclude.bottom);
			menu.pPane = m_pSelectedPane;
			pButton->m_bPressed = TRUE;
			Invalidate(FALSE);

			pManager->NotifyOwner(XTP_DPN_CONTEXTMENU, (LPARAM)&menu);

			pButton->m_bPressed = FALSE;
			if (m_hWnd) Invalidate(FALSE);

			InternalRelease();
		}
		return TRUE;

	}
	return FALSE;
}
void CXTPDockingPaneTabbedContainer::OnCaptionButtonClick(CXTPDockingPaneCaptionButton* pButton)
{
	CXTPDockingPane* pSelectedPane = m_pSelectedPane;

	CXTPDockingPaneManager* pManager = GetDockingPaneManager();

	switch (pButton->GetID())
	{
	case XTP_IDS_DOCKINGPANE_CLOSE:

		if (pManager->m_bCloseGroupOnButtonClick)
		{
			POSITION pos = m_lstPanes.GetTailPosition();
			while (pos)
			{
				CXTPDockingPane* pPane = (CXTPDockingPane*)m_lstPanes.GetPrev(pos);

				ClosePane(pPane);
			}

		}
		else if (pSelectedPane)
		{
			ClosePane(pSelectedPane);
		}
		break;


	case XTP_IDS_DOCKINGPANE_AUTOHIDE:

		if (!IsHidden())
		{
			if (!pManager->NotifyAction(xtpPaneActionUnpinning, pSelectedPane))
			{
				GetDockingSite()->SetFocus();
				NormalizeDockingSize();
				pSelectedPane->Hide();
				pManager->NotifyAction(xtpPaneActionUnpinned, pSelectedPane);
			}

		}
		else
		{
			GetDockingPaneManager()->ToggleDocking(pManager->m_bHideGroupOnButtonClick ?
				(CXTPDockingPaneBase*)this : (CXTPDockingPaneBase*)pSelectedPane);
		}

		break;

	case XTP_IDS_DOCKINGPANE_MAXIMIZE:
		Maximize();
		break;

	case XTP_IDS_DOCKINGPANE_RESTORE:
		Restore();
		break;

	}
}
BOOL CXTPDockingPaneSidePanel::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	CXTPDockingPaneManager* pManager = GetDockingPaneManager();

	if (pManager)
	{
		pManager->GetToolTipContext()->FilterToolTipMessage(this, message, wParam, lParam);
	}

	return CMiniFrameWnd::OnWndMsg(message, wParam, lParam, pResult);
}
BOOL CXTPDockingPaneSplitterWnd::GetAvailableRect(CRect& rcAvail, CRect& rcUnion)
{
	CXTPDockingPaneManager* pManager = GetDockingPaneManager();
	if (!pManager)
		return FALSE;

	int nSplitterSize = pManager->GetPaintManager()->m_nSplitterSize;

	BOOL bHoriz = m_pContainer->m_bHoriz;
	ASSERT(m_pFirst && m_pSecond);
	if (!m_pFirst || !m_pSecond)
		return FALSE;

	CRect rcFirst = m_pFirst->GetPaneWindowRect();
	CRect rcSecond = m_pSecond->GetPaneWindowRect();

	MINMAXINFO mmiFirst, mmiSecond;
	m_pFirst->GetMinMaxInfo(&mmiFirst);
	m_pSecond->GetMinMaxInfo(&mmiSecond);

	rcAvail.UnionRect(rcFirst, rcSecond);
	rcUnion = rcAvail;

	int nGap = pManager->m_nSplitterGap;
	if (bHoriz)
	{
		rcAvail.DeflateRect(max(mmiFirst.ptMinTrackSize.x, nGap), 0,
			max(mmiSecond.ptMinTrackSize.x + nSplitterSize, nGap), 0);

		if (rcUnion.Width() > mmiFirst.ptMaxTrackSize.x)
			rcAvail.right = min(rcAvail.right, rcUnion.left + mmiFirst.ptMaxTrackSize.x);

		if (rcUnion.Width() > mmiSecond.ptMaxTrackSize.x)
			rcAvail.left = max(rcAvail.left, rcUnion.right - mmiSecond.ptMaxTrackSize.x - nSplitterSize);

		if (rcAvail.left >= rcAvail.right)
			return FALSE;
	}
	else
	{
		rcAvail.DeflateRect(0, max(mmiFirst.ptMinTrackSize.y, nGap),
			0, max(mmiSecond.ptMinTrackSize.y + nSplitterSize, nGap));

		if (rcUnion.Height() > mmiFirst.ptMaxTrackSize.y)
			rcAvail.bottom = min(rcAvail.bottom, rcUnion.top + mmiFirst.ptMaxTrackSize.y);

		if (rcUnion.Height() > mmiSecond.ptMaxTrackSize.y)
			rcAvail.top = max(rcAvail.top, rcUnion.bottom - mmiSecond.ptMaxTrackSize.y - nSplitterSize);

		if (rcAvail.top >= rcAvail.bottom)
			return FALSE;
	}
	return TRUE;
}
CRect CXTPDockingPaneSplitterContainer::_CalculateResultDockingRect(BOOL bHoriz, CXTPDockingPaneBaseList& lst, CRect rect, CXTPDockingPaneBase* pPaneI)
{
	CXTPDockingPaneManager* pManager = pPaneI->GetDockingPaneManager();
	int nSplitterSize = pManager->GetPaintManager()->m_nSplitterSize;

	int nTotalLength = 0;
	int nLengthAvail = 0;

	_AdjustPanesLength(pManager, lst, rect, bHoriz, FALSE, nTotalLength, nLengthAvail);


	POSITION pos = lst.GetHeadPosition();

	CRect rcPane(rect);
	while (pos)
	{
		CXTPDockingPaneBase* pPane = lst.GetNext(pos);

		int nLength = -pPane->m_nLength;
		if (pPane->m_nLength > 0)
		{
			nLength = nTotalLength == 0 ? 0 : int((nLengthAvail * pPane->m_nLength) / nTotalLength);

			nTotalLength -= pPane->m_nLength;
			nLengthAvail = max(nLengthAvail - nLength, 0);
		}

		if (bHoriz)
		{
			rcPane.right = pos == NULL ? rect.right : rcPane.left + nLength;

			if (pPaneI == pPane)
				break;

			rcPane.left = rcPane.right + nSplitterSize;
		}
		else
		{
			rcPane.bottom = pos == NULL ? rect.bottom : rcPane.top + nLength;

			if (pPaneI == pPane)
				break;

			rcPane.top = rcPane.bottom + nSplitterSize;
		}
	}

	return rcPane;
}
void CXTPDockingPaneSidePanel::RecalcLayout(BOOL /*bNotify*/)
{
	if (m_bInRecalcLayout)
		return;

	m_bInRecalcLayout = TRUE;

	CXTPDockingPaneManager* pManager = GetDockingPaneManager();
	CWnd* pSite = GetDockingSite();
	CRect rcClient = pManager->GetClientPane()->GetPaneWindowRect();
	pSite->ScreenToClient(rcClient);

	OnSizeParentEx(pManager, pSite, rcClient);

	m_bInRecalcLayout = FALSE;


}
void CXTPDockingPaneTabbedContainer::ClosePane(CXTPDockingPane* pPane)
{
	if (!pPane)
		return;

	if ((pPane->GetOptions() & xtpPaneNoCloseable) != 0)
		return;

	CXTPDockingPaneManager* pManager = GetDockingPaneManager();

	pPane->InternalAddRef();
	if (!pManager->NotifyAction(xtpPaneActionClosing, pPane))
	{
		pPane->Close();
		pManager->NotifyAction(xtpPaneActionClosed, pPane);
	}
	pPane->InternalRelease();
}
BOOL CXTPDockingPaneTabbedContainer::IsCaptionVertical() const
{
	CXTPDockingPaneManager* pManager = GetDockingPaneManager();

	switch (pManager->GetCaptionDirection())
	{
		case xtpPaneCaptionHorizontal:
			return FALSE;

		case xtpPaneCaptionAutoBySize:
			return m_rcWindow.Width() > m_rcWindow.Height();

		case xtpPaneCaptionAutoByPosition:
			XTPDockingPaneDirection direction = pManager->GetPaneDirection(this);
			return (direction == xtpPaneDockTop) || (direction == xtpPaneDockBottom);

	}
	return TRUE;
}
void CXTPDockingPaneSidePanel::OnCaptionButtonClick(CXTPDockingPaneCaptionButton* pButton)
{
	CXTPDockingPaneManager* pManager = GetDockingPaneManager();

	switch (pButton->GetID())
	{
		case XTP_IDS_DOCKINGPANE_CLOSE:
			{
				CXTPDockingPaneBaseList lstPanes;
				FindPane(xtpPaneTypeDockingPane, &lstPanes);

				POSITION pos = lstPanes.GetTailPosition();
				while (pos)
				{
					CXTPDockingPane* pPane = (CXTPDockingPane*)lstPanes.GetPrev(pos);

					if ((pPane->GetOptions() & xtpPaneNoCloseable) != 0)
						continue;

					pPane->InternalAddRef();

					if (!pManager->NotifyAction(xtpPaneActionClosing, pPane))
					{
						pPane->Close();
						pManager->NotifyAction(xtpPaneActionClosed, pPane);
					}

					pPane->InternalRelease();
				}
			}
			break;

		case XTP_IDS_DOCKINGPANE_AUTOHIDE:
			OnPinButtonClick();
			break;
	}
}
void CXTPDockingPaneSplitterContainer::OnSizeParent(CWnd* pParent, CRect rect, LPVOID lParam)
{
	CXTPDockingPaneManager* pManager = GetDockingPaneManager();
	CXTPDockingPanePaintManager* pPaintManager = pManager->GetPaintManager();

	int nSplitterSize = pPaintManager->m_nSplitterSize;
	int nSplitterIndent = pPaintManager->m_bShowCaption ? pPaintManager->m_nSplitterIndent : 0;

	CXTPDockingPaneBase* pClient = pManager->GetClientPane();


	AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;

	m_pDockingSite = pParent;
	m_rcWindow = rect;

	BOOL bClientPane = !pManager->m_bHideClient;

	// getting list of nonempty panes
	CXTPDockingPaneBaseList lst;
	POSITION pos = GetHeadPosition();
	while (pos)
	{
		CXTPDockingPaneBase* pPane = GetNext(pos);
		if (!pPane->IsEmpty())
			lst.AddTail(pPane);

		if (!bClientPane && pPane->ContainPane(pClient))
			bClientPane = TRUE;

	}

	if (!lst.IsEmpty() && bClientPane && pManager->m_bHideClient)
	{
		pClient->OnSizeParent(pParent, CXTPEmptyRect(), lParam);
	}


	if (lst.GetCount() == 0)
		return;

	if (lst.GetCount() == 1)
	{
		lst.GetHead()->OnSizeParent(pParent, rect, lParam);
		return;
	}

	if (m_bRecalcLayout)
		return;

	m_bRecalcLayout = TRUE;

	//ASSERT(m_lstSpliters.GetCount() == lst.GetCount() - 1);

	int nTotalLength = 0;
	int nLengthAvail = 0;

	_AdjustPanesLength(pManager, lst, rect, m_bHoriz, TRUE, nTotalLength, nLengthAvail);

	pos = lst.GetHeadPosition();
	POSITION posSplitter = m_lstSpliters.GetHeadPosition();

	CRect rcPane(rect);
	while (pos)
	{
		CXTPDockingPaneBase* pPane = lst.GetNext(pos);

		int nLength = -pPane->m_nLength;
		if (pPane->m_nLength > 0)
		{
			nLength = nTotalLength == 0 ? 0 : int((nLengthAvail * pPane->m_nLength) / nTotalLength);

			nTotalLength -= pPane->m_nLength;
			nLengthAvail = max(nLengthAvail - nLength, 0);
		}

		CRect rcSplitter;

		if (m_bHoriz)
		{
			rcPane.right = pos == NULL ? rect.right : rcPane.left + nLength;
			rcSplitter.SetRect(rcPane.right - nSplitterIndent, rect.top, rcPane.right + nSplitterSize + nSplitterIndent, rect.bottom);
		}
		else
		{
			rcPane.bottom = pos == NULL ? rect.bottom : rcPane.top + nLength;
			rcSplitter.SetRect(rect.left, rcPane.bottom - nSplitterIndent, rect.right, rcPane.bottom + nSplitterSize + nSplitterIndent);
		}

		if (lpLayout->hDWP != NULL && posSplitter)
		{
			CXTPDockingPaneSplitterWnd* pSplitter = m_lstSpliters.GetNext(posSplitter);
			if (pSplitter)
			{
				rcSplitter.IntersectRect(rcSplitter, rect);
				pSplitter->SetWindowPos(&CWnd::wndBottom, rcSplitter.left, rcSplitter.top, rcSplitter.Width(), rcSplitter.Height(), 0);
				pSplitter->Invalidate(FALSE);
			}
		}

		pPane->OnSizeParent(pParent, rcPane, lParam);

		if (m_bHoriz)
		{
			rcPane.left = rcPane.right + nSplitterSize;
		}
		else
		{
			rcPane.top = rcPane.bottom + nSplitterSize;
		}
	}

	m_bRecalcLayout = FALSE;
}
void CXTPDockingPaneSplitterWnd::OnLButtonDown(UINT /*nFlags*/, CPoint point)
{
	if (m_pContainer == 0)
		return;

	CXTPDockingPaneManager* pManager = GetDockingPaneManager();

	if (pManager->IsSplittersLocked())
		return;

	CXTPWindowRect rc(this);

	CRect rcAvail, rcUnion;
	if (!GetAvailableRect(rcAvail, rcUnion))
		return;

	if (m_pContainer->OnAction(xtpPaneActionSplitterResizing))
		return;

	m_pContainer->NormalizeDockingSize();

	BOOL bHoriz = m_pContainer->m_bHoriz;


	//point = rc.TopLeft();
	ClientToScreen(&point);

	if (pManager->IsSplitterTrackerUsed())
	{

		CXTPSplitterTracker tracker;
		BOOL bAccept = tracker.Track(this, rcAvail, rc, point, bHoriz);

		if (bAccept)
		{
			Reposition(rc, rcUnion);


			pManager->RecalcFrameLayout(m_pContainer, TRUE);
		}
	}
	else
	{
		CPoint ptOffset = bHoriz ? CPoint(rc.left - point.x, 0) :
			CPoint(0, rc.top - point.y);

		SetCapture();

		while (::GetCapture() == m_hWnd)
		{
			MSG msg;

			while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE | PM_NOYIELD))
			{
				DispatchMessage(&msg);
			}

			if (!GetMessage(&msg, NULL, 0, 0))
				break;

			if (msg.message == WM_MOUSEMOVE)
			{

				point = CPoint(msg.lParam);
				ClientToScreen(&point);
				point += ptOffset;

				point.x = max(min(point.x, rcAvail.right), rcAvail.left);
				point.y = max(min(point.y, rcAvail.bottom), rcAvail.top);

				if (bHoriz)
				{
					if (rc.left == point.x)
						continue;
					rc.OffsetRect(point.x - rc.left, 0);
				}
				else
				{
					if (rc.top == point.y)
						continue;
					rc.OffsetRect(0, point.y - rc.top);
				}

				Reposition(rc, rcUnion);

				pManager->RecalcFrameLayout(m_pContainer);
			}
			else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) break;
			else if (msg.message == WM_LBUTTONUP) break;
			else ::DispatchMessage(&msg);
		}

		if (CWnd::GetCapture() == this) ReleaseCapture();
	}

	m_pContainer->OnAction(xtpPaneActionSplitterResized);
}