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

📄 mditabctrl.h

📁 一个使用wtl写的完整的多窗口浏览器
💻 H
📖 第 1 页 / 共 2 页
字号:
#pragma once
/////////////////////////////////////////////////////////////////////////////
// MDITabCtrl.h : interface of the CMDITabCtrl class
//
// How to use:
//  1.Place CMDITabCtrl m_MDITab in MDI mainframe class.
//  2.Place CMDITabCtrl& m_MDITab in MDI child class.
//  3.Place PASS_MSG_MAP_MDICHILD_TO_MDITAB(m_MDITab) in the head of MDI child's message map
//
// Note:
//	If you click system menu item which has short cut(Ctrl+F6 etc) on frame bar,
//	it send WM_COMMAND and send WM_SYSCOMMAND.
//	But if you TrackPopup system menu by yourself, only WM_COMMAND is sent.
//
// Why I choose not MDI child window but CMDITabctrl itself as popup menu owner:
//  If you cancel popup menu with pressing ESC key or clicking outside
//  (how do I know when canceled!?) and select menu on main frame bar, 
//  cause menu command sender can't be determine,
//  I can't skip this message and WM_COMMAND is handled twice.
//
// Written by MB<mb2@geocities.co.jp> 2000.06.28
/////////////////////////////////////////////////////////////////////////////	

#include "OleDragDropTabCtrl.h"
#include "HlinkDataObject.h"

namespace MTL
{
// Extended styles
#define MTB_EX_ADDLEFT				0x00000001L
#define MTB_EX_RIGHTCLICKCLOSE		0x00000002L
#define MTB_EX_DELAYED				0x00000004L
#define MTB_EX_MULTILINE			0x00000008L
#define MTB_EX_DOUBLECLICKCLOSE		0x00000010L
#define MTB_EX_XCLICKCLOSE			0x00000020L
#define MTB_EX_RIGHTCLICKREFRESH	0x00000040L
#define MTB_EX_DOUBLECLICKREFRESH	0x00000080L
#define MTB_EX_XCLICKREFRESH		0x00000100L
#define MTB_EX_RIGHTACTIVEONCLOSE	0x00000200L
#define MTB_EX_LEFTACTIVEONCLOSE	0x00000400L
#define MTB_EX_ADDRIGHTACTIVE		0x00000800L
#define MTB_EX_ADDLEFTACTIVE		0x00001000L
#define MTB_EX_WHEEL				0x00002000L
#define MTB_EX_FIXEDSIZE			0x00004000L
#define MTB_EX_ANCHORCOLOR			0x00008000L

//#undef	WM_XBUTTONUP
//#define WM_XBUTTONUP 0x020C

class CMDITabCtrl :
	public COleDragDropTabCtrl<CMDITabCtrl>
{
public:
	DECLARE_WND_CLASS_EX(_T("Mtl_MDI_TabCtrl"), CS_DBLCLKS, COLOR_BTNFACE)

// Constants

// Data members
	CWindow m_wndMDIChildProcessing;	// while message processing
	CMDIWindow m_wndMDIChildPopuping;	// while menu popuping (m_bPopup is not enough)
	DWORD m_dwExtendedStyle;
	CString m_strInitial;
	CMenu m_menuPopup;
	HWND m_hWndMenuOwner;

	bool m_bInsertHere;
	int m_nInsertIndex;

	int m_nMaxTabItemTextLength;
	bool m_bRedrawLocked;

// Constructor
	CMDITabCtrl()
		: m_dwExtendedStyle(0), m_strInitial(_T("Loading...")),
		  m_hWndMenuOwner(NULL), m_bInsertHere(false), m_nInsertIndex(-1), m_nMaxTabItemTextLength(30),
		  m_bRedrawLocked(false)
	{
	}

	BOOL LoadMenu(_U_STRINGorID menu)
	{
		return m_menuPopup.LoadMenu(menu);
	}

	void SetMenuOwner(HWND hWndOwner)
	{
		m_hWndMenuOwner = hWndOwner;
	}

	void SetMDITabLogFont(const LOGFONT& lf)
	{
		CFontHandle font;
		MTLVERIFY(font.CreateFontIndirect(&lf));
		if (font.m_hFont) {
			if(m_font.m_hFont != NULL)
				m_font.DeleteObject();
			m_font.Attach(font.m_hFont);
			SetFont(m_font);
			Invalidate();
		}
	}

	BOOL GetMDITabLogFont(LOGFONT& lf)
	{
		if (m_font.m_hFont) {
			return m_font.GetLogFont(&lf);
		}
		return false;
	}

	int AddTabItem(HWND hWndMDIChild, LPCTSTR lpszText = NULL)
	{
		if (hWndMDIChild == NULL)
			return -1;

		// add tab item
		int nPos;
		int nCurSel = GetCurSel();
		if (nCurSel == -1)
			nPos = 0;
		else if (m_dwExtendedStyle & MTB_EX_ADDLEFT)
			nPos = 0;
		else if (m_dwExtendedStyle & MTB_EX_ADDLEFTACTIVE)
			nPos = nCurSel;
		else if (m_dwExtendedStyle & MTB_EX_ADDRIGHTACTIVE)
			nPos = nCurSel + 1;
		else
			nPos = GetItemCount();

		BYTE fsState = TCISTATE_ENABLED;
		if (m_bRedrawLocked || hWndMDIChild != m_wndMDIChildPopuping.MDIGetActive())
			fsState |= TCISTATE_INACTIVE;

		return InsertItem(nPos, CTabCtrlItem(lpszText, -1, (DWORD)hWndMDIChild, fsState));
	}

// Attributes
	int GetTabIndex(HWND hWndMDIChild)
	{	
		if (hWndMDIChild == NULL)
			return -1;

		for (int i = 0; i < GetItemCount(); ++i) {
			DWORD dwData;
			GetItemUserData(i, dwData);
			if ((HWND)dwData == hWndMDIChild)
				return i;
		}
		return -1;
	}

	HWND GetTabHwnd(int nIndex)
	{
		if (nIndex < 0)
			return NULL;

		DWORD dwData;
		GetItemUserData(nIndex, dwData);
		return (HWND)dwData;
	}

	void RightTab()
	{
		int nIndex = GetCurSel();
		int nCount = GetItemCount();
		if (nCount < 2)
			return;

		int nNext = nIndex + 1 < nCount ? nIndex + 1 : 0;
		SetCurSelEx(nNext);
	}

	void SetCurSelEx(int nIndex, bool bActivate = true)
	{
		SetCurSel(nIndex);

		if (bActivate) {
			HWND hWnd = GetTabHwnd(nIndex);
			ATLASSERT(::IsWindow(hWnd));
			m_wndMDIChildPopuping.MDIActivate(hWnd);
		}
	}

	void LeftTab()
	{
		int nIndex = GetCurSel();
		int nCount = GetItemCount();
		if (nCount < 2)
			return;

		int nNext = nIndex - 1 < 0 ? nCount - 1 : nIndex - 1;
		SetCurSelEx(nNext);
	}

	void _SendSelChange(int nIndex)
	{
		int idCtrl = ::GetDlgCtrlID(m_hWnd);
		NMHDR nmh = { m_hWnd, idCtrl, TCN_SELCHANGE };
		SendMessage(WM_NOTIFY, (WPARAM)idCtrl, (LPARAM)&nmh);
	}

	DWORD GetMDITabExtendedStyle() const
	{
		return m_dwExtendedStyle;
	}
	DWORD SetMDITabExtendedStyle(DWORD dwExtendedStyle)
	{
		DWORD dwPrevStyle = m_dwExtendedStyle;
		m_dwExtendedStyle = dwExtendedStyle;
	
		if (dwExtendedStyle & MTB_EX_MULTILINE)
			ModifyTabCtrl2ExtendedStyle(0, TAB2_EX_MULTILINE);
		else
			ModifyTabCtrl2ExtendedStyle(TAB2_EX_MULTILINE, 0);

		if (dwExtendedStyle & MTB_EX_FIXEDSIZE)
			ModifyTabCtrl2ExtendedStyle(0, TAB2_EX_FIXEDSIZE);
		else
			ModifyTabCtrl2ExtendedStyle(TAB2_EX_FIXEDSIZE, 0);

		if (dwExtendedStyle & MTB_EX_ANCHORCOLOR)
			ModifyTabCtrl2ExtendedStyle(0, TAB2_EX_ANCHORCOLOR);
		else
			ModifyTabCtrl2ExtendedStyle(TAB2_EX_ANCHORCOLOR, 0);

		return dwPrevStyle;
	}
	void SetInitialText(LPCTSTR lpszInitialText)
	{
		m_strInitial = lpszInitialText;
	}

	void SetMaxTabItemTextLength(int nLength)
	{
		if (m_nMaxTabItemTextLength == nLength)
			return;

		m_nMaxTabItemTextLength = nLength;
		for (int i = 0; i < GetItemCount(); ++i) {
			HWND hWnd = GetTabHwnd(i);
			ATLASSERT(::IsWindow(hWnd));
			TCHAR szText[MAX_PATH];
			::GetWindowText(hWnd, szText, MAX_PATH);
			_SetTabText(i, szText);
		}
	}

	int GetMaxTabItemTextLength()
	{
		return m_nMaxTabItemTextLength;
	}

// Operations
	void SetMDIClient(HWND hWndMDIClient)
	{
		ATLASSERT(::IsWindow(hWndMDIClient));
		ATLASSERT(m_wndMDIChildPopuping.m_hWndMDIClient == NULL);
		m_wndMDIChildPopuping.m_hWndMDIClient = hWndMDIClient;
	}

// Message map and handlers
	BEGIN_MSG_MAP(CMDITabCtrl)
		MSG_WM_RBUTTONUP(OnRButtonUp)
		MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
		MESSAGE_HANDLER(WM_MBUTTONUP, OnXButtonUp)
		REFLECTED_NOTIFY_CODE_HANDLER_EX(TCN_SELCHANGE, OnTcnSelChange)
		MSG_WM_COMMAND(OnCommand)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)

