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.

437 lines
9.3 KiB
C++

// XTPTabCtrlButtons.cpp : implementation of the CXTPTabCtrlButtons class.
//
// This file is a part of the XTREME CONTROLS 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 "Common/XTPColorManager.h"
#include "Common/XTPDrawHelpers.h"
#include "../Util/XTPControlTheme.h"
#include "XTPTabCtrlButtons.h"
#include "XTPTabBaseTheme.h"
#include "XTPTabBase.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DB_LEFT 0x0002
#define DB_RIGHT 0x0004
#define DB_CROSS 0x0008
#define DB_ENABLED 0x0000
#define DB_DISABLED 0x0100
#define DB_PRESSED 0x1000
#define DB_OVER 0x4000
#define DB_ISENABLED(Style) (!((Style)&DB_DISABLED))
#define DB_ISPRESSED(Style) (((Style) & (DB_PRESSED)) != 0)
#define DB_ISOVER(Style) (((Style)&DB_OVER) == DB_OVER)
void CXTPTabCtrlButton::SetEnable(BOOL bEnable)
{
if (!bEnable)
m_wStyle |= DB_DISABLED;
else
m_wStyle &= ~DB_DISABLED;
}
void CXTPTabCtrlButton::Draw (CDC* pDC, COLORREF clrButton)
{
m_pButtons->m_pTabCtrlBase->GetTheme()->DrawButton(pDC, this, clrButton);
}
DWORD CXTPTabCtrlButton::Click (CXTPTabCtrlButtons* pWnd, CPoint pt, BOOL bRepeat)
{
if ((::GetCapture() != NULL) || !DB_ISENABLED(m_wStyle))
{
return FALSE;
}
pWnd->SetCapture();
ASSERT(pWnd == CWnd::GetCapture());
BOOL bDown = FALSE, bClick = FALSE;
CRect rcBtn(m_Rect);
UINT_PTR nTimer = (bRepeat == FALSE) ? 0 : SetTimer(pWnd->GetSafeHwnd(), 1, 150, NULL);
for (;;)
{
if (bRepeat && DB_ISENABLED(m_wStyle))
{
ASSERT(m_pTabCtrl);
if (!m_pTabCtrl)
return FALSE;
int nCount = m_pTabCtrl->GetItemCount();
CRect rc;
m_pTabCtrl->GetItemRect(-1, rc);
TCHITTESTINFO hi = {{5, rc.CenterPoint().y}};
int nFirst = m_pTabCtrl->HitTest(&hi);
if (m_wStyle & DB_LEFT)
{
if (nFirst > 0)
m_pTabCtrl->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, nFirst - 1), 0);
}
else if (nCount > 0)
{
m_pTabCtrl->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, nFirst + 1), 0);
}
m_pTabCtrl->Invalidate(FALSE);
pWnd->Invalidate(FALSE);
}
BOOL bNewDown = ::PtInRect (rcBtn, pt) != 0;
if (bNewDown != bDown)
{
bDown = bNewDown;
if (bDown)
m_wStyle = m_wStyle | DB_PRESSED;
else
m_wStyle &= ~DB_PRESSED;
pWnd->InvalidateRect (m_Rect, FALSE);
}
MSG msg;
VERIFY(::GetMessage(&msg, NULL, 0, 0));
if (CWnd::GetCapture() != pWnd)
{
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 = bDown;
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();
if (nTimer) KillTimer(*pWnd, nTimer);
m_wStyle &= ~DB_PRESSED;
CheckForMouseOver (pWnd, pt);
pWnd->InvalidateRect (m_Rect, FALSE);
return bClick;
}
void CXTPTabCtrlButton::CheckForMouseOver (CWnd* pWnd, CPoint pt)
{
if (!PtInRect (pt) && DB_ISOVER(m_wStyle))
{
m_wStyle &= ~DB_OVER;
pWnd->InvalidateRect (m_Rect, FALSE);
}
if (!DB_ISOVER(m_wStyle) && PtInRect (pt) && DB_ISENABLED(m_wStyle))
{
TRACKMOUSEEVENT tme =
{
sizeof(TRACKMOUSEEVENT), TME_LEAVE, *pWnd, 0
};
_TrackMouseEvent(&tme);
m_wStyle |= DB_OVER;
pWnd->InvalidateRect (m_Rect, FALSE);
}
}
/////////////////////////////////////////////////////////////////////////////
// CXTPTabCtrlButtons
CXTPTabCtrlButtons::CXTPTabCtrlButtons()
: m_btnClose(DB_CROSS), m_btnLeft(DB_LEFT), m_btnRight(DB_RIGHT)
{
m_dwFlags = xtpNavBtnArrows;
m_bShow = FALSE;
m_hwndSubclassed = 0;
m_hwndPrimary = 0;
m_pTabCtrlBase = 0;
m_pTabCtrl = 0;
m_btnRight.m_pButtons = m_btnClose.m_pButtons = m_btnLeft.m_pButtons = this;
}
CXTPTabCtrlButtons::~CXTPTabCtrlButtons()
{
}
BEGIN_MESSAGE_MAP(CXTPTabCtrlButtons, CWnd)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_WINDOWPOSCHANGED()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()
void CXTPTabCtrlButtons::OnPaint()
{
CPaintDC dcPaint(this);
CXTPClientRect rc(m_pTabCtrl);
CXTPClientRect rcClient(this);
CXTPBufferDC dc(dcPaint, rc);
int nCount = m_pTabCtrl->GetItemCount();
if (!m_bShow || nCount == 0)
{
CWnd::DefWindowProc(WM_PAINT, (WPARAM)dc.m_hDC, 0);
return;
}
COLORREF clrText =m_pTabCtrlBase->GetTheme()->FillButtons(&dc, this);
CRect rcItem;
m_pTabCtrl->GetItemRect(-1, &rcItem);
int nTop = (rcItem.Height() - 13) / 2;
int nRight = rcClient.right - 5;
if (m_dwFlags & xtpNavBtnClose)
{
m_btnClose.SetRect(CRect(nRight - 14, nTop, nRight, nTop + 15));
m_btnClose.Draw(&dc, clrText);
nRight -= 14;
}
else
m_btnClose.SetRect(CXTPEmptyRect());
if (m_dwFlags & xtpNavBtnArrows)
{
ASSERT(m_pTabCtrl);
if (!m_pTabCtrl)
return;
BOOL bEnableRight = FALSE, bEnableLeft = FALSE;
if (nCount > 0)
{
CRect rcLastItem;
m_pTabCtrl->GetItemRect(nCount - 1, &rcLastItem);
bEnableRight = rcLastItem.right > rc.Width() - GetWidth();
m_pTabCtrl->GetItemRect(0, &rcLastItem);
bEnableLeft = rcLastItem.left < 0;
}
m_btnRight.SetRect(CRect(nRight - 14, nTop, nRight, nTop + 15));
m_btnRight.SetEnable(bEnableRight);
m_btnRight.Draw(&dc, clrText);
m_btnLeft.SetRect(CRect(nRight - 28, nTop, nRight -14, nTop + 15));
m_btnLeft.SetEnable(bEnableLeft);
m_btnLeft.Draw(&dc, clrText);
}
else
{
m_btnRight.SetRect(CXTPEmptyRect());
m_btnLeft.SetRect(CXTPEmptyRect());
}
}
BOOL CXTPTabCtrlButtons::OnEraseBkgnd(CDC*)
{
return TRUE;
}
int CXTPTabCtrlButtons::GetWidth()
{
return 10 + (m_dwFlags & xtpNavBtnClose ? 14: 0) + (m_dwFlags & xtpNavBtnArrows ? 28 : 0);
}
BOOL CXTPTabCtrlButtons::Create(CXTPTabBase* pCtrlBase)
{
m_pTabCtrlBase = pCtrlBase;
m_pTabCtrl = m_btnRight.m_pTabCtrl = m_btnClose.m_pTabCtrl = m_btnLeft.m_pTabCtrl = pCtrlBase->GetTabCtrlImpl();
return TRUE;
}
CRect CXTPTabCtrlButtons::AdjustRect()
{
CRect rcItem;
m_pTabCtrl->GetItemRect(-1, &rcItem);
CXTPClientRect rc(m_pTabCtrl);
rc.left = rc.right - GetWidth();
rc.bottom = rcItem.bottom + 1;
rc.top = rcItem.top + ((m_pTabCtrl->GetStyle() & TCS_BOTTOM) != 0 ? -2 : 0);
return rc;
}
void CXTPTabCtrlButtons::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_bShow)
{
if (m_btnClose.PtInRect(point) && m_btnClose.Click(this, point))
{
m_pTabCtrl->SendMessage(WM_COMMAND, XTP_IDC_TAB_CLOSE);
}
else if (m_btnLeft.PtInRect(point))
{
m_btnLeft.Click(this, point, TRUE);
}
else if (m_btnRight.PtInRect(point))
{
m_btnRight.Click(this, point, TRUE);
}
}
else
{
CWnd::OnLButtonDown(nFlags, point);
}
}
BOOL CXTPTabCtrlButtons::ShowButtons()
{
return m_bShow;
}
void CXTPTabCtrlButtons::ShowButtons(BOOL bShow)
{
if (m_bShow != bShow)
{
m_bShow = bShow;
if (m_hWnd && !m_bShow) ShowWindow(SW_HIDE);
}
if (m_bShow && m_hWnd)
{
Refresh();
}
}
void CXTPTabCtrlButtons::Refresh()
{
if (!m_hWnd) return;
if (m_bShow)
{
CRect rc = AdjustRect();
SetWindowPos(&CWnd::wndTop, rc.left, rc.top, rc.Width(), rc.Height(),
m_pTabCtrl->GetItemCount() > 0 ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
CPoint point;
GetCursorPos(&point);
ScreenToClient(&point);
OnMouseMove(0, point);
}
Invalidate(FALSE);
}
void CXTPTabCtrlButtons::OnMouseMove(UINT , CPoint point)
{
if (m_bShow)
{
m_btnClose.CheckForMouseOver(this, point);
m_btnLeft.CheckForMouseOver(this, point);
m_btnRight.CheckForMouseOver(this, point);
}
}
void CXTPTabCtrlButtons::OnMouseLeave()
{
OnMouseMove(0, CPoint(-1, -1));
}
void CXTPTabCtrlButtons::SubclassTabButtons(CWnd* pWnd)
{
if (pWnd && pWnd->GetSafeHwnd() && m_hwndSubclassed != pWnd->GetSafeHwnd())
{
UnSubclassTabButtons();
SubclassWindow(*pWnd);
m_hwndSubclassed = pWnd->GetSafeHwnd();
}
else
{
if (!m_hWnd)
{
VERIFY(CWnd::Create(AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
0, WS_CHILD | WS_VISIBLE, CXTPEmptyRect(), m_pTabCtrl, 0));
m_hwndPrimary = m_hWnd;
}
}
}
void CXTPTabCtrlButtons::UnSubclassTabButtons()
{
if (m_hWnd)
{
HWND hWnd = UnsubclassWindow();
if (hWnd == m_hwndPrimary)
{
::DestroyWindow(hWnd);
}
}
m_hwndSubclassed = NULL;
}
void CXTPTabCtrlButtons::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
CWnd::OnWindowPosChanged(lpwndpos);
static BOOL bOnWindowPosChanged = FALSE;
if (m_bShow && !bOnWindowPosChanged)
{
if (m_pTabCtrl->GetItemCount() == 0)
return;
bOnWindowPosChanged = TRUE;
CRect rc = AdjustRect();
SetWindowPos(&CWnd::wndTop, rc.left, rc.top, rc.Width(), rc.Height(), SWP_SHOWWINDOW);
bOnWindowPosChanged = FALSE;
}
}
void CXTPTabCtrlButtons::SetButtonStyle(DWORD dwFlags)
{
m_dwFlags = dwFlags;
}