You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1596 lines
34 KiB
C++

2 years ago
// XTPTabManager.cpp: implementation of the CXTPTabManager class.
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Resource.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPToolTipContext.h"
#include "Common/XTPResourceManager.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPMarkupRender.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPWinThemeWrapper.h"
#include "XTPTabManager.h"
#include "XTPTabPaintManager.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNAMIC(CXTPTabManagerItem, CCmdTarget)
//////////////////////////////////////////////////////////////////////
// CXTPTabManagerItem
CXTPTabManagerItem::CXTPTabManagerItem()
{
EnableAutomation();
m_bVisible = TRUE;
m_bEnabled = TRUE;
m_hIcon = 0;
m_hWnd = 0;
m_clrItem = 0;
m_nIndex = -1;
m_nImage = -1;
m_dwData = 0;
m_rcItem.SetRectEmpty();
m_nItemRow = 0;
m_nButtonLength = m_nContentLength = 0;
m_bClosable = TRUE;
m_pTabManager = NULL;
m_bFound = FALSE;
m_pMarkupUIElement = 0;
}
void CXTPTabManagerItem::OnRemoved()
{
m_arrNavigateButtons.RemoveAll();
}
CXTPTabManagerItem::~CXTPTabManagerItem()
{
m_arrNavigateButtons.RemoveAll();
XTPMarkupReleaseElement(m_pMarkupUIElement);
}
void CXTPTabManagerItem::Reposition()
{
if (m_pTabManager) m_pTabManager->Reposition();
}
void CXTPTabManagerItem::SetCaption(LPCTSTR lpszCaption)
{
CString strCaption(lpszCaption);
if (m_strCaption != strCaption)
{
m_strCaption = strCaption;
XTPMarkupReleaseElement(m_pMarkupUIElement);
if (m_pTabManager && m_pTabManager->GetMarkupContext())
{
m_pMarkupUIElement = XTPMarkupParseText(m_pTabManager->GetMarkupContext(), lpszCaption);
}
Reposition();
}
}
void CXTPTabManagerItem::SetColor(COLORREF clr)
{
if (m_clrItem != clr)
{
m_clrItem = clr;
m_pTabManager->RedrawControl(GetRect(), FALSE);
}
}
CString CXTPTabManagerItem::GetCaption() const
{
return m_pTabManager->GetItemCaption(this);
}
CString CXTPTabManagerItem::GetTooltip() const
{
return m_pTabManager->GetItemTooltip(this);
}
COLORREF CXTPTabManagerItem::GetColor()
{
return m_pTabManager->GetItemColor(this);
}
void CXTPTabManagerItem::SetHandle(HWND hWnd)
{
m_hWnd = hWnd;
}
void CXTPTabManagerItem::Remove()
{
if (m_pTabManager) m_pTabManager->DeleteItem(m_nIndex);
}
void CXTPTabManagerItem::Select()
{
if (m_pTabManager) m_pTabManager->OnItemClick(this);
}
HWND CXTPTabManagerItem::GetHandle() const
{
return m_hWnd;
}
BOOL CXTPTabManagerItem::IsVisible() const
{
return m_bVisible;
}
void CXTPTabManagerItem::SetVisible(BOOL bVisible)
{
if (m_bVisible != bVisible)
{
m_bVisible = bVisible;
Reposition();
}
}
BOOL CXTPTabManagerItem::IsEnabled() const
{
return m_bEnabled;
}
void CXTPTabManagerItem::SetEnabled(BOOL bEnabled)
{
if (m_bEnabled != bEnabled)
{
m_bEnabled = bEnabled;
Reposition();
}
}
void CXTPTabManagerItem::Move(int nIndex)
{
if (GetIndex() != nIndex)
{
m_pTabManager->MoveItem(this, nIndex);
}
}
BOOL CXTPTabManagerItem::DrawRotatedImage(CDC* pDC, CRect rcItem, CXTPImageManagerIcon* pImage)
{
CXTPImageManagerIconHandle& imageHandle = !IsEnabled() ? pImage->GetDisabledIcon(): IsHighlighted() ? pImage->GetHotIcon() :
IsSelected() ? pImage->GetCheckedIcon() : pImage->GetIcon();
const int cx = rcItem.Width();
const int cy = rcItem.Height();
ASSERT(cx == cy);
if (cx != cy)
return FALSE;
UINT* pSrcBits = NULL, *pDestBits = NULL;
HBITMAP hbmSrc = CXTPImageManager::Create32BPPDIBSection(NULL, cx, cy, (LPBYTE*)&pSrcBits);
if (!pSrcBits)
return FALSE;
HBITMAP hbmDest = CXTPImageManager::Create32BPPDIBSection(NULL, cx, cy, (LPBYTE*)&pDestBits);
if (!pDestBits)
return FALSE;
CDC dc;
dc.CreateCompatibleDC(NULL);
HGDIOBJ hbmpOld = ::SelectObject(dc, hbmSrc);
CRect rcDraw(0, 0, cx, cy);
dc.BitBlt(0, 0, cx, cy, pDC, rcItem.left, rcItem.top, SRCCOPY);
::SelectObject(dc, hbmpOld);
UINT* pSrcInv = pDestBits;
UINT* pDestInv = pSrcBits;
UINT* pDest = &pDestBits[cx];
int i;
for (i = 0; i < cy; i++)
{
pDest -= 1;
pDestBits = pDest;
for (int j = 0; j < cx; j++)
{
*pDestBits = *pSrcBits;
pSrcBits += 1;
pDestBits += cy;
}
}
hbmpOld = ::SelectObject(dc, hbmDest);
pImage->Draw(&dc, rcDraw.TopLeft(), imageHandle, rcDraw.Size());
::SelectObject(dc, hbmpOld);
pDest = &pDestInv[cx * (cy - 1)];
for (i = 0; i < cy; i++)
{
pDestInv = pDest;
for (int j = 0; j < cx; j++)
{
*pDestInv = *pSrcInv;
pSrcInv += 1;
pDestInv -= cy;
}
pDest += 1;
}
pDC->DrawState(rcItem.TopLeft(), rcItem.Size(), hbmSrc, DST_BITMAP);
DeleteObject(hbmSrc);
DeleteObject(hbmDest);
return TRUE;
}
void CXTPTabManagerItem::DrawImage(CDC* pDC, CRect rcIcon, CXTPImageManagerIcon* pImage)
{
if (rcIcon.Width() == rcIcon.Height() && GetTabManager()->GetPaintManager()->m_bRotateImageOnVerticalDraw
&& (GetTabManager()->GetPosition() == xtpTabPositionLeft || GetTabManager()->GetPosition() == xtpTabPositionRight)
&& DrawRotatedImage(pDC, rcIcon, pImage))
{
}
else
{
CXTPImageManagerIconHandle& imageHandle = !IsEnabled() ? pImage->GetDisabledIcon(): IsHighlighted() ? pImage->GetHotIcon() :
IsSelected() ? pImage->GetCheckedIcon() : pImage->GetIcon();
pImage->Draw(pDC, rcIcon.TopLeft(), imageHandle, rcIcon.Size());
}
}
void CXTPTabManagerItem::SetRect(CRect rcItem)
{
m_rcItem = rcItem;
for (int i = (int)m_arrNavigateButtons.GetSize() - 1; i >= 0; i--)
{
CXTPTabManagerNavigateButton* pButton = m_arrNavigateButtons.GetAt(i);
pButton->SetRect(CRect(0, 0, 0, 0));
}
}
//////////////////////////////////////////////////////////////////////////
// CXTPTabManagerNavigateButtons
CXTPTabManagerNavigateButtons::CXTPTabManagerNavigateButtons()
{
}
CXTPTabManagerNavigateButtons::~CXTPTabManagerNavigateButtons()
{
RemoveAll();
}
void CXTPTabManagerNavigateButtons::RemoveAll()
{
for (int i = 0; i < m_arrButtons.GetSize(); i++)
{
delete m_arrButtons[i];
}
m_arrButtons.RemoveAll();
}
void CXTPTabManagerNavigateButtons::RemoveAt(int nIndex)
{
delete m_arrButtons[nIndex];
m_arrButtons.RemoveAt(nIndex);
}
//////////////////////////////////////////////////////////////////////////
// CXTPTabManagerNavigateButton
CXTPTabManagerNavigateButton::CXTPTabManagerNavigateButton(CXTPTabManager* pManager, UINT nID, XTPTabNavigateButtonFlags dwFlags)
{
m_pManager = pManager;
m_nID = nID;
m_dwFlags = dwFlags;
m_rcButton.SetRectEmpty();
m_bEnabled = TRUE;
m_bPressed = FALSE;
m_pItem = NULL;
}
CXTPTabManagerNavigateButton::~CXTPTabManagerNavigateButton()
{
if (m_pManager->m_pHighlightedNavigateButton == this)
m_pManager->m_pHighlightedNavigateButton = NULL;
}
CSize CXTPTabManagerNavigateButton::GetSize() const
{
return m_pManager->GetPaintManager()->m_szNavigateButton;
}
void CXTPTabManagerNavigateButton::AdjustWidth(int& nWidth)
{
if (m_pManager->IsNavigateButtonVisible(this))
{
if ((m_pManager->GetPosition() == xtpTabPositionTop) || (m_pManager->GetPosition() == xtpTabPositionBottom))
{
nWidth -= GetSize().cx;
}
else
{
nWidth -= GetSize().cy;
}
}
}
void CXTPTabManagerNavigateButton::SetRect(CRect rcButton)
{
m_rcButton = rcButton;
}
void CXTPTabManagerNavigateButton::Reposition(CRect& rcNavigateButtons)
{
if (m_pManager->IsNavigateButtonVisible(this))
{
CSize szButton = GetSize();
if (m_pManager->IsHorizontalPosition())
{
m_rcButton.SetRect(rcNavigateButtons.right - szButton.cx, rcNavigateButtons.CenterPoint().y + szButton.cy / 2 - szButton.cy, rcNavigateButtons.right, rcNavigateButtons.CenterPoint().y + szButton.cy / 2);
rcNavigateButtons.right -= szButton.cx;
}
else
{
m_rcButton.SetRect(rcNavigateButtons.CenterPoint().x - szButton.cx / 2, rcNavigateButtons.bottom - szButton.cy, rcNavigateButtons.CenterPoint().x - szButton.cx / 2 + szButton.cx, rcNavigateButtons.bottom);
rcNavigateButtons.bottom -= szButton.cy;
}
}
else
m_rcButton.SetRectEmpty();
}
void CXTPTabManagerNavigateButton::Draw(CDC* pDC)
{
if (!m_rcButton.IsRectEmpty())
{
CRect rc(m_rcButton);
m_pManager->GetPaintManager()->DrawNavigateButton(pDC, this, rc);
}
}
void CXTPTabManagerNavigateButton::PerformClick(HWND hWnd, CPoint pt)
{
if ((::GetCapture() != NULL) || !m_bEnabled)
return;
::SetCapture(hWnd);
BOOL bClick = FALSE;
DWORD dwStart = GetTickCount();
for (;;)
{
if (m_bEnabled && GetTickCount() - dwStart > 20)
{
dwStart = GetTickCount();
OnExecute(TRUE);
}
BOOL bPressed = m_rcButton.PtInRect(pt);
if (bPressed != m_bPressed)
{
m_bPressed = bPressed;
m_pManager->RedrawControl(m_rcButton, TRUE);
}
MSG msg;
if (!::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
continue;
VERIFY(::GetMessage(&msg, NULL, 0, 0));
if (::GetCapture() != hWnd)
{
DispatchMessage (&msg);
goto ExitLoop;
}
switch (msg.message)
{
case WM_MOUSEMOVE:
pt = CPoint((short signed)LOWORD(msg.lParam), (short signed)HIWORD(msg.lParam));
break;
case WM_LBUTTONUP:
bClick = m_bPressed;
goto ExitLoop;
case WM_KEYDOWN:
if (msg.wParam != VK_ESCAPE)
break;
case WM_CANCELMODE:
case WM_RBUTTONDOWN:
goto ExitLoop;
default:
DispatchMessage (&msg);
break;
}
}
ExitLoop:
ReleaseCapture();
m_bPressed = FALSE;
m_pManager->PerformMouseMove(hWnd, pt);
m_pManager->RedrawControl(NULL, FALSE);
if (bClick)
{
OnExecute(FALSE);
}
}
void CXTPTabManagerNavigateButton::OnExecute(BOOL bTick)
{
if (!bTick)
{
m_pManager->OnNavigateButtonClick(this);
}
}
//////////////////////////////////////////////////////////////////////////
// CXTPTabManager::CRowIndexer
CXTPTabManager::CRowIndexer::CRowIndexer(CXTPTabManager* pManager)
{
m_nRowCount = 0;
m_pRowItems = 0;
m_pManager = pManager;
CreateIndexer(1);
}
CXTPTabManager::CRowIndexer::~CRowIndexer()
{
SAFE_DELETE_AR(m_pRowItems);
}
CXTPTabManager::ROW_ITEMS* CXTPTabManager::CRowIndexer::CreateIndexer(int nRowCount)
{
if (m_nRowCount != nRowCount)
{
SAFE_DELETE_AR(m_pRowItems);
m_pRowItems = new ROW_ITEMS[nRowCount];
m_nRowCount = nRowCount;
}
if (nRowCount > 0)
{
m_pRowItems[0].nFirstItem = 0;
m_pRowItems[0].nLastItem = m_pManager->GetItemCount() - 1;
}
return m_pRowItems;
}
//////////////////////////////////////////////////////////////////////////
// CXTPTabManager::CNavigateButtonArrow
class CXTPTabManager::CNavigateButtonArrow : public CXTPTabManagerNavigateButton
{
protected:
CNavigateButtonArrow(CXTPTabManager* pManager, XTPTabNavigateButton nID, XTPTabNavigateButtonFlags dwFlags)
: CXTPTabManagerNavigateButton(pManager, nID, dwFlags)
{
}
virtual void Reposition(CRect& rcNavigateButtons);
virtual void AdjustWidth(int& nWidth);
};
class CXTPTabManager::CNavigateButtonArrowLeft : public CNavigateButtonArrow
{
public:
CNavigateButtonArrowLeft(CXTPTabManager* pManager, XTPTabNavigateButtonFlags dwFlags)
: CNavigateButtonArrow(pManager, xtpTabNavigateButtonLeft, dwFlags)
{
}
protected:
virtual void DrawEntry(CDC* pDC, CRect rc);
virtual void Reposition(CRect& rcNavigateButtons);
virtual void OnExecute(BOOL bTick);
};
class CXTPTabManager::CNavigateButtonArrowRight : public CNavigateButtonArrow
{
public:
CNavigateButtonArrowRight(CXTPTabManager* pManager, XTPTabNavigateButtonFlags dwFlags)
: CNavigateButtonArrow(pManager, xtpTabNavigateButtonRight, dwFlags)
{
}
protected:
virtual void DrawEntry(CDC* pDC, CRect rc);
virtual void Reposition(CRect& rcNavigateButtons);
virtual void OnExecute(BOOL bTick);
};
class CXTPTabManager::CNavigateButtonClose : public CXTPTabManagerNavigateButton
{
public:
CNavigateButtonClose(CXTPTabManager* pManager, XTPTabNavigateButtonFlags dwFlags)
: CXTPTabManagerNavigateButton(pManager, xtpTabNavigateButtonClose, dwFlags)
{
CXTPResourceManager::AssertValid(XTPResourceManager()->LoadString(&m_strToolTip, XTP_IDS_TABNAVIGATEBUTTON_CLOSE));
}
protected:
virtual void DrawEntry(CDC* pDC, CRect rc);
};
class CXTPTabManager::CNavigateButtonTabClose : public CXTPTabManager::CNavigateButtonClose
{
public:
CNavigateButtonTabClose(CXTPTabManagerItem* pItem, XTPTabNavigateButtonFlags dwFlags)
: CXTPTabManager::CNavigateButtonClose(pItem->GetTabManager(), dwFlags)
{
m_pItem = pItem;
}
};
void CXTPTabManager::CNavigateButtonClose::DrawEntry(CDC* pDC, CRect rc)
{
CPoint pt = rc.CenterPoint();
pDC->MoveTo(pt.x - 4, pt.y - 3);
pDC->LineTo(pt.x + 3, pt.y + 4);
pDC->MoveTo(pt.x - 3, pt.y - 3);
pDC->LineTo(pt.x + 4, pt.y + 4);
pDC->MoveTo(pt.x - 4, pt.y + 3);
pDC->LineTo(pt.x + 3, pt.y - 4);
pDC->MoveTo(pt.x - 3, pt.y + 3);
pDC->LineTo(pt.x + 4, pt.y - 4);
}
void CXTPTabManager::CNavigateButtonArrowRight::DrawEntry(CDC* pDC, CRect rc)
{
CPoint pt = rc.CenterPoint();
if (m_pManager->IsHorizontalPosition())
CXTPDrawHelpers::Triangle(pDC, CPoint(pt.x - 2, pt.y - 5), CPoint(pt.x + 2, pt.y - 1), CPoint(pt.x - 2, pt.y + 3));
else
CXTPDrawHelpers::Triangle(pDC, CPoint(pt.x - 5, pt.y - 2), CPoint(pt.x - 1, pt.y + 2), CPoint(pt.x + 3, pt.y - 2));
}
void CXTPTabManager::CNavigateButtonArrow::AdjustWidth(int& nWidth)
{
if (m_dwFlags == xtpTabNavigateButtonAlways)
{
if ((m_pManager->GetPosition() == xtpTabPositionTop) || (m_pManager->GetPosition() == xtpTabPositionBottom))
{
nWidth -= GetSize().cx;
}
else
{
nWidth -= GetSize().cy;
}
}
}
void CXTPTabManager::CNavigateButtonArrow::Reposition(CRect& rcNavigateButtons)
{
if (m_pManager->GetLayout() == xtpTabLayoutMultiRow)
{
m_rcButton.SetRectEmpty();
return;
}
if (m_dwFlags == xtpTabNavigateButtonAutomatic)
{
if (m_pManager->GetLayout() == xtpTabLayoutSizeToFit)
{
m_rcButton.SetRectEmpty();
return;
}
CRect rc = m_pManager->GetAppearanceSet()->GetHeaderMargin();
if (!(m_pManager->GetItemsLength() + m_pManager->GetHeaderOffset() - rc.left - 1 > m_pManager->GetRectLength(rcNavigateButtons) - (rc.left + rc.right)
|| m_pManager->GetHeaderOffset() < 0))
{
m_rcButton.SetRectEmpty();
return;
}
}
CXTPTabManagerNavigateButton::Reposition(rcNavigateButtons);
}
void CXTPTabManager::CNavigateButtonArrowRight::Reposition(CRect& rcNavigateButtons)
{
XTPResourceManager()->LoadString(&m_strToolTip, m_pManager->IsHorizontalPosition() ? XTP_IDS_TABNAVIGATEBUTTON_RIGHT : XTP_IDS_TABNAVIGATEBUTTON_DOWN);
CRect rcHeaderMargin = m_pManager->GetPaintManager()->GetAppearanceSet()->GetHeaderMargin();
m_bEnabled = m_pManager->GetItemsLength() + m_pManager->GetHeaderOffset() >
m_pManager->GetRectLength(rcNavigateButtons) - (rcHeaderMargin.left + rcHeaderMargin.right) - 28;
CNavigateButtonArrow::Reposition(rcNavigateButtons);
}
void CXTPTabManager::CNavigateButtonArrowRight::OnExecute(BOOL bTick)
{
if (bTick)
{
m_pManager->OnScrollHeader(TRUE);
}
}
void CXTPTabManager::OnScrollHeader(BOOL bRight)
{
if (bRight)
{
SetHeaderOffset(GetHeaderOffset() - m_nScrollDelta);
}
else
{
SetHeaderOffset(GetHeaderOffset() + m_nScrollDelta);
}
}
void CXTPTabManager::CNavigateButtonArrowLeft::DrawEntry(CDC* pDC, CRect rc)
{
CPoint pt = rc.CenterPoint();
if (m_pManager->IsHorizontalPosition())
CXTPDrawHelpers::Triangle(pDC, CPoint(pt.x + 2, pt.y - 5), CPoint(pt.x - 2, pt.y - 1), CPoint(pt.x + 2, pt.y + 3));
else
CXTPDrawHelpers::Triangle(pDC, CPoint(pt.x - 5, pt.y + 2), CPoint(pt.x - 1, pt.y - 2), CPoint(pt.x + 3, pt.y + 2));
}
void CXTPTabManager::CNavigateButtonArrowLeft::Reposition(CRect& rcNavigateButtons)
{
XTPResourceManager()->LoadString(&m_strToolTip, m_pManager->IsHorizontalPosition() ? XTP_IDS_TABNAVIGATEBUTTON_LEFT : XTP_IDS_TABNAVIGATEBUTTON_UP);
m_bEnabled = m_pManager->GetHeaderOffset() < 0;
CNavigateButtonArrow::Reposition(rcNavigateButtons);
}
void CXTPTabManager::CNavigateButtonArrowLeft::OnExecute(BOOL bTick)
{
if (bTick)
{
m_pManager->OnScrollHeader(FALSE);
}
}
//////////////////////////////////////////////////////////////////////
// CXTPTabManager
CXTPTabManager::CXTPTabManager()
{
m_pSelected = 0;
m_pHighlighted = 0;
m_pPressed = 0;
m_nHeaderOffset = 0;
m_bAllowReorder = TRUE;
m_bActive = TRUE;
m_nScrollDelta = 20;
m_rcHeaderRect.SetRectEmpty();
m_rcControl.SetRectEmpty();
m_rcClient.SetRectEmpty();
m_bCloseItemButton = xtpTabNavigateButtonNone;
m_pHighlightedNavigateButton = NULL;
m_pRowIndexer = new CRowIndexer(this);
m_arrNavigateButtons.Add(new CNavigateButtonArrowLeft(this, xtpTabNavigateButtonAutomatic));
m_arrNavigateButtons.Add(new CNavigateButtonArrowRight(this, xtpTabNavigateButtonAutomatic));
m_arrNavigateButtons.Add(new CNavigateButtonClose(this, xtpTabNavigateButtonNone));
m_pMarkupContext = NULL;
}
CXTPTabManager::~CXTPTabManager()
{
for (int i = 0; i < m_arrItems.GetSize(); i++)
{
CXTPTabManagerItem* pItem = m_arrItems[i];
pItem->OnRemoved();
pItem->InternalRelease();
}
m_arrNavigateButtons.RemoveAll();
delete m_pRowIndexer;
XTPMarkupReleaseContext(m_pMarkupContext);
}
void CXTPTabManager::EnableMarkup(BOOL bEnable)
{
BOOL bMarkupContext = m_pMarkupContext != NULL;
if (bMarkupContext == bEnable)
return;
for (int i = 0; i < m_arrItems.GetSize(); i++)
{
XTPMarkupReleaseElement(m_arrItems[i]->m_pMarkupUIElement);
}
XTPMarkupReleaseContext(m_pMarkupContext);
if (bEnable)
{
m_pMarkupContext = XTPMarkupCreateContext();
}
}
void CXTPTabManager::SetActive(BOOL bActive)
{
if (m_bActive != bActive)
{
m_bActive = bActive;
Reposition();
}
}
BOOL CXTPTabManager::IsNavigateButtonVisible(CXTPTabManagerNavigateButton* pButton)
{
if (pButton->GetFlags() == xtpTabNavigateButtonAutomatic)
return IsNavigateButtonAutomaticVisible(pButton);
if (pButton->GetFlags() == xtpTabNavigateButtonAlways)
{
if (pButton->GetID() == xtpTabNavigateButtonClose && pButton->GetItem())
{
return pButton->GetItem()->IsClosable();
}
return TRUE;
}
return FALSE;
}
BOOL CXTPTabManager::IsNavigateButtonAutomaticVisible(CXTPTabManagerNavigateButton* pButton)
{
if (pButton->GetID() == xtpTabNavigateButtonClose)
{
if (pButton->GetItem())
{
return pButton->GetItem()->IsSelected() ? pButton->GetItem()->IsClosable() : FALSE;
}
return m_pSelected ? m_pSelected->IsClosable() : FALSE;
}
return TRUE;
}
void CXTPTabManager::EnableTabThemeTexture(HWND hWnd, BOOL bEnable)
{
CXTPWinThemeWrapper themeTabControl; // Internal helper for drawing XP interface parts.
themeTabControl.OpenTheme(hWnd, L"TAB");
themeTabControl.EnableThemeDialogTexture(hWnd, bEnable ? ETDT_ENABLETAB : ETDT_DISABLE | ETDT_USETABTEXTURE);
}
CXTPTabManagerNavigateButton* CXTPTabManager::FindNavigateButton(UINT nID) const
{
for (int i = 0; i < m_arrNavigateButtons.GetSize(); i++)
{
if (m_arrNavigateButtons[i]->m_nID == nID)
return m_arrNavigateButtons[i];
}
return NULL;
}
void CXTPTabManager::SetHeaderOffset(int nOffset)
{
if (nOffset > 0) nOffset = 0;
if (nOffset != m_nHeaderOffset)
{
m_nHeaderOffset = nOffset;
Reposition();
}
}
int CXTPTabManager::GetItemsLength() const
{
int nLength = 0;
if (GetLayout() == xtpTabLayoutRotated)
{
nLength = GetPaintManager()->GetAppearanceSet()->GetButtonHeight(this)
* GetItemCount();
}
else
{
for (int i = 0; i < GetItemCount(); i++)
nLength += GetItem(i)->GetButtonLength();
}
return nLength;
}
void CXTPTabManager::DeleteAllItems()
{
for (int i = 0; i < m_arrItems.GetSize(); i++)
{
CXTPTabManagerItem* pItem = m_arrItems[i];
pItem->OnRemoved();
pItem->InternalRelease();
}
m_arrItems.RemoveAll();
m_pHighlighted = m_pSelected = m_pPressed = NULL;
OnItemsChanged();
}
BOOL CXTPTabManager::DeleteItem(int nItem)
{
if (nItem < 0 || nItem >= GetItemCount())
return FALSE;
CXTPTabManagerItem* pItem = m_arrItems[nItem];
BOOL bSelected = (m_pSelected == pItem);
if (m_pHighlighted == pItem)
m_pHighlighted = NULL;
m_arrItems.RemoveAt(nItem);
pItem->OnRemoved();
pItem->InternalRelease();
if (bSelected)
{
SetCurSel(nItem);
}
OnItemsChanged();
return TRUE;
}
CXTPTabManagerItem* CXTPTabManager::AddItem(int nItem, CXTPTabManagerItem* pItem /*= NULL*/)
{
if (!pItem)
pItem = new CXTPTabManagerItem();
pItem->m_pTabManager = this;
if (nItem < 0 || nItem > GetItemCount())
nItem = GetItemCount();
m_arrItems.InsertAt(nItem, pItem);
pItem->m_clrItem = xtpTabColorBlue + (GetPaintManager()->m_nItemColor++ % 8);
if (m_bCloseItemButton != xtpTabNavigateButtonNone)
{
pItem->m_arrNavigateButtons.Add(new CNavigateButtonTabClose(pItem, m_bCloseItemButton));
}
OnItemsChanged();
return pItem;
}
void CXTPTabManager::OnItemsChanged()
{
for (int i = 0; i < GetItemCount(); i++)
{
GetItem(i)->m_nIndex = i;
}
Reposition();
}
CString CXTPTabManager::GetItemCaption(const CXTPTabManagerItem* pItem) const
{
return pItem->m_strCaption;
}
HICON CXTPTabManager::GetItemIcon(const CXTPTabManagerItem* pItem) const
{
return pItem->m_hIcon;
}
void CXTPTabManager::ShowIcons(BOOL bShowIcons)
{
GetPaintManager()->m_bShowIcons = bShowIcons;
Reposition();
}
COLORREF CXTPTabManager::GetItemColor(const CXTPTabManagerItem* pItem) const
{
COLORREF nColor = pItem->m_clrItem;
if (nColor >= xtpTabColorBlue && nColor <= xtpTabColorMagenta)
return CXTPTabPaintManager::GetOneNoteColor((XTPTabOneNoteColor)nColor);
return nColor;
}
void CXTPTabManager::SetCurSel(int nIndex)
{
if (GetItemCount() != 0)
{
nIndex = nIndex < 0 ? 0: nIndex >= GetItemCount() ? GetItemCount() - 1 : nIndex;
SetSelectedItem(GetItem(nIndex));
}
else
{
SetSelectedItem(NULL);
}
}
int CXTPTabManager::GetCurSel() const
{
if (m_pSelected)
{
return m_pSelected->GetIndex();
}
return -1;
}
void CXTPTabManager::SetSelectedItem(CXTPTabManagerItem* pItem)
{
if (m_pSelected != pItem)
{
m_pSelected = pItem;
Reposition();
EnsureVisible(pItem);
}
}
void CXTPTabManager::EnsureVisible(CXTPTabManagerItem* pItem)
{
if (!pItem)
return;
GetPaintManager()->EnsureVisible(this, pItem);
}
void CXTPTabManager::SetPosition(XTPTabPosition tabPosition)
{
GetPaintManager()->m_tabPosition = tabPosition;
Reposition();
}
void CXTPTabManager::SetLayoutStyle(XTPTabLayoutStyle tabLayout)
{
GetPaintManager()->m_tabLayout = tabLayout;
Reposition();
}
CXTPTabManagerItem* CXTPTabManager::HitTest(CPoint point) const
{
if (!m_rcControl.PtInRect(point))
return NULL;
if (!m_rcHeaderRect.IsRectEmpty() && !m_rcHeaderRect.PtInRect(point))
return NULL;
for (int i = 0; i < GetItemCount(); i++)
{
CXTPTabManagerItem* pItem = GetItem(i);
if (pItem->GetRect().PtInRect(point) && pItem->IsEnabled() && pItem->IsVisible())
{
return pItem;
}
}
return NULL;
}
XTPTabPosition CXTPTabManager::GetPosition() const
{
return GetPaintManager()->m_tabPosition;
}
XTPTabLayoutStyle CXTPTabManager::GetLayout() const
{
return GetPaintManager()->m_tabLayout;
}
void CXTPTabManager::MoveItem(CXTPTabManagerItem* pItem, int nIndex)
{
ASSERT(pItem && pItem->GetTabManager() == this);
if (!pItem || pItem->GetTabManager() != this)
return;
int nOldIndex = pItem->GetIndex();
if (nOldIndex == nIndex)
return;
ASSERT(nOldIndex >= 0);
ASSERT(nIndex >= 0 && nIndex < GetItemCount());
if (nIndex < 0 || nIndex >= GetItemCount())
nIndex = GetItemCount() - 1;
m_arrItems.RemoveAt(nOldIndex);
m_arrItems.InsertAt(nIndex, pItem);
OnItemsChanged();
}
void CXTPTabManager::TrackClick(HWND hWnd, CPoint pt, CXTPTabManagerItem* pItem)
{
if (GetPaintManager()->m_bHotTracking)
m_pHighlighted = pItem;
m_pPressed = pItem;
BOOL bHighlighted = TRUE;
Reposition();
BOOL bAccept = FALSE;
::SetCapture(hWnd);
while (::GetCapture() == hWnd)
{
MSG msg;
VERIFY(::GetMessage(&msg, NULL, 0, 0));
if (::GetCapture() != hWnd)
{
DispatchMessage (&msg);
break;
}
switch (msg.message)
{
case WM_MOUSEMOVE:
{
pt = CPoint((short signed)LOWORD(msg.lParam), (short signed)HIWORD(msg.lParam));
bHighlighted = pItem->GetRect().PtInRect(pt);
if (GetPaintManager()->m_bHotTracking)
{
CXTPTabManagerItem* pHighlighted = bHighlighted ? pItem : NULL;
if (pHighlighted != m_pHighlighted)
{
m_pHighlighted = pHighlighted;
RedrawControl(pItem->GetRect(), TRUE);
}
}
}
break;
case WM_KEYDOWN:
if (msg.wParam != VK_ESCAPE)
break;
case WM_CANCELMODE:
case WM_RBUTTONDOWN:
goto ExitLoop;
case WM_LBUTTONUP:
bAccept = TRUE;
goto ExitLoop;
default:
DispatchMessage (&msg);
break;
}
}
ExitLoop:
ReleaseCapture();
m_pPressed = FALSE;
PerformMouseMove(hWnd, pt);
RedrawControl(NULL, FALSE);
if (bAccept && bHighlighted)
{
OnItemClick(pItem);
}
}
void CXTPTabManager::ReOrder(HWND hWnd, CPoint pt, CXTPTabManagerItem* pItem)
{
CXTPTabManagerItem* pSelected = m_pSelected;
m_pSelected = pItem;
if (GetPaintManager()->m_bHotTracking)
m_pHighlighted = pItem;
Reposition();
CArray<CRect, CRect&> arrRects;
for (int j = 0; j < GetItemCount(); j++)
{
CRect rc = GetItem(j)->GetRect();
arrRects.Add(rc);
}
int nIndex = pItem->GetIndex();
::SetCapture(hWnd);
while (::GetCapture() == hWnd)
{
MSG msg;
VERIFY(::GetMessage(&msg, NULL, 0, 0));
if (::GetCapture() != hWnd)
{
DispatchMessage (&msg);
break;
}
switch (msg.message)
{
case WM_MOUSEMOVE:
{
pt = CPoint((short signed)LOWORD(msg.lParam), (short signed)HIWORD(msg.lParam));
for (int i = 0; i < arrRects.GetSize(); i++)
{
if (i != pItem->GetIndex() && arrRects[i].PtInRect(pt))
{
while (i != pItem->GetIndex())
{
int j = i < pItem->GetIndex() ? pItem->GetIndex() - 1 : pItem->GetIndex() + 1;
CXTPTabManagerItem* p1 = pItem;
CXTPTabManagerItem* p2 = m_arrItems[pItem->GetIndex()] = m_arrItems[j];
m_arrItems[j] = p1;
OnItemsChanged();
OnSwitchItem(p1, p2);
}
break;
}
}
}
break;
case WM_KEYDOWN:
if (msg.wParam != VK_ESCAPE)
break;
case WM_CANCELMODE:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
goto ExitLoop;
default:
DispatchMessage (&msg);
break;
}
}
ExitLoop:
ReleaseCapture();
PerformMouseMove(hWnd, pt);
m_pSelected = pSelected;
OnItemClick(pItem);
if (nIndex != pItem->GetIndex())
{
OnItemOrderChanged(pItem, nIndex, pItem->GetIndex());
}
}
void CXTPTabManager::OnItemClick(CXTPTabManagerItem* pItem)
{
SetSelectedItem(pItem);
}
void CXTPTabManager::SetFocusedItem(CXTPTabManagerItem* pItem)
{
if (!OnBeforeItemClick(pItem))
return;
if (pItem)
{
OnItemClick(pItem);
}
}
CXTPTabManagerItem* CXTPTabManager::FindNextFocusable(int nIndex, int nDirection) const
{
CXTPTabManagerItem* pItem = NULL;
do
{
nIndex += nDirection;
pItem = GetItem(nIndex);
if (!pItem)
return NULL;
}
while (!(pItem->IsVisible() && pItem->IsEnabled()));
return pItem;
}
BOOL CXTPTabManager::PerformKeyDown(HWND hWnd, UINT nChar)
{
const int nCount = GetItemCount();
if (nCount < 1)
return FALSE;
if (nChar == VK_LEFT && (DWORD)GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
nChar = VK_RIGHT;
else if (nChar == VK_RIGHT && (DWORD)GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
nChar = VK_LEFT;
switch (nChar)
{
case VK_HOME:
SetFocusedItem(FindNextFocusable(-1, +1));
return TRUE;
case VK_END:
SetFocusedItem(FindNextFocusable(nCount, -1));
return TRUE;
case VK_LEFT:
if (IsHorizontalPosition() && m_pSelected && m_pSelected->GetIndex() > 0)
SetFocusedItem(FindNextFocusable(m_pSelected->GetIndex(), -1));
return TRUE;
case VK_UP:
if (!IsHorizontalPosition() && m_pSelected && m_pSelected->GetIndex() > 0)
SetFocusedItem(FindNextFocusable(m_pSelected->GetIndex(), -1));
return TRUE;
case VK_RIGHT:
if (IsHorizontalPosition() && m_pSelected && m_pSelected->GetIndex() < nCount - 1)
SetFocusedItem(FindNextFocusable(m_pSelected->GetIndex(), + 1));
return TRUE;
case VK_DOWN:
if (!IsHorizontalPosition() && m_pSelected && m_pSelected->GetIndex() < nCount - 1)
SetFocusedItem(FindNextFocusable(m_pSelected->GetIndex(), + 1));
return TRUE;
}
return FALSE;
}
BOOL CXTPTabManager::OnBeforeItemClick(CXTPTabManagerItem* /*pItem*/)
{
return TRUE;
}
CXTPTabManagerNavigateButton* CXTPTabManager::HitTestNavigateButton(CPoint point, BOOL bHeaderOnly, int* pnIndex) const
{
int i;
for (i = 0; i < (int)m_arrNavigateButtons.GetSize(); i++)
{
CXTPTabManagerNavigateButton* pButton = m_arrNavigateButtons[i];
if (pButton->m_rcButton.PtInRect(point))
{
if (!pButton->IsEnabled())
return NULL;
if (pnIndex)
{
*pnIndex = i;
}
return pButton;
}
}
if (bHeaderOnly)
return NULL;
CXTPTabManagerItem* pItem = HitTest(point);
if (!pItem)
return NULL;
for (i = 0; i < (int)pItem->GetNavigateButtons()->GetSize(); i++)
{
CXTPTabManagerNavigateButton* pButton = pItem->GetNavigateButtons()->GetAt(i);
if (pButton->m_rcButton.PtInRect(point))
{
if (!pButton->IsEnabled())
return NULL;
if (pnIndex)
{
*pnIndex = i;
}
return pButton;
}
}
return NULL;
}
BOOL CXTPTabManager::PerformClick(HWND hWnd, CPoint pt, BOOL bNoItemClick)
{
CXTPTabManagerNavigateButton* pNavigateButton = HitTestNavigateButton(pt, FALSE);
if (pNavigateButton)
{
pNavigateButton->PerformClick(hWnd, pt);
return TRUE;
}
if (bNoItemClick)
return FALSE;
CXTPTabManagerItem* pItem = HitTest(pt);
if (pItem)
{
if (!OnBeforeItemClick(pItem))
return FALSE;
if (IsAllowReorder())
{
ReOrder(hWnd, pt, pItem);
}
else if (GetPaintManager()->m_bSelectOnButtonDown)
{
OnItemClick(pItem);
}
else
{
TrackClick(hWnd, pt, pItem);
}
return TRUE;
}
return FALSE;
}
void CXTPTabManager::PerformMouseMove(HWND hWnd, CPoint pt)
{
CXTPTabPaintManagerAppearanceSet* pAppearance = GetPaintManager()->GetAppearanceSet();
if (!CXTPDrawHelpers::IsTopParentActive(hWnd) || IsMouseLocked())
{
if (m_pHighlighted)
{
CRect rcRedraw(pAppearance->GetButtonDrawRect(m_pHighlighted));
m_pHighlighted = NULL;
RedrawControl(rcRedraw, TRUE);
}
return;
}
if (GetPaintManager()->m_bHotTracking)
{
CXTPTabManagerItem* pItem = HitTest(pt);
if (pItem != m_pHighlighted)
{
if (m_pHighlighted)
{
CRect rcRedraw(pAppearance->GetButtonDrawRect(m_pHighlighted));
m_pHighlighted = NULL;
RedrawControl(rcRedraw, TRUE);
}
m_pHighlighted = pItem;
if (m_pHighlighted)
{
RedrawControl(pAppearance->GetButtonDrawRect(m_pHighlighted), FALSE);
}
if (pItem)
{
TRACKMOUSEEVENT tme =
{
sizeof(TRACKMOUSEEVENT), TME_LEAVE, hWnd
};
_TrackMouseEvent(&tme);
}
}
}
CXTPTabManagerNavigateButton* pNavigateButton = HitTestNavigateButton(pt, FALSE);
if (pNavigateButton != m_pHighlightedNavigateButton)
{
if (m_pHighlightedNavigateButton)
{
RedrawControl(m_pHighlightedNavigateButton->GetRect(), TRUE);
}
m_pHighlightedNavigateButton = pNavigateButton;
if (m_pHighlightedNavigateButton)
{
RedrawControl(m_pHighlightedNavigateButton->GetRect(), FALSE);
}
if (pNavigateButton)
{
TRACKMOUSEEVENT tme =
{
sizeof(TRACKMOUSEEVENT), TME_LEAVE, hWnd
};
_TrackMouseEvent(&tme);
}
}
}
CString CXTPTabManager::GetItemTooltip(const CXTPTabManagerItem* pItem) const
{
return pItem->m_strToolTip;
}
INT_PTR CXTPTabManager::PerformToolHitTest(HWND hWnd, CPoint point, TOOLINFO* pTI) const
{
if (IsMouseLocked())
return -1;
int nIndex = -1;
CXTPTabManagerNavigateButton* pNavigateButton = HitTestNavigateButton(point, FALSE, &nIndex);
if (pNavigateButton)
{
ASSERT(nIndex != -1);
CString strTip = pNavigateButton->GetTooltip();
if (strTip.IsEmpty())
return -1;
CXTPToolTipContext::FillInToolInfo(pTI, hWnd, pNavigateButton->GetRect(), nIndex, strTip);
return nIndex;
}
CXTPTabManagerItem* pItem = HitTest(point);
if (pItem)
{
if (GetPaintManager()->m_toolBehaviour == xtpTabToolTipNever)
return -1;
if (GetPaintManager()->m_toolBehaviour == xtpTabToolTipShrinkedOnly && !pItem->IsItemShrinked())
return -1;
CString strTip = GetItemTooltip(pItem);
if (strTip.IsEmpty())
return -1;
CXTPToolTipContext::FillInToolInfo(pTI, hWnd, pItem->GetRect(), pItem->GetIndex(), strTip, pItem->GetCaption(), strTip);
return pItem->GetIndex();
}
return -1;
}
void CXTPTabManager::GetItemMetrics(CSize* lpszNormal, CSize* lpszMin /*= NULL*/, CSize* lpszMax /*= NULL*/) const
{
CXTPTabPaintManager* pPaintManager = GetPaintManager();
if (lpszNormal) *lpszNormal = CSize(pPaintManager->m_nFixedTabWidth, 0);
if (lpszMin) *lpszMin = CSize(pPaintManager->m_nMinTabWidth, 0);
if (lpszMax) *lpszMax = CSize(pPaintManager->m_nMaxTabWidth, 0);
}
void CXTPTabManager::SetItemMetrics(CSize szNormal, CSize szMin /*= CSize(0, 0)*/, CSize szMax /*= CSize(0, 0)*/)
{
CXTPTabPaintManager* pPaintManager = GetPaintManager();
pPaintManager->m_nFixedTabWidth = szNormal.cx;
pPaintManager->m_nMinTabWidth = szMin.cx;
pPaintManager->m_nMaxTabWidth = szMax.cx;
Reposition();
}
BOOL CXTPTabManager::IsDrawStaticFrame() const
{
return GetPaintManager()->m_bStaticFrame;
}
CXTPTabPaintManagerColorSet* CXTPTabManager::SetColor(XTPTabColorStyle tabColor)
{
CXTPTabPaintManagerColorSet* pColorSet = GetPaintManager()->SetColor(tabColor);
Reposition();
return pColorSet;
}
CXTPTabPaintManagerColorSet* CXTPTabManager::SetColorSet(CXTPTabPaintManagerColorSet* pColorSet)
{
GetPaintManager()->SetColorSet(pColorSet);
Reposition();
return pColorSet;
}
CXTPTabPaintManagerAppearanceSet* CXTPTabManager::SetAppearance(XTPTabAppearanceStyle tabAppearance)
{
CXTPTabPaintManagerAppearanceSet* pAppearanceSet = GetPaintManager()->SetAppearance(tabAppearance);
Reposition();
return pAppearanceSet;
}
CXTPTabPaintManagerAppearanceSet* CXTPTabManager::SetAppearanceSet(CXTPTabPaintManagerAppearanceSet* pAppearanceSet)
{
GetPaintManager()->SetAppearanceSet(pAppearanceSet);
Reposition();
return pAppearanceSet;
}
CXTPTabPaintManagerAppearanceSet* CXTPTabManager::GetAppearanceSet() const
{
return GetPaintManager()->GetAppearanceSet();
}
CXTPTabPaintManagerColorSet* CXTPTabManager::GetColorSet() const
{
return GetPaintManager()->GetColorSet();
}
XTPTabAppearanceStyle CXTPTabManager::GetAppearance() const
{
return GetPaintManager()->GetAppearance();
}
XTPTabColorStyle CXTPTabManager::GetColor() const
{
return GetPaintManager()->GetColor();
}