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

📄 customtabctrl.h

📁 These listed libraries are written in WTL. But it s really hard to mix both MFC & WTL together. Obvi
💻 H
📖 第 1 页 / 共 5 页
字号:

	void ActivateTooltips(BOOL bActivate = TRUE)
	{
		ATLASSERT(m_tooltip.IsWindow());
		if(m_tooltip.IsWindow())
		{
			m_tooltip.Activate(bActivate);
		}
	}

	void ClearCurrentHotTracking(bool bRedrawEffectedArea = true)
	{
		switch(m_dwState & ectcHotTrack)
		{
		case ectcHotTrack_CloseButton:
			m_dwState &= ~ectcHotTrack;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcCloseButton);
			}
			break;
		case ectcHotTrack_ScrollRight:
			m_dwState &= ~ectcHotTrack;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcScrollRight);
			}
			break;
		case ectcHotTrack_ScrollLeft:
			m_dwState &= ~ectcHotTrack;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcScrollLeft);
			}
			break;
		case ectcHotTrack_TabItem:
			m_dwState &= ~ectcHotTrack;
			m_iHotItem = -1;

			if(bRedrawEffectedArea)
			{
				// In case the derived class actually changes the width
				//  of a hot tracked tab, invalidate the whole tab window
				this->Invalidate();
			}
			break;
		default:
			m_dwState &= ~ectcHotTrack;
			m_iHotItem = -1;
			if(bRedrawEffectedArea)
			{
				this->Invalidate();
			}
			break;
		}
	}

	void ClearCurrentMouseDownTracking(bool bRedrawEffectedArea = true)
	{
		switch(m_dwState & ectcMouseDown)
		{
		case ectcMouseDownL_CloseButton:
		case ectcMouseDownR_CloseButton:
			m_dwState &= ~ectcMouseDown;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcCloseButton);
			}
			break;
		case ectcMouseDownL_ScrollRight:
		case ectcMouseDownR_ScrollRight:
			m_dwState &= ~ectcMouseDown;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcScrollRight);
			}
			break;
		case ectcMouseDownL_ScrollLeft:
		case ectcMouseDownR_ScrollLeft:
			m_dwState &= ~ectcMouseDown;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcScrollLeft);
			}
			break;
		case ectcMouseDownL_TabItem:
		case ectcMouseDownR_TabItem:
			m_dwState &= ~ectcMouseDown;

			if(bRedrawEffectedArea)
			{
				// In case the derived class actually changes the width
				//  of a hot tracked tab, invalidate the whole tab window
				this->Invalidate();

				//if(m_iActionItem >= 0 && m_iActionItem < m_Items.GetCount())
				//{
				//	RECT rcItemDP;
				//	this->GetItemRect(m_iActionItem, &rcItemDP);
				//	this->InvalidateRect(rcItemDP);
				//}
			}
			break;
		default:
			m_dwState &= ~ectcMouseDown;
			if(bRedrawEffectedArea)
			{
				this->Invalidate();
			}
			break;
		}
	}

	void ClearCurrentMouseOverTracking(bool bRedrawEffectedArea = true)
	{
		switch(m_dwState & ectcMouseOver)
		{
		case ectcMouseOver_CloseButton:
			m_dwState &= ~ectcMouseOver;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcCloseButton);
			}
			break;
		case ectcMouseOver_ScrollRight:
			m_dwState &= ~ectcMouseOver;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcScrollRight);
			}
			break;
		case ectcMouseOver_ScrollLeft:
			m_dwState &= ~ectcMouseOver;
			if(bRedrawEffectedArea)
			{
				this->InvalidateRect(&m_rcScrollLeft);
			}
			break;
		case ectcMouseOver_TabItem:
			m_dwState &= ~ectcMouseOver;

			if(bRedrawEffectedArea)
			{
				// In case the derived class actually changes the width
				//  of a hot tracked tab, invalidate the whole tab window
				this->Invalidate();

				//if(m_iActionItem >= 0 && m_iActionItem < m_Items.GetCount())
				//{
				//	RECT rcItemDP = {0};
				//	this->GetItemRect(m_iActionItem, &rcItemDP);
				//	this->InvalidateRect(rcItemDP);
				//}
			}
			break;
		default:
			m_dwState &= ~ectcMouseOver;
			if(bRedrawEffectedArea)
			{
				this->Invalidate();
			}
			break;
		}
	}