		CHAIN_MSG_MAP(COleDragDropTabCtrl<CMDITabCtrl>)
	ALT_MSG_MAP(1)// MDI child windows messages
		m_wndMDIChildProcessing = hWnd;
		MSG_WM_MDIACTIVATE(OnMDIActivate)
		MSG_WM_SETTEXT(OnSetText)
		m_wndMDIChildProcessing = NULL;
	END_MSG_MAP()

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

		POINT point = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };

		if (m_dwExtendedStyle & MTB_EX_XCLICKCLOSE) {
			int nIndex = HitTest(point);
			if (nIndex != -1) {
				HWND hWndChild = GetTabHwnd(nIndex);
				::PostMessage(hWndChild, WM_CLOSE, 0, 0);
			}
		}
		else if (m_dwExtendedStyle & MTB_EX_XCLICKREFRESH) {
			int nIndex = HitTest(point);
			if (nIndex != -1) {
				HWND hWndChild = GetTabHwnd(nIndex);
				::PostMessage(hWndChild, WM_COMMAND, (WPARAM)ID_VIEW_REFRESH, 0);
			}
		}

		return 0;
	}

	void OnLButtonDblClk(UINT nFlags, CPoint point)
	{
		SetMsgHandled(FALSE);

		if (m_dwExtendedStyle & MTB_EX_DOUBLECLICKCLOSE) {
			int nIndex = HitTest(point);
			if (nIndex != -1) {
				HWND hWndChild = GetTabHwnd(nIndex);
				::PostMessage(hWndChild, WM_CLOSE, 0, 0);
			}
		}
		else if (m_dwExtendedStyle & MTB_EX_DOUBLECLICKREFRESH) {
			int nIndex = HitTest(point);
			if (nIndex != -1) {
				HWND hWndChild = GetTabHwnd(nIndex);
				::PostMessage(hWndChild, WM_COMMAND, (WPARAM)ID_VIEW_REFRESH, 0);
			}
		}
	}


	void OnRButtonUp(UINT nFlags, CPoint point)
	{// Overrides
		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnRButtonUp\n"));
		int nIndex = HitTest(point);
		if (nIndex != -1) {
			HWND hWndChild = GetTabHwnd(nIndex);
			ATLASSERT(hWndChild != NULL);
			if (m_dwExtendedStyle & MTB_EX_RIGHTCLICKCLOSE) {
				::PostMessage(hWndChild, WM_CLOSE, 0, 0);
			}
			else if (m_dwExtendedStyle & MTB_EX_RIGHTCLICKREFRESH) {
				::PostMessage(hWndChild, WM_COMMAND, (WPARAM)ID_VIEW_REFRESH, 0);
			}
			else if (m_menuPopup.m_hMenu) {
				ClientToScreen(&point);
				CMenuHandle menu = m_menuPopup.GetSubMenu(0);
				MTLVERIFY(menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
					point.x, point.y, m_hWndMenuOwner != NULL ? m_hWndMenuOwner : hWndChild));
			}
			else {// system menu (default)
				CMenuHandle menuSys = ::GetSystemMenu(hWndChild, FALSE);
				ClientToScreen(&point);
				m_wndMDIChildPopuping = hWndChild;
				_UpdateMenu(menuSys);
				menuSys.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
					point.x, point.y, m_hWnd);// owner is me!!
			}
		}
		SetMsgHandled(FALSE);
	}

	LRESULT OnTcnSelChange(LPNMHDR lpnhmdr)
	{
		// Watch OnLButtonDown, this handler will not be called by windows.
		// The flat style tab has a wastefull animation.

		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnTcnSelChange : %d\n"), GetCurSel());
		int nIndex = GetCurSel();
		ATLASSERT(nIndex != -1);
		HWND hWndActive = GetTabHwnd(nIndex);
		m_wndMDIChildPopuping.MDIActivate(hWndActive);
		return 0;
	}

	LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_wndMDIChildPopuping.m_hWndMDIClient));
		// for help message line
		return ::SendMessage(::GetParent(m_wndMDIChildPopuping.m_hWndMDIClient), WM_MENUSELECT, wParam, lParam);
	}

	void OnCommand(UINT wNotifyCode, int wID, HWND hwndCtl)
	{
		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnCommand - MDI child window:%x\n"), m_wndMDIChildPopuping.m_hWnd);
		if (m_wndMDIChildPopuping.m_hWnd == NULL) {// this is not my command message
			SetMsgHandled(FALSE);
			return;
		}

		ATLASSERT(m_wndMDIChildPopuping.IsWindow());
		CMDIWindow wnd = m_wndMDIChildPopuping;
		m_wndMDIChildPopuping = NULL;// It must be reset cause SendMessage(WM_SYSCOMMAND) make one more WM_COMMAND.
	
		if (wID != SC_CLOSE && wID != SC_NEXTWINDOW)
			wnd.BringWindowToTop();

		// Note: If you send SC_NEXTWINDOW to inactive child window,
		//       order is broken. Tell me why.
		if (wID == SC_NEXTWINDOW) 
			wnd.MDINext(NULL);// I think NULL is natural.
		else if (wID == SC_MAXIMIZE)
			wnd.ShowWindow(SW_MAXIMIZE);// without this, frame window maximized. why?
//		else if (wID == SC_CLOSE)
//			wnd.PostMessage(WM_CLOSE);	// without this, debug assertion occurs?
		else
			wnd.SendMessage(WM_SYSCOMMAND, (WPARAM)wID);
	}

	void OnMDIChildCreate(HWND hWnd)
	{
		ATLTRACE2(atlTraceUser, 4, _T("CChildFrame::OnMDIChildCreate\n"));

		if (m_bInsertHere) {
			BYTE fsState = TCISTATE_ENABLED;
			if (m_bRedrawLocked || hWnd != m_wndMDIChildPopuping.MDIGetActive())
				fsState |= TCISTATE_INACTIVE;		

			InsertItem(m_nInsertIndex, CTabCtrlItem(m_strInitial, -1, (DWORD)hWnd, fsState));
			return;
		}

		ATLASSERT(GetTabIndex(hWnd) == -1);

		AddTabItem(hWnd, m_strInitial);
		ATLTRACE2(atlTraceUser, 4, _T(" new child window found, add tab\n"));
		return;
	}

	void OnMDIActivate(HWND hWndChildDeact, HWND hWndChildAct)
	{
		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnMDIActivate\n"));
		SetMsgHandled(FALSE);

		if (hWndChildAct == NULL)
			return;

		int nIndex = GetTabIndex(hWndChildAct);
		ATLASSERT(nIndex != -1);
		if (!m_bRedrawLocked) {
			SetItemActive(nIndex);
			UpdateWindow();
		}
		SetCurSelEx(nIndex, false);
	}

	LRESULT OnSetText(LPCTSTR lpszText)
	{
		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnSetText\n"));
		SetMsgHandled(FALSE);
		// for new text
		int nIndex = GetTabIndex(m_wndMDIChildProcessing);
		if (nIndex != -1)
			_SetTabText(nIndex, lpszText);
		return FALSE;
	}

	void OnMDIChildDestroy(HWND hWnd)
	{
		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::OnDestroy\n"));
		int nIndex = GetTabIndex(hWnd);
		if (nIndex != -1) {
			DeleteItem(nIndex);
		}
	}

// Implementation
	bool _SetTabText(int nIndex, LPCTSTR lpszTab)
	{
		CString strTab(lpszTab);
		strTab = MtlCompactString(strTab, m_nMaxTabItemTextLength);
		return SetItemText(nIndex, strTab);
	}

	CString _GetTabText(int nIndex)
	{
		CString str;
		GetItemText(nIndex, str);
	}

	void _UpdateMenu(CMenuHandle& menuSys)
	{// Emulation is needed cause MDI child window won't update its menu information until clicked. 
		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrlImpl::_UpdateMenu\n"));
		ATLASSERT(::IsMenu(menuSys.m_hMenu));

		// no effect
		// m_wndMDIChildPopuping.SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE |
		//	SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);

		menuSys.EnableMenuItem(SC_RESTORE, MF_BYCOMMAND|MF_ENABLED);
		menuSys.EnableMenuItem(SC_MOVE, MF_BYCOMMAND|MF_ENABLED);
		menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_ENABLED);
		menuSys.EnableMenuItem(SC_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
		menuSys.EnableMenuItem(SC_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);	

		CWindowPlacement wndpl;
		m_wndMDIChildPopuping.GetWindowPlacement(&wndpl);
		switch(wndpl.showCmd) {
		case SW_SHOWNORMAL:
			ATLTRACE2(atlTraceUser, 4, _T(" SW_SHOWNORMAL\n"));
			menuSys.EnableMenuItem(SC_RESTORE, MF_BYCOMMAND|MF_GRAYED);
			::SetMenuDefaultItem(menuSys, SC_CLOSE, FALSE);
			break;
		case SW_SHOWMAXIMIZED:
			ATLTRACE2(atlTraceUser, 4, _T(" SW_SHOWMAXIMIZED\n"));
			menuSys.EnableMenuItem(SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
			menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_GRAYED);
			menuSys.EnableMenuItem(SC_MAXIMIZE, MF_BYCOMMAND|MF_GRAYED);
			::SetMenuDefaultItem(menuSys, SC_CLOSE, FALSE);
			break;
		case SW_SHOWMINIMIZED:
			ATLTRACE2(atlTraceUser, 4, _T(" SW_SHOWMINIMIZED\n"));
			menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_GRAYED);
			menuSys.EnableMenuItem(SC_MINIMIZE, MF_BYCOMMAND|MF_GRAYED);
			::SetMenuDefaultItem(menuSys, SC_RESTORE, FALSE);
			break;
		default:
			ATLASSERT(FALSE);
			break;
		}

		if (m_wndMDIChildPopuping.m_hWnd != m_wndMDIChildPopuping.MDIGetActive()) {// it's not active
			menuSys.EnableMenuItem(SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
			menuSys.EnableMenuItem(SC_SIZE, MF_BYCOMMAND|MF_GRAYED);		
		}
	}

	BOOL LoadConnectingAndDownloadingImageList(UINT nImageBmpID,
		int cx, int cy, COLORREF clrMask, UINT nFlags = ILC_COLOR8)
	{
		if(m_imgs.m_hImageList == NULL)
		{
			m_imgs.Create(cx, cy, nFlags | ILC_MASK, 2, 1);
			ATLASSERT(m_imgs.m_hImageList != NULL);
			if(m_imgs.m_hImageList == NULL)
				return FALSE;
		}

		CBitmap bmp;
		bmp.LoadBitmap(nImageBmpID);
		ATLASSERT(bmp.m_hBitmap != NULL);
		if(bmp.m_hBitmap == NULL)
			return FALSE;
		if(m_imgs.Add(bmp, clrMask) == -1)
			return FALSE;

		return TRUE;
	}

	void SetConnecting(HWND hWnd)
	{
		int nItem = GetTabIndex(hWnd);
		if (nItem == -1)
			return;

		ATLTRACE2(atlTraceUser, 4, _T("CMDITabCtrl::SetConnecting\n"));
		_SetImageListIndex(nItem, 0);
	}

	void SetDownloading(HWND hWnd)
	{
		int nItem = GetTabIndex(hWnd);
		if (nItem == -1)

⌨️ 快捷键说明

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