//////////////////////////////////////////
// BCFEditor.h
// Copyright (c) 06/23/2002 by BCCSkelton
//////////////////////////////////////////
//BCCSkeltonのヘッダー−これに必要なヘッダーが入っている
#include	"BCCSkelton.h"
//特殊リッチエディットコントロールのヘッダー
#include	"CREDITEX.h"
//リソースIDのヘッダー
#include	"ResBCFEditor.h"
//リッチテキストコントロール用
#define	IDC_CHILD_CONTROL	1

/////////////////////////////////////
//リッチエディットコントロールの作成
/////////////////////////////////////
//☆リッチエディットコントロールの定義がここにあるのは、メッセージテーブルに認識させるためです
CREDITEX Edit;

/////////////////////////////////////////////////////////////////////
//CMyWndクラスをCMDIクラスから派生させ、メッセージ用の関数を宣言する
/////////////////////////////////////////////////////////////////////
class CMyWnd : public CMDI
{

public:	//以下はコールバック関数マクロと関連している
	//２重起動防止用のMutex用ID名称
	CMyWnd(char* UName) : CMDI(UName) {}
	//メニュー項目、ダイアログコントロール関連
	bool OnNew();
	bool OnOpen();
	bool OnSave(HWND);
	bool OnSaveas(HWND);
	bool OnSetprint();
	bool OnPrint(HWND);
	bool OnExit();
	bool OnUndo(HWND);
	bool OnRedo(HWND);
	bool OnCut(HWND);
	bool OnCopy(HWND);
	bool OnPaste(HWND);
	bool OnSelall(HWND);
	bool OnFind(HWND);
	bool OnReplace(HWND);
	bool OnJump(HWND);
	bool OnDialogon();
	bool OnDialogoff();
	bool OnSet();
	bool OnSkelton();
	bool OnMake();
	bool OnTilehorz();
	bool OnTilevert();
	bool OnCascade();
	bool OnArrange();
	bool OnBccskelton();
	bool OnShortCut();
	bool OnVer();
	//ウィンドウメッセージ関連
	bool OnMDIFrameCreate(WPARAM, LPARAM);
	bool OnMDIChildCreate(WPARAM, LPARAM);
	bool OnMDIActivate(WPARAM, LPARAM);
	bool OnSetFocus(WPARAM, LPARAM);
	bool OnFindReplace(LPARAM);
	bool OnMDIFrameSize(WPARAM, LPARAM);
	bool OnMDIChildSize(WPARAM, LPARAM);
	bool OnNotify(WPARAM, LPARAM);
	bool OnChange(WPARAM);
	bool OnChildClose(HWND);
	bool OnClose(WPARAM, LPARAM);
	bool OnDropFiles(WPARAM);
};

////////////////////////////////////////////////////////////////////////
//派生させたCMyWndクラスのインスタンスとコールバック関数(マクロ）の作成
//主ウィンドウはダイアログと違い、コールバック関数は一つしか作れない
////////////////////////////////////////////////////////////////////////
CMyWnd BCFEditor("BCFEditor");	//ウィンドウクラスインスタンスの生成

BEGIN_MDIMSG(BCFEditor)	//ダイアログと違い、コールバック関数名を特定しない
	//メニュー項目、ダイアログコントロール関連
	ON_COMMAND(BCFEditor, IDM_NEW, OnNew())
	ON_COMMAND(BCFEditor, IDM_OPEN, OnOpen())
	ON_COMMAND(BCFEditor, IDM_SETPRINT, OnSetprint())
	ON_COMMAND(BCFEditor, IDM_EXIT, OnExit())
	ON_COMMAND(BCFEditor, IDM_SET, OnSet())
	ON_COMMAND(BCFEditor, IDM_SKELTON, OnSkelton())
	ON_COMMAND(BCFEditor, IDM_MAKE, OnMake())
	ON_COMMAND(BCFEditor, IDM_CASCADE, OnCascade())
	ON_COMMAND(BCFEditor, IDM_TILEHORZ, OnTilehorz())
	ON_COMMAND(BCFEditor, IDM_TILEVERT, OnTilevert())
	ON_COMMAND(BCFEditor, IDM_ARRANGE, OnArrange())
	ON_COMMAND(BCFEditor, IDM_BCCSKELTON, OnBccskelton())
	ON_COMMAND(BCFEditor, IDM_SHORTCUT, OnShortCut())
	ON_COMMAND(BCFEditor, IDM_VER, OnVer())
	//ウィンドウメッセージ関連
	//MDIFrame親ウィンドウは自動的にOnMDIFrameCreate()を呼ぶ
	ON_MDIFRAMESIZE(BCFEditor)
	ON_NOTIFY(BCFEditor)
	ON_CLOSE(BCFEditor)
	ON_(BCFEditor, WM_DROPFILES, OnDropFiles(wParam))