// Drag and drop methods (overrideable)
// In this base class implementation, we mimic the drag rearrange
// of MDI tabs in VS.NET (except, we add scroll support)
public:

	void AcceptItemDrag(bool bRedrawEffectedArea = true)
	{
		T* pT = static_cast<T*>(this);

		NMCTC2ITEMS nmh = {{ m_hWnd, this->GetDlgCtrlID(), CTCN_ACCEPTITEMDRAG }, m_iDragItemOriginal, m_iDragItem, {-1,-1}};
		::SendMessage(GetParent(), WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh);

		// In this implementation, the tab is moved as they drag.
		pT->StopItemDrag(bRedrawEffectedArea);
	}

	void CancelItemDrag(bool bRedrawEffectedArea = true)
	{
		T* pT = static_cast<T*>(this);

		// In this implementation, the tab is moved as they drag.
		// To cancel the drag, we move the item back to its original place.
		if(	m_iDragItemOriginal >= 0 &&
			m_iDragItem >= 0 &&
			m_iDragItemOriginal != m_iDragItem)
		{
			pT->MoveItem(m_iDragItem, m_iDragItemOriginal, true, false);
			pT->EnsureVisible(m_iDragItemOriginal);
		}

		NMCTCITEM nmh = {{ m_hWnd, this->GetDlgCtrlID(), CTCN_CANCELITEMDRAG }, m_iDragItemOriginal, {-1,-1}};
		::SendMessage(GetParent(), WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh);

		pT->StopItemDrag(bRedrawEffectedArea);
	}

	void StopItemDrag(bool bRedrawEffectedArea = true)
	{
		if(ectcDraggingItem == (m_dwState & ectcDraggingItem))
		{
			m_dwState &= ~ectcDraggingItem;

			// Restore the default cursor
// need conditional code because types don't match in winuser.h
#ifdef _WIN64
			::SetCursor((HCURSOR)::GetClassLongPtr(m_hWnd, GCLP_HCURSOR));
#else
			::SetCursor((HCURSOR)LongToHandle(::GetClassLongPtr(m_hWnd, GCLP_HCURSOR)));
#endif

			if(m_hCursorMove != NULL)
			{
				::DestroyCursor(m_hCursorMove);
				m_hCursorMove = NULL;
			}
			if(m_hCursorNoDrop != NULL)
			{
				::DestroyCursor(m_hCursorNoDrop);
				m_hCursorNoDrop = NULL;
			}

			m_iDragItem = -1;
			m_iDragItemOriginal = -1;
			::ZeroMemory(&m_ptDragOrigin, sizeof(POINT));

			if(bRedrawEffectedArea)
			{
				this->Invalidate();
			}
		}
	}

	void BeginItemDrag(int index, POINT ptDragOrigin)
	{
		T* pT = static_cast<T*>(this);
		if(index >= 0)
		{
			DWORD dwStyle = this->GetStyle();

			if(CTCS_DRAGREARRANGE == (dwStyle & CTCS_DRAGREARRANGE))
			{
				NMCTCITEM nmh = {{ m_hWnd, this->GetDlgCtrlID(), CTCN_BEGINITEMDRAG }, index, {ptDragOrigin.x, ptDragOrigin.y} };
				if(FALSE != ::SendMessage(GetParent(), WM_NOTIFY, nmh.hdr.idFrom, (LPARAM)&nmh))
				{
					// Returning non-zero prevents our default handling.
					// We've possibly already set a couple things that we
					// need to cleanup, so call StopItemDrag
					pT->StopItemDrag(false);
				}
				else
				{
					// returning FALSE let's us do our default handling

					// Mark the beginning of a drag operation.
					// We should have already done SetCapture, but just
					// in case, we'll set it again.
					this->SetCapture();

					// Set focus so that we get an ESC key press
					pT->SetFocus();

					// This call to DoDragDrop is just to ensure a dependency on OLE32.dll.
					// In the future, if we support true OLE drag and drop,
					// we'll really use DoDragDrop.
					::DoDragDrop(NULL, NULL, 0, 0);

					// To save on resources, we'll load the drag cursor
					// only when we need it, and destroy it when the drag is done
					HMODULE hOle32 = ::GetModuleHandle(_T("OLE32.dll"));
					if(hOle32 != NULL)
					{
						// Cursor ID identified using resource editor in Visual Studio
						int dragCursor = 2;
						int noDropCursor = 1;
						m_hCursorMove = ::LoadCursor(hOle32, MAKEINTRESOURCE(dragCursor));
						m_hCursorNoDrop = ::LoadCursor(hOle32, MAKEINTRESOURCE(noDropCursor));
					}

					m_dwState |= ectcDraggingItem;

					m_iDragItem = index;
					m_iDragItemOriginal = index;
					m_ptDragOrigin = ptDragOrigin;
				}
			}
		}
	}

	// Update the drag operation.
	//  ptCursor should be in client coordinates
	void ContinueItemDrag(POINT ptCursor)
	{
		// We're dragging an item
		T* pT = static_cast<T*>(this);

		RECT rcClient = {0};
		this->GetClientRect(&rcClient);
		if(::PtInRect(&rcClient, ptCursor))
		{
			::SetCursor(m_hCursorMove);
		}
		else
		{
			::SetCursor(m_hCursorNoDrop);
		}

		CTCHITTESTINFO tchti = { 0 };
		tchti.pt = ptCursor;
		int index = pT->HitTest(&tchti);
		if((index != m_iDragItem) && (index >= 0))
		{
			RECT rcItem = {0};
			this->GetItemRect(index, &rcItem);

			int itemMiddlePointX = rcItem.left + ((rcItem.right - rcItem.left) / 2);
			
			if((m_iDragItem < index) && (ptCursor.x > itemMiddlePointX))
			{
				// They're dragging an item from left to right,
				// and have dragged it over the half way mark to the right
				pT->MoveItem(m_iDragItem, index, true, false);
				m_iDragItem = index;
			}
			else if((m_iDragItem > index) && (ptCursor.x < itemMiddlePointX))
			{
				// They're dragging an item from right to left,
				// and have dragged it over the half way mark to the left
				pT->MoveItem(m_iDragItem, index, true, false);
				m_iDragItem = index;
			}
		}

		// Now scroll if necessary
		DWORD dwStyle = this->GetStyle();
		if(CTCS_SCROLL == (dwStyle & CTCS_SCROLL))
		{
			RECT rcLeftScrollZone = {rcClient.left, rcClient.top, (m_rcTabItemArea.left + CTCD_SCROLLZONEWIDTH), rcClient.bottom};
			RECT rcRightScrollZone = {(m_rcTabItemArea.right - CTCD_SCROLLZONEWIDTH), rcClient.top, rcClient.right, rcClient.bottom};

			if(	::PtInRect(&rcLeftScrollZone, ptCursor) &&
				(ectcOverflowLeft == (m_dwState & ectcOverflowLeft)))
			{
				pT->ScrollLeft(true);
				this->SetTimer(ectcTimer_ScrollLeft, CTCSR_SLOW);
			}
			else if(::PtInRect(&rcRightScrollZone, ptCursor) &&
				(ectcOverflowRight == (m_dwState & ectcOverflowRight)))
			{
				pT->ScrollRight(true);
				this->SetTimer(ectcTimer_ScrollRight, CTCSR_SLOW);
			}
		}
	}

