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

📄 flattabctrl.h

📁 软件是使用VC70
💻 H
字号:
/* 
 * Copyright (C) 2001-2005 Jacek Sieka, arnetheduck on gmail point com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#if !defined(AFX_FLATTABCTRL_H__FFFCBD5C_891D_44FB_B9F3_1DF83DA3EA83__INCLUDED_)
#define AFX_FLATTABCTRL_H__FFFCBD5C_891D_44FB_B9F3_1DF83DA3EA83__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "../client/SettingsManager.h"
#include "../client/ResourceManager.h"

#include "WinUtil.h"

enum {
	FT_FIRST = WM_APP + 700,
	/** This will be sent when the user presses a tab. WPARAM = HWND */
	FTM_SELECTED,
	/** The number of rows changed */
	FTM_ROWS_CHANGED,
	/** Set currently active tab to the HWND pointed by WPARAM */
	FTM_SETACTIVE,
	/** Display context menu and return TRUE, or return FALSE for the default one */
	FTM_CONTEXTMENU,
	/** Close window with postmessage... */
	WM_REALLY_CLOSE
};

template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits>
class ATL_NO_VTABLE FlatTabCtrlImpl : public CWindowImpl< T, TBase, TWinTraits> {
public:

	enum { FT_EXTRA_SPACE = 18 };

	FlatTabCtrlImpl() : closing(NULL), rows(1), height(0), active(NULL), moving(NULL), inTab(false) { 
		black.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
	};
	~FlatTabCtrlImpl() { }

	static LPCTSTR GetWndClassName()
	{
		return _T("FlatTabCtrl");
	}

	void addTab(HWND hWnd, COLORREF color = RGB(0, 0, 0)) {
		TabInfo* i = new TabInfo(hWnd, color);
		dcassert(getTabInfo(hWnd) == NULL);
		tabs.push_back(i);
		viewOrder.push_back(hWnd);
		nextTab = --viewOrder.end();
		active = i;
		calcRows(false);
		Invalidate();		
	}

	void removeTab(HWND aWnd) {
		TabInfo::ListIter i;
		for(i = tabs.begin(); i != tabs.end(); ++i) {
			if((*i)->hWnd == aWnd)
				break;
		}

		dcassert(i != tabs.end());
		TabInfo* ti = *i;
		if(active == ti)
			active = NULL;
		delete ti;
		tabs.erase(i);
		dcassert(find(viewOrder.begin(), viewOrder.end(), aWnd) != viewOrder.end());
		viewOrder.erase(find(viewOrder.begin(), viewOrder.end(), aWnd));
		nextTab = viewOrder.end();
		if(!viewOrder.empty())
			--nextTab;

		calcRows(false);
		Invalidate();
	}

	void startSwitch() {
		nextTab = --viewOrder.end();
		inTab = true;
	}

	void endSwitch() {
		inTab = false;
		if(active) 
		setTop(active->hWnd);
	}

	HWND getNext() {
		if(viewOrder.empty())
			return NULL;
		if(nextTab == viewOrder.begin()) {
			nextTab = --viewOrder.end();
		} else {
			--nextTab;
		}
		return *nextTab;
	}
	HWND getPrev() {
		if(viewOrder.empty())
			return NULL;
		nextTab++;
		if(nextTab == viewOrder.end()) {
			nextTab = viewOrder.begin();
		}
		return *nextTab;
	}

	void setActive(HWND aWnd) {
		if(!inTab)
			setTop(aWnd);

		TabInfo* ti = getTabInfo(aWnd);
		dcassert(ti != NULL);
		active = ti;
		ti->dirty = false;
		calcRows(false);
		Invalidate();
	}

	void setTop(HWND aWnd) {
		dcassert(find(viewOrder.begin(), viewOrder.end(), aWnd) != viewOrder.end());
		viewOrder.erase(find(viewOrder.begin(), viewOrder.end(), aWnd));
		viewOrder.push_back(aWnd);
		nextTab = --viewOrder.end();
	}

	void setDirty(HWND aWnd) {
		TabInfo* ti = getTabInfo(aWnd);
		dcassert(ti != NULL);
		bool inval = ti->update();
		
		if(active != ti) {
			if(!ti->dirty) {
				ti->dirty = true;
				inval = true;
			}
		}

		if(inval) {
			calcRows(false);
			Invalidate();
		}
	}

	void setColor(HWND aWnd, COLORREF color) {
		TabInfo* ti = getTabInfo(aWnd);
		if(ti != NULL) {
			ti->pen.DeleteObject();
			ti->pen.CreatePen(PS_SOLID, 1, color);
			Invalidate();
		}
	}

	void updateText(HWND aWnd, LPCTSTR text) {
		TabInfo* ti = getTabInfo(aWnd);
		if(ti != NULL) {
			ti->updateText(text);
			calcRows(false);
			Invalidate();
		}
	}

	BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_SIZE, onSize)
		MESSAGE_HANDLER(WM_CREATE, onCreate)
		MESSAGE_HANDLER(WM_PAINT, onPaint)
		MESSAGE_HANDLER(WM_LBUTTONDOWN, onLButtonDown)
		MESSAGE_HANDLER(WM_LBUTTONUP, onLButtonUp)
		MESSAGE_HANDLER(WM_CONTEXTMENU, onContextMenu)
		COMMAND_ID_HANDLER(IDC_CLOSE_WINDOW, onCloseWindow)
		COMMAND_ID_HANDLER(IDC_CHEVRON, onChevron)
		COMMAND_RANGE_HANDLER(IDC_SELECT_WINDOW, IDC_SELECT_WINDOW+tabs.size(), onSelectWindow)
	END_MSG_MAP()

	LRESULT onLButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) {
		int xPos = GET_X_LPARAM(lParam); 
		int yPos = GET_Y_LPARAM(lParam); 
		int row = getRows() - ((yPos / getTabHeight()) + 1);

		for(TabInfo::ListIter i = tabs.begin(); i != tabs.end(); ++i) {
			TabInfo* t = *i;
			if((row == t->row) && (xPos >= t->xpos) && (xPos < (t->xpos + t->getWidth())) ) {
				// Bingo, this was clicked
				HWND hWnd = GetParent();
				if(hWnd) {
					if(wParam & MK_SHIFT)
						::SendMessage(t->hWnd, WM_CLOSE, 0, 0);
					else 
						moving = t;
				}
				break;
			}
		}
		return 0;
	}

	LRESULT onLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) {
		if (moving) {
			int xPos = GET_X_LPARAM(lParam); 
			int yPos = GET_Y_LPARAM(lParam); 
			int row = getRows() - ((yPos / getTabHeight()) + 1);
			
			bool moveLast = true;

			for(TabInfo::ListIter i = tabs.begin(); i != tabs.end(); ++i) {
				TabInfo* t = *i;
				if((row == t->row) && (xPos >= t->xpos) && (xPos < (t->xpos + t->getWidth())) ) {
					// Bingo, this was clicked
					HWND hWnd = GetParent();
					if(hWnd) {
						if(t == moving) 
							::SendMessage(hWnd, FTM_SELECTED, (WPARAM)t->hWnd, 0);
						else{
							//check if the pointer is on the left or right half of the tab
							//to determine where to insert the tab
							moveTabs(t, xPos > (t->xpos + (t->getWidth()/2)));
						}
					}
					moveLast = false;
					break;
				}
			}
			if(moveLast)
				moveTabs(tabs.back(), true);
			moving = NULL;
		}
		return 0;
	}

	LRESULT onContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) {
		POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };        // location of mouse click 

		ScreenToClient(&pt); 
		int xPos = pt.x;
		int row = getRows() - ((pt.y / getTabHeight()) + 1);

		for(TabInfo::ListIter i = tabs.begin(); i != tabs.end(); ++i) {
			TabInfo* t = *i;
			if((row == t->row) && (xPos >= t->xpos) && (xPos < (t->xpos + t->getWidth())) ) {
				// Bingo, this was clicked, check if the owner wants to handle it...
				if(!::SendMessage(t->hWnd, FTM_CONTEXTMENU, 0, lParam)) {
					closing = t->hWnd;
					ClientToScreen(&pt);
					CMenu mnu;
					mnu.CreatePopupMenu();
					mnu.AppendMenu(MF_STRING, IDC_CLOSE_WINDOW, CTSTRING(CLOSE));
					mnu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_BOTTOMALIGN, pt.x, pt.y, m_hWnd);
				}
				break;
			}
		}
		return 0;
	}

	LRESULT onCloseWindow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		if(::IsWindow(closing))
			::SendMessage(closing, WM_CLOSE, 0, 0);
		return 0;
	}

	int getTabHeight() { return height; };
	int getHeight() { return (getRows() * getTabHeight())+1; };
	int getFill() { return (getTabHeight() + 1) / 2; };

	int getRows() { return rows; };

	void calcRows(bool inval = true) {
		CRect rc;
		GetClientRect(rc);
		int r = 1;
		int w = 0;
		bool notify = false;
		bool needInval = false;

		for(TabInfo::ListIter i = tabs.begin(); i != tabs.end(); ++i) {
			TabInfo* ti = *i;
			if( (r != 0) && ((w + ti->getWidth() + getFill()) > rc.Width()) ) {
				if(r >= SETTING(MAX_TAB_ROWS)) {
					notify |= (rows != r);
					rows = r;
					r = 0;
					chevron.EnableWindow(TRUE);
				} else {
					r++;
					w = 0;
				}
			} 
			ti->xpos = w;
			needInval |= (ti->row != (r-1));
			ti->row = r-1;
			w += ti->getWidth();
		}

		if(r != 0) {
			chevron.EnableWindow(FALSE);
			notify |= (rows != r);
			rows = r;
		}

		if(notify) {
			::SendMessage(GetParent(), FTM_ROWS_CHANGED, 0, 0);
		}
		if(needInval && inval)
			Invalidate();
	}

	LRESULT onCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { 
		chevron.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
			BS_PUSHBUTTON , 0, IDC_CHEVRON);
		chevron.SetWindowText(_T("

⌨️ 快捷键说明

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