END_MDIMSG(BCFEditor)

//ウィンドウメッセージは全てフレームウィンドウにあるので、
//必要なメッセージ関数を子供ウィンドウへ移すことが必要
//☆以下の関数の殆どは親から移動したものです。処理によってどこに置くべきか考えます。
//☆MDI子メッセージテーブル内では、m_FocusedChildメンバー変数に子のhWndが入ります
BEGIN_MDICHILDMSG(BCFEditor)	//ダイアログと違い、コールバック関数名を特定しない
	ON_COMMAND(BCFEditor, IDM_SAVE, OnSave(hWnd))
	ON_COMMAND(BCFEditor, IDM_SAVEAS, OnSaveas(hWnd))
	ON_COMMAND(BCFEditor, IDM_PRINT, OnPrint(hWnd))
	ON_COMMAND(BCFEditor, IDM_UNDO, OnUndo(hWnd))
	ON_COMMAND(BCFEditor, IDM_REDO, OnRedo(hWnd))
	ON_COMMAND(BCFEditor, IDM_CUT, OnCut(hWnd))
	ON_COMMAND(BCFEditor, IDM_COPY, OnCopy(hWnd))
	ON_COMMAND(BCFEditor, IDM_PASTE, OnPaste(hWnd))
	ON_COMMAND(BCFEditor, IDM_SELALL, OnSelall(hWnd))
	ON_COMMAND(BCFEditor, IDM_FIND, OnFind(hWnd))
	ON_COMMAND(BCFEditor, IDM_REPLACE, OnReplace(hWnd))
	ON_COMMAND(BCFEditor, IDM_JUMP, OnJump(hWnd))
	ON_COMMAND(BCFEditor, IDM_DIALOGON, OnDialogon())
	ON_COMMAND(BCFEditor, IDM_DIALOGOFF, OnDialogoff())
	ON_COMMAND(BCFEditor, IDC_CHILD_CONTROL, OnChange(wParam))	//EN_CHANGE処理
	//MDIChild子ウィンドウは自動的にOnMDIChildCreate()を呼ぶ
	ON_SETFOCUS(BCFEditor)
	ON_NOTIFY(BCFEditor)
	ON_(BCFEditor, WM_CLOSE, OnChildClose(hWnd))				//子の終了処理
	//☆重要！CREDITクラスは文字列検索･置換用にユーザーメッセージを作るので、
	//  このような処理を行います。CREDITファイルを覗いてください。
	ON_(BCFEditor, Edit.m_frMsg, OnFindReplace(lParam))
	ON_MDICHILDSIZE(BCFEditor)
END_MDICHILDMSG

///////////////////
//ツールバーの作成
///////////////////
CTBAR TBar;

///////////////////////
//ステータスバーの作成
///////////////////////
CSBAR SBar;

/////////////////////////
//コモンダイアログの作成
/////////////////////////
CMNDLG cmndlg;

///////////////////////
//クリップボードの作成
///////////////////////
CCLIPBOARD Clip;

//////////////////////////////////////////
//右クリックポップアップメニューのハンドル
//////////////////////////////////////////
HMENU g_hPopup;

////////////////////////////////////
//CARGクラスとファイル付き起動フラグ
////////////////////////////////////
CARG arg;
bool ByFile = FALSE;

////////////////////
//初期化ファイル関連
////////////////////
CINI ini;

///////////////////////////////////////////
// CDLGクラスからSETUPDLGクラスを派生
// 複数の同一ダイアログ変数とダイアログも作
// れるが、一つのダイアログに一つの派生ダイ
// アログクラスを作成するのが基本
///////////////////////////////////////////
class SETUPDLG : public CDLG {
public:
	//背景色の変更に使用する
	HBRUSH m_Brush;
	//メニュー項目、ダイアログコントロール関連
	bool OnIdok();
	bool OnMaker();
	bool OnSkelton();
	bool OnFont();
	bool OnBackCol();
	bool OnDirective();
	bool OnConstant();
	bool OnReserve();
	bool OnComment();
	bool OnString();
	bool OnBCCClass();
	//ウィンドウメッセージ関連
	bool OnInit(WPARAM, LPARAM);
	bool OnOwnerdraw(WPARAM, LPARAM);
	bool OnDestroy(WPARAM, LPARAM);
};

//////////////////////////////////////////////////////////////////////////////
// SETUPDLGDLGクラスダイアログ変数の生成とそのコールバック関数（マクロ）を定義
// 複数同一クラスのダイアログを作成することを予期してコールバック関数を明記
//////////////////////////////////////////////////////////////////////////////
SETUPDLG setupdlg;

BEGIN_MODALDLGMSG(setupdlgProc, setupdlg)	//第1引数がコールバック関数の名前
	//メニュー項目、ダイアログコントロール関連
	ON_COMMAND(setupdlg, IDOK, OnIdok())
	ON_COMMAND(setupdlg, IDC_MAKERBTN, OnMaker())
	ON_COMMAND(setupdlg, IDC_SKELTONBTN, OnSkelton())
	ON_COMMAND(setupdlg, IDC_FONTBTN, OnFont())
	ON_COMMAND(setupdlg, IDC_BKCOL, OnBackCol())
	ON_COMMAND(setupdlg, IDC_CDIR, OnDirective())
	ON_COMMAND(setupdlg, IDC_CNST, OnConstant())
	ON_COMMAND(setupdlg, IDC_RSV, OnReserve())
	ON_COMMAND(setupdlg, IDC_CMT, OnComment())
	ON_COMMAND(setupdlg, IDC_STR, OnString())
	ON_COMMAND(setupdlg, IDC_BCC, OnBCCClass())
	//ウィンドウメッセージ関連
	ON_(setupdlg, WM_DRAWITEM, OnOwnerdraw(wParam, lParam))
	ON_DESTROY(setupdlg)
END_DLGMSG

///////////////////////////////////////////
// CDLGクラスからJUMPDLGクラスを派生
// 複数の同一ダイアログ変数とダイアログも作
// れるが、一つのダイアログに一つの派生ダイ
// アログクラスを作成するのが基本
///////////////////////////////////////////
class JUMPDLG : public CDLG {
public:
	bool OnIdok();
};

////////////////////////////////////////////////////////////////////////////
// JUMPDLGクラスダイアログ変数の生成とそのコールバック関数（マクロ）を定義
// 複数同一クラスのダイアログを作成することを予期してコールバック関数を明記
////////////////////////////////////////////////////////////////////////////
JUMPDLG jumpdlg;

BEGIN_MODALDLGMSG(jumpdlgProc, jumpdlg)	//第1引数がコールバック関数の名前
	ON_COMMAND(jumpdlg, IDOK, OnIdok())
END_DLGMSG

///////////////////////////////////////////
// CDLGクラスからVERSIONDLGクラスを派生
// 複数の同一ダイアログ変数とダイアログも作
// れるが、一つのダイアログに一つの派生ダイ
// アログクラスを作成するのが基本
///////////////////////////////////////////
class VERSIONDLG : public CDLG {
public:
	bool OnInit(WPARAM, LPARAM);
	bool OnIdok();
};

////////////////////////////////////////////////////////////////////////////
// VERSIONDLGクラスダイアログ変数の生成とそのコールバック関数（マクロ）を定義
// 複数同一クラスのダイアログを作成することを予期してコールバック関数を明記
////////////////////////////////////////////////////////////////////////////
VERSIONDLG versiondlg;

BEGIN_MODALDLGMSG(versiondlgProc, versiondlg)	//第1引数がコールバック関数の名前
	ON_COMMAND(versiondlg, IDOK, OnIdok())
END_DLGMSG

///////////////////////////////////////////
// CDLGクラスからBCFHELPERDLGクラスを派生
// 複数の同一ダイアログ変数とダイアログも作
// れるが、一つのダイアログに一つの派生ダイ
// アログクラスを作成するのが基本
///////////////////////////////////////////
class BCFHELPERDLG : public CDLG {
public:
	//変数
	CSTR	m_FileName;			//Res.hファイルパス、名
	CSTR	m_InstName;			//メインインスタンス名（= 拡張子なしファイル名）
	bool Init(char*);			//Res〜.hファイルで初期化する
	void SetMsg();				//Window Messageの設定
	char** SearchMsg(int);		//WMのON_〜とOn〜の加工型を返す
	void SetMenuCtrl();			//メニュー、ダイアログコントロールの設定
	char** GetMenuCtrl(int);	//メニュー、ダイアログコントロールの加工型を返す
	//ウィンドウメッセージ関連
	bool OnInit(WPARAM, LPARAM);
	//メニュー項目、ダイアログコントロール関連
	bool OnCombobox(WPARAM);
	bool OnIdok();
	bool OnIdcancel();
};