// Message Handling
public:
	// Your derived class should use DECLARE_WND_CLASS or DECLARE_WND_SUPERCLASS, etc.
	//DECLARE_WND_CLASS_EX(_T("WTL_CustomTabCtrl"), CS_DBLCLKS, COLOR_WINDOW)

	BEGIN_MSG_MAP(CCustomTabCtrl)
		CHAIN_MSG_MAP(offscreenDrawClass)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
		MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
		MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
		MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
		MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
		MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
		MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)
		MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown)
		MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUp)
		MESSAGE_HANDLER(WM_RBUTTONDBLCLK, OnRButtonDoubleClick)
		MESSAGE_HANDLER(WM_MBUTTONDOWN, OnMButtonDown)
		MESSAGE_HANDLER(WM_MBUTTONUP, OnMButtonUp)
		MESSAGE_HANDLER(WM_MBUTTONDBLCLK, OnMButtonDoubleClick)
		MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
		MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSettingChange)
		MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
		MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
		MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
		MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
		MESSAGE_HANDLER(WM_STYLECHANGED, OnStyleChanged)
		MESSAGE_HANDLER(WM_TIMER, OnTimer)
		MESSAGE_HANDLER(WM_SETREDRAW, OnSetRedraw)
		NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnGetToolTipInfo)
	END_MSG_MAP()

	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		LRESULT lRes = DefWindowProc();
		if(lRes == -1)
		{
			return -1;
		}

		T* pT = static_cast<T*>(this);
		pT->Initialize();
		return lRes;
	}

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

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

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

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

	LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;
		if(m_tooltip.IsWindow())
		{
			MSG msg = { m_hWnd, uMsg, wParam, lParam };
			m_tooltip.RelayEvent(&msg);
		}
		return 1;
	}

	LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

		DWORD dwStyle = this->GetStyle();
		POINT ptCursor = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};

		T* pT = static_cast<T*>(this);
		if(ectcMouseInWindow != (m_dwState & ectcMouseInWindow))
		{
			TRACKMOUSEEVENT tme = { 0 };
			tme.cbSize = sizeof(tme);
			tme.dwFlags = TME_LEAVE;

⌨️ 快捷键说明

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