//////////////////////////////
// CTABクラス定義ファイル
// Copyright (c) August, 2022
//        By Ysama
//////////////////////////////

#define	MAX_PAGE	64				//タブページの最大数

class CTAB : public CCTRL
{
public:		//メンバー変数
	RECT m_rectParent;				//親のクライアント領域
	RECT m_rectTab;					//タブの表示領域
	HIMAGELIST m_hIList = 0;		//イメージリストハンドル
	int m_CtrlID[MAX_PAGE]{};		//各タブページに設定する親ウィンドウのコントロールID

public:		//メンバー関数
	CTAB();							//コンストラクター（１）
	CTAB(int, int, int);			//コンストラクター（２）
	~CTAB();						//デストラクター
	bool Create(HWND, HINSTANCE, HMENU, int, int, int, int);//CTABコントロール作成関数
	int TabCount() {return TabCtrl_GetItemCount(m_hWnd);}	//タブの数を取得する
	void MoveTab(int, int, int, int);						//タブを移動させる
	void FitParent(HWND, HWND);								//親のクライアント領域に合わせる
	void FitSiblings(WPARAM);								//タブコントロールサイズ調整
	bool AddPage(int, int, LPWSTR);	//タブページと表示する親のコントロール登録関数
	bool DeletePage();				//カレントタブと親の表示コントロールを削除する
	HWND GetCtrl();					//カレントタブで表示される親のコントロールのハンドルを返す
	int GetPage();					//カレントページの番号を取得する
	bool SetPage(int);				//カレントページを設定する
	WCHAR* GetTitle();				//カレントページのタイトルを取得する
	WCHAR* GetTitle(int);			//指定ページのタイトルを取得する
};

////////////////////////
// メンバー関数の実装
////////////////////////
//コンストラクター(初期化のみ（１））
CTAB::CTAB() {

	m_hWnd			= 0;
	m_dwExStyle		= 0;
	m_lpClassName	= L"SYSTABCONTROL32";
	m_lpWindowName	= NULL;
	m_dwStyle		= WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | TCS_TOOLTIPS | TCS_HOTTRACK;
	m_x				= 0;
	m_y				= 0;
	m_Width			= 0;
	m_Height		= 0;
	m_hParent		= NULL;
	m_hMenu			= NULL;
	m_hInstance		= 0;
	m_lpParam		= NULL;
	//イメージリストの初期化（初期値は16 x 16−16色）
	m_hIList = ImageList_Create(16, 16, ILC_COLOR4, MAX_PAGE, 0);
	if(!m_hIList)
		MessageBoxW(m_hWnd, L"イメージリストの初期化に失敗しました",
					L"警告", MB_OK | MB_ICONSTOP);
}

//コンストラクター(初期化のみ）（２）
CTAB::CTAB(int w, int h, int c) {

	m_hWnd			= 0;
	m_dwExStyle		= 0;
	m_lpClassName	= L"SYSTABCONTROL32";
	m_lpWindowName	= NULL;
	m_dwStyle		= WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | TCS_TOOLTIPS | TCS_HOTTRACK;
	m_x				= 0;
	m_y				= 0;
	m_Width			= 0;
	m_Height		= 0;
	m_hParent		= NULL;
	m_hMenu			= NULL;
	m_hInstance		= 0;
	m_lpParam		= NULL;
	//イメージリストの初期化
	m_hIList = ImageList_Create(w, h, c, MAX_PAGE, 0);
	if(!m_hIList)
		MessageBoxW(m_hWnd, L"イメージリストの初期化に失敗しました",
					L"警告", MB_OK | MB_ICONSTOP);
}

//デストラクター
CTAB::~CTAB() {

	ImageList_Destroy(m_hIList);
	DestroyWindow(m_hWnd);
}

//CTABコントロール作成関数
bool CTAB::Create(HWND hParent, HINSTANCE hInstance, HMENU ID, int x = 0, int y = 0, int w = 0, int h = 0) {

	//親のクライアント領域を取得する
	GetClientRect(m_hParent = hParent, &m_rectParent);
	if(!x) x = m_rectParent.left;
	if(!y) y = m_rectParent.top;
	if(!w) w = m_rectParent.right - m_rectParent.left;
	if(!h) h = m_rectParent.bottom - m_rectParent.top;
	m_hInstance = hInstance;
	m_hMenu = ID;
	CCTRL::Create(L"", m_dwStyle, 0, m_hParent, ID, x, y, w, h);
	return TRUE;
}

//タブを移動させる
void CTAB::MoveTab(int x, int y, int w , int h) {

	int focus = TabCtrl_GetCurSel(m_hWnd);
	if(focus != -1)
		ShowWindow(GetDlgItem(m_hParent, m_CtrlID[focus]), SW_HIDE);
	m_x = x;
	m_y = y;
	m_Width = w;
	m_Height = h;
	MoveWindow(m_hWnd, x, y, w, h, TRUE);
	ShowWindow(GetDlgItem(m_hParent, m_CtrlID[focus]), SW_SHOWNORMAL);
}

//タブのサイズを親ウィンドウに合わせる
void CTAB::FitParent(HWND hStatusBar = 0, HWND hToolBar = 0) {

	RECT rectStatus, rectTool;
	//親ウィンドウのサイズを取得
	GetClientRect(m_hParent, &m_rectParent);
	//ツールバーの高さを取得
	if(hToolBar) {
		GetWindowRect(hToolBar, &rectTool);
		m_rectParent.top += (rectTool.bottom - rectTool.top);
	}
	//ステータスバーの高さを取得
	if(hStatusBar) {
		GetWindowRect(hStatusBar, &rectStatus);
		m_rectParent.bottom -= (rectStatus.bottom - rectStatus.top);
	}
	//タブのサイズをあわせる
	MoveWindow(m_hWnd, m_x = m_rectParent.left, m_y = m_rectParent.top,
				m_Width = (m_rectParent.right - m_rectParent.left),
				m_Height = (m_rectParent.bottom - m_rectParent.top), TRUE);
	FitSiblings((WPARAM)m_hMenu);
}

//タブの表示サイズに親のコントロールサイズをあわせる
void CTAB::FitSiblings(WPARAM wParam) {

	if(wParam != (WPARAM)m_hMenu)	return;			//タブコントロールでなければ帰る
	int focus = TabCtrl_GetCurSel(m_hWnd);
	if(focus == -1)					return;			//選択されていなければ帰る
	//親のWM_SIZEメッセージでFitParent関数が実行される際に実行されるためm_x等の位置情報は最新
	m_rectTab.left = m_x;
	m_rectTab.right = m_x + m_Width;
	m_rectTab.top = m_y;
	m_rectTab.bottom = m_y + m_Height;
	TabCtrl_AdjustRect(m_hWnd, FALSE, &m_rectTab);	//タブウィンドウ矩形位置を求める
	//カレントタブ以外のタブのコントロールを隠し、サイズを調整する
	for(int i = 0, j = TabCount(); i < j; i++) {
		if(i != focus)		//カレントタブ以外のタブのコントロールを隠す
			ShowWindow(GetDlgItem(m_hParent, m_CtrlID[i]), SW_HIDE);
		MoveWindow(GetDlgItem(m_hParent, m_CtrlID[i]),
							m_rectTab.left, m_rectTab.top,
							m_rectTab.right - m_rectTab.left,
							m_rectTab.bottom - m_rectTab.top, TRUE);
	}
	//最後にカレントタブコントロールを再表示してフォーカスを当てる
	ShowWindow(GetDlgItem(m_hParent, m_CtrlID[focus]), SW_SHOWNORMAL);
	SetFocus(GetDlgItem(m_hParent, m_CtrlID[focus]));
}

//タブページと表示する親のコントロール登録関数
bool CTAB::AddPage(int ID, int BitmapID, LPWSTR Title) {

	int item = TabCount();
	//既にそのタブページに親のコントロールが作成されているか、MAX_PAGEであれば
	if(m_CtrlID[item] || (item >= MAX_PAGE))
		return FALSE;	//エラーとして何もしない
	//イメージとタイトルをタブに設定
	HBITMAP hBitmap = LoadBitmap(m_hInstance, MAKEINTRESOURCE(BitmapID));
	if(!hBitmap)
		MessageBoxW(m_hWnd, L"ビットマップを読み込めませんでした",
					L"警告", MB_OK | MB_ICONSTOP);
	TCITEMW tcItem;		//タブコントロール情報構造体
	tcItem.mask = TCIF_TEXT | TCIF_IMAGE;
	tcItem.pszText = Title;
	tcItem.iImage = ImageList_Add(m_hIList, hBitmap, NULL);
	if(tcItem.iImage == -1)
		MessageBoxW(m_hWnd, L"ビットマップを登録できませんでした",
					L"警告", MB_OK | MB_ICONSTOP);
	SendMessageW(m_hWnd, TCM_INSERTITEM, item, (LPARAM)&tcItem);
	SendMessageW(m_hWnd, TCM_SETIMAGELIST, 0, (LPARAM)m_hIList);
	DeleteObject(hBitmap);
	//新規タブページに表示する親のコントロールIDの登録
	m_CtrlID[item] = ID;
	//新規タブページを表示ページにして親のコントロールも表示
	TabCtrl_SetCurSel(m_hWnd, item);
	FitSiblings((WPARAM)m_hMenu);
	return TRUE;
}

//カレントタブと親の表示コントロールを削除する
bool CTAB::DeletePage() {

	int item = TabCtrl_GetCurSel(m_hWnd);
	if(item == -1)	return FALSE;	//選択されていない
	WCHAR Buff[MAX_PATH];			//ラベル文字列収容バッファ
	TCITEMW tcItem;					//タブコントロール情報構造体
	//現在の表示タブページで表示されている親のコントロールを破壊
	DestroyWindow(GetDlgItem(m_hParent, m_CtrlID[item]));
	//タブのラベルビットマップを破壊（一つづつ繰り下がる）
	ImageList_Remove(m_hIList, item);
	//タブページを破壊（一つづつ繰り下がる）
	TabCtrl_DeleteItem(m_hWnd, item);
	for(int i = item, j = TabCount(); i < j; i++) {
		m_CtrlID[i] = m_CtrlID[i + 1];
		tcItem.mask = TCIF_TEXT | TCIF_IMAGE;
		tcItem.cchTextMax = MAX_PATH;
		tcItem.pszText = Buff;
		TabCtrl_GetItem(m_hWnd, i, &tcItem);
		tcItem.iImage--;
		TabCtrl_SetItem(m_hWnd, i, &tcItem);
	}
	m_CtrlID[TabCount()] = 0;
	TabCtrl_SetCurSel(m_hWnd, item);
	FitSiblings((WPARAM)m_hMenu);
	return TRUE;
}

//カレントタブで表示される親のコントロールのハンドルを返す
HWND CTAB::GetCtrl() {

	int item = TabCtrl_GetCurSel(m_hWnd);
	if(item != -1)
		return GetDlgItem(m_hParent, m_CtrlID[item]);
	else
		return 0;
}

//カレントページの番号を取得する
int CTAB::GetPage() {

	return SendMessage(m_hWnd, TCM_GETCURSEL, 0, 0);	//タブが選択されていない場合は-1
}

//カレントページを設定する
bool CTAB::SetPage(int cur) {

	int ret = SendMessage(m_hWnd, TCM_SETCURSEL, cur, 0);
	if(ret == -1)
		return FALSE;
	else
		return TRUE;
}

//カレントページのタイトルを取得する
WCHAR* CTAB::GetTitle() {

	int item = TabCtrl_GetCurSel(m_hWnd);
	if(item == -1)
		return 0;
	static WCHAR Buff[MAX_PATH];	//ラベル文字列収容バッファ
	TCITEMW tcItem;					//タブコントロール情報構造体
	tcItem.mask = TCIF_TEXT;
	tcItem.cchTextMax = MAX_PATH;
	tcItem.pszText = Buff;
	TabCtrl_GetItem(m_hWnd, item, &tcItem);
	return Buff;
}

//指定ページのタイトルを取得する
WCHAR* CTAB::GetTitle(int item) {

	if(item >= TabCount())
		return 0;
	static WCHAR Buff[MAX_PATH];	//ラベル文字列収容バッファ
	TCITEMW tcItem;					//タブコントロール情報構造体
	tcItem.mask = TCIF_TEXT;
	tcItem.cchTextMax = MAX_PATH;
	tcItem.pszText = Buff;
	TabCtrl_GetItem(m_hWnd, item, &tcItem);
	return Buff;
}