////////////////////////////////////////////////////////////////////////////
// BCFHELPERDLGクラスのインスタンス生成とコールバック関数（マクロ）を定義
// 複数同一クラスのダイアログを作成することを予期してコールバック関数を明記
////////////////////////////////////////////////////////////////////////////
BCFHELPERDLG bcfhelperdlg;

BEGIN_MODALDLGMSG(bcfhelperdlgProc, bcfhelperdlg)	//第1引数がコールバック関数の名前
	//メニュー項目、ダイアログコントロール関連
	ON_COMMAND(bcfhelperdlg, IDC_COMBOBOX, OnCombobox(wParam))
	ON_COMMAND(bcfhelperdlg, IDOK, OnIdok())
	ON_COMMAND(bcfhelperdlg, IDCANCEL, OnIdcancel())
END_DLGMSG

//メインインスタンス名の設定
bool BCFHELPERDLG::Init(char* filename) {	//"Res〜.h"ファイルを前提とする

	m_FileName = filename;	//Res〜.hファイルパス、名を記録
	//"Res"を外したものをインスタンス名として記録する
	char* cp = strstr(filename, "Res");
	if(cp)
		m_InstName = (cp + 3);
	else {
		MessageBox(m_hWnd, "Resヘッダーファイルではありません", "エラー", MB_OK | MB_ICONERROR);
		return FALSE;
	}
	//拡張子(.h)も外す
	if(cp = strstr(m_InstName.ToChar(), ".h")) {
		*cp = NULL;
		m_InstName = m_InstName.ToChar();
	}
	return TRUE;
}

//Window Messageの設定
void BCFHELPERDLG::SetMsg() {

	static char* wm[30] = {"WM_CREATE",
		"WM_INITDIALOG",
		"WM_ACTIVATE",
		"WM_ENABLE",
		"WM_TIMER",
		"WM_SETFOCUS",
		"WM_CHAR",
		"WM_KEYUP",
		"WM_KEYDOWN",
		"WM_LBUTTONDOWN",
		"WM_LBUTTONUP",
		"WM_LBUTTONDBLCLK",
		"WM_MBUTTONDOWN",
		"WM_MBUTTONUP",
		"WM_MBUTTONDBLCLK",
		"WM_RBUTTONDOWN",
		"WM_RBUTTONUP",
		"WM_RBUTTONDBLCLK",
		"WM_MOUSEMOVE",
		"WM_NOTIFY",
		"WM_SIZE",
		"WM_MOVE",
		"WM_HSCROLL",
		"WM_VSCROLL",
		"WM_PAINT",
		"WM_ERASEBKGND",
		"WM_CLOSE",
		"WM_DESTROY",
		"WM_DROPFILES",
		"WM_GETMINMAXINFO"
	};
	for(int i = 0; i < 30; i++)
		SendItemMsg(IDC_LISTBOX, LB_INSERTSTRING, i, (LPARAM)wm[i]);
}

char** BCFHELPERDLG::SearchMsg(int i) {

	static char* wm[30][2] = {
		{"ON_CREATE", "OnCreate"},
		{"ON_INITDIALOG", "OnInit"},
		{"ON_ACTIVATE", "OnActivate"},
		{"ON_ENABLE", "OnEnable"},
		{"ON_TIMER", "OnTimer"},
		{"ON_SETFOCUS", "OnSetFocus"},
		{"ON_CHAR", "OnChar"},
		{"ON_KEYUP", "OnKeyUp"},
		{"ON_KEYDOWN", "OnKeyDown"},
		{"ON_LBUTTONDOWN", "OnLButtonDown"},
		{"ON_LBUTTONUP", "OnLButtonUp"},
		{"ON_LBUTTONDBLCLK", "OnLButtonDblClk"},
		{"ON_MBUTTONDOWN", "OnMButtonDown"},
		{"ON_MBUTTONUP", "OnMButtonUp"},
		{"ON_MBUTTONDBLCLK", "OnMButtonDblClk"},
		{"ON_RBUTTONDOWN", "OnRButtonDown"},
		{"ON_RBUTTONUP", "OnRButtonUp"},
		{"ON_RBUTTONDBLCLK", "OnRButtonDblClk"},
		{"ON_MOUSEMOVE", "OnMouseMove"},
		{"ON_NOTIFY", "OnNotify"},
		{"ON_SIZE", "OnSize"},
		{"ON_MOVE", "OnMove"},
		{"ON_HSCROLL", "OnHScroll"},
		{"ON_VSCROLL", "OnVScroll"},
		{"ON_PAINT", "OnPaint"},
		{"ON_ERASEBKGND", "OnEraseBkgnd"},
		{"ON_CLOSE", "OnClose"},
		{"ON_DESTROY", "OnDestroy"},
		{"ON_DROPFILES", "OnDropFiles"},
		{"ON_MINMAX", "OnMiniMax"}
	};
	return wm[i];
}

//メニュー、ダイアログコントロールの設定
void BCFHELPERDLG::SetMenuCtrl() {

	CSTR File, Line, Word, Res, Output;
	char* cp;
	if(!File.FromFile(m_FileName.ToChar()))	//Res.hファイルを読み込む
		MessageBox(m_hWnd, "ファイルを飲み込めませんでした", m_FileName.ToChar(), MB_OK | MB_ICONERROR);
	while(File.GetLine(Line)) {		//ファイルから一行読み出す
		//GetLineで取得した文字列には'\r\n'がついているのでそれを外す
		*(strstr(Line.ToChar(), "\r\n")) = NULL;
		if(cp = strstr(Line.ToChar(), "// ダイアログ ")) {
			cp += lstrlen("// ダイアログ ");
			Res = "Dlg :";
			Res = Res + cp;
		}
		else if(cp = strstr(Line.ToChar(), "// メニュー ")) {
			cp += lstrlen("// メニュー ");
			Res = "Menu:";
			Res = Res + cp;
		}
		else if(cp = strstr(Line.ToChar(), "#define	")) {
			cp += lstrlen("#define	");
			Line = cp;
			Line.Next(Word);
			Output = Res + "->" + Word;
			SendItemMsg(IDC_LISTBOX, LB_ADDSTRING, 0, (LPARAM)Output.ToChar());
		}
		else if(strstr(Line.ToChar(), "イメージリソース"))
			break;
		else if(strstr(Line.ToChar(), "ストリングテーブル"))
			break;
		else if(strstr(Line.ToChar(), "アクセラレーター"))
			break;
		else if(strstr(Line.ToChar(), "ヴァージョン情報"))
			break;
	}
}

//メニュー、ダイアログコントロールの加工型を返す
char** BCFHELPERDLG::GetMenuCtrl(int i) {

	//リストボックスの指定行の文字列を取得
	static char line[MAX_PATH];
	SendItemMsg(IDC_LISTBOX, LB_GETTEXT, i, (LPARAM)line);
	//word[0]はリソース名、word[1]は"->"以降のアイテム名、word[3]はオリジナル名
	static char* word[3];
	//オリジナル名の確保
	static char org[MAX_PATH / 4];
	lstrcpy(org, (strstr(line, "->") + 2));	//"->"は必ずある
	word[2] = org;
	/*
	//書式は以下の通り
	// Dlg :(ダイアログ名)->(コントロール名)
	// Menu:(ダイアログ名)->(コントロール名)
	// 文頭から'_'迄は除去
	// ダイアログ名はすべて小文字で最後に"dlg"を付ける
	// アイテム名は第1文字を大文字以下を小文字とし"bool On"と"()"で挟む
	*/
	//ダイアログかメニュ^かの判定フラグ
	bool IsMenu = strstr(line, "Menu:");
	//ダイアログ名取得が完了したかのフラグ
	bool Done = FALSE;
	char* sp = line + 5;	//テキスト判読開始ポイント
	word[0] = sp;			//リソース名取得開始ポイント
	while(*sp) {
		switch(*sp) {
		case '_':
			sp++;
			if(Done)
				word[1] = sp;	//コントロール、メニューアイテムのやり直し
			else
				word[0] = sp;	//リソース名のやり直し
			break;
		case '-':
			if(*(sp + 1) == '>') {	//"->"の場合
				*sp++ = NULL;		//'-'をヌルに
				*sp++ = NULL;		//'>'をヌルにして
				Done = TRUE;		//リソース名が完了
				word[1] = sp;
			}
			break;
		default:
			break;
		}
		sp++;
	}
	//wordの整形(word[0]がメニューの場合はNULL)
	if(IsMenu)
		word[0] = NULL;
	else
		for(char* cp = word[0]; *cp; cp++)
			if(isupper(*cp))
				*cp = tolower(*cp);
	for(char* cp = word[1] + 1; *cp; cp++)
		if(isupper(*cp))
			*cp = tolower(*cp);
	if(islower(word[1][0]))
		word[1][0] = toupper(word[1][0]);	//コントロール等の最初の1字は大文字
	//3語を返す
	return word;
}
