//
//	ToolLib.cs
//
//	エディター共通処理 - ツールのGUI処理の統括部分
//
//	* Wed Apr 26 21:33:29 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//	* Thu Apr 27 22:34:39 JST 2017 Naoyuki Sawa
//	- Tool_Delete()を追加しました。
//	* Tue May 02 22:54:46 JST 2017 Naoyuki Sawa
//	- 各モジュール内のサイズ定義の倍率を一律で調整出来るように、ToolLib.csにTOOL_SCALEの定義を追加しました。
//	  詳細は、/clip/ToolLib/ToolLib.hの同日のコメントを参照して下さい。
//	* Fri May 12 09:53:14 JST 2017 Naoyuki Sawa
//	- Tool_EnableBaseRight()関数を追加しました。
//	  詳細は、/clip/ToolLib/ToolLib.hの同日のコメントを参照して下さい。
//	* Sun May 14 23:23:22 JST 2017 Naoyuki Sawa
//	- Tool_IsAnyHovered()関数を追加しました。
//	  詳細は、ToolLib.hの同日のコメントを参照して下さい。
//
using System;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	
		//*****************************************************************************
		public struct POINT { public int x, y; }			//┐
		public struct SIZE { public int cx, cy; }			//├'C:\Program Files (x86)\Microsoft Visual Studio\VC98\Include\WTYPES.H'参照
		public struct RECT { public int left, top, right, bottom; }	//┘
		//*****************************************************************************
		//	定数、マクロ、構造体
		//*****************************************************************************
		//初期化情報構造体
		public class SToolInfo {
		//{{静的に初期化出来るフィールド
			public Func<int/*x1*/,int/*y1*/,int/*x2*/,int/*y2*/,uint/*Color*/,bool/*FillFlag*/,int>				fnDrawBox;
			public Func<int/*x*/,int/*y*/,string/*String*/,uint/*Color*/,int/*FontHandle*/,int>				fnDrawStringToHandle;
			public Func<int/*x1*/,int/*y1*/,int/*x2*/,int/*y2*/,int/*x3*/,int/*y3*/,uint/*Color*/,bool/*FillFlag*/,int>	fnDrawTriangle;
			public Func<int/*Red*/,int/*Green*/,int/*Blue*/,uint>								fnGetColor;
			public delegate int fnGetDrawScreenSize_t(out int XBuf, out int YBuf);	//out/ref引数を取る関数はFunc<>では定義出来ないので明示的にdelegateで定義する必要が有る。□参考資料:「Func<T> with out parameter」(http://stackoverflow.com/questions/1283127/funct-with-out-parameter)
			public fnGetDrawScreenSize_t											fnGetDrawScreenSize;
			public Func<string/*String*/,int/*StrLen*/,int/*FontHandle*/,int>						fnGetDrawStringWidthToHandle;
			public Func<int>												fnGetMouseInput;
			public delegate int fnGetMousePoint_t(out int XBuf, out int YBuf);	//out/ref引数を取る関数はFunc<>では定義出来ないので明示的にdelegateで定義する必要が有る。□参考資料:「Func<T> with out parameter」(http://stackoverflow.com/questions/1283127/funct-with-out-parameter)
			public fnGetMousePoint_t												fnGetMousePoint;
			public Func<int/*x1*/,int/*y1*/,int/*x2*/,int/*y2*/,int>							fnSetDrawArea;
			public Func<int>												fnSetDrawAreaFull;
			public Func<int/*BlendMode*/,int/*BlendParam*/,int>								fnSetDrawBlendMode;
		//}}静的に初期化出来るフィールド
		//{{実行時に初期化するフィールド
			public int	NormalFontHandle;	//通常文字描画用のフォントハンドル。		一般的には「CreateFontToHandle(null,TOOL_FONT_HEIGHT,0,DX_FONTTYPE_EDGE  )」で初期化するのでこのフィールドは実行時に初期化する必要が有りますが、環境によってフォントハンドルを定数で表せる場合はこのフィールドも静的に初期化しても構いません。
			public int	ButtonFontHandle;	//ボタン内文字描画用のフォントハンドル。	一般的には「CreateFontToHandle(null,TOOL_FONT_HEIGHT,0,DX_FONTTYPE_NORMAL)」で初期化するのでこのフィールドは実行時に初期化する必要が有りますが、環境によってフォントハンドルを定数で表せる場合はこのフィールドも静的に初期化しても構いません。
		//}}実行時に初期化するフィールド
		}
		//-----------------------------------------------------------------------------
		private const int TOOL_BASE_RIGHT_X		= (TOOL_SCALE*(350));	//サイズ変更可能な表示領域の初期右端X座標。
		private const int TOOL_BASE_RIGHT_X_SPACE	= (TOOL_SCALE*(50));	//サイズ変更可能な表示領域を最大まで広くした場合の右端の余白。
		private const int TOOL_BASE_RIGHT_BAR_WIDTH	= (TOOL_SCALE*(4));	//サイズ変更可能な表示領域のサイズ変更帯の幅。
		//-----------------------------------------------------------------------------
		//ToolLib管理用構造体
		private struct SToolManage {
			public SToolInfo	pToolInfo;		//初期化情報ポインタ。
			public double		NowTime;		//通算経過時間。(単位:秒)
			public bool		BaseRightEnable;	//サイズ変更可能な表示領域の機能を使用するかどうか。
			public int		BaseRightX;		//サイズ変更可能な表示領域の右端X座標。
			public bool		BaseRightGrip;		//サイズ変更可能な表示領域のサイズ変更帯を掴んでいるかどうか。
			public int		BaseRightGripX;		//サイズ変更可能な表示領域のサイズ変更帯を掴んだときの右端X座標。
			public int		BaseRightGripMouseX;	//サイズ変更可能な表示領域のサイズ変更帯を掴んだときのマウスのX座標。
			public int		MouseInput;		//マウスのボタン入力状態。
			public int		MouseEdgeInput;		//マウスのボタン入力状態(押された瞬間のボタンのみ)。
			public int		MouseX, MouseY;		//マウスカーソルの座標。
			public int		MouseMovX, MouseMovY;	//マウスカーソルの座標移動量。
		}
		//*****************************************************************************
		//	ローカル変数
		//*****************************************************************************
		private static SToolManage	g_ToolManage;
		//*****************************************************************************
		//	アプリケーション用関数
		//*****************************************************************************
		//ツール用処理の初期化を行う。
		public static void Tool_Initialize(SToolInfo pToolInfo) {
			//構造体をクリアする。
			g_ToolManage = default(SToolManage);
			//初期化情報ポインタを格納する。
			g_ToolManage.pToolInfo = pToolInfo;
			//サイズ変更可能な表示領域の右端X座標の初期化。
			g_ToolManage.BaseRightEnable = true;
			g_ToolManage.BaseRightX = TOOL_BASE_RIGHT_X;
		}
		//-----------------------------------------------------------------------------
		//ツール用処理の後始末を行う。
		public static void Tool_Terminate() {
			//ウィジットを全て削除する。
			Tool_Delete();
			//構造体をクリアする。
			g_ToolManage = default(SToolManage);
		}
		//-----------------------------------------------------------------------------
		//ツール用処理の状態推移処理を行う。
		public static void Tool_Step(double StepTime) {
			int MouseX, MouseY;
			int ScreenWidth, ScreenHeight;
			//通算経過時間を加算する。
			g_ToolManage.NowTime += StepTime;
			//前回のマウスのボタン入力を保存。
			g_ToolManage.MouseEdgeInput = g_ToolManage.MouseInput;
			//マウスのボタン入力を取得。
			g_ToolManage.MouseInput = ToolFunc_GetMouseInput();
			//マウスのボタン入力状態(押された瞬間のボタンのみ)を算出。
			g_ToolManage.MouseEdgeInput ^= g_ToolManage.MouseInput;
			g_ToolManage.MouseEdgeInput &= g_ToolManage.MouseInput;
			//マウスカーソルの座標を取得。
			ToolFunc_GetMousePoint(out MouseX, out MouseY);
			//前回からの座標移動量を算出。
			g_ToolManage.MouseMovX = MouseX - g_ToolManage.MouseX;
			g_ToolManage.MouseMovY = MouseY - g_ToolManage.MouseY;
			//マウスカーソルの座標を保存。
			g_ToolManage.MouseX    = MouseX;
			g_ToolManage.MouseY    = MouseY;
			//ツール用処理のサイズ変更可能な表示領域の機能を使用するならば…
			if(g_ToolManage.BaseRightEnable) {
				//サイズ変更可能な表示領域のサイズ変更帯を掴んでいるかどうかで処理を変更。
				if(g_ToolManage.BaseRightGrip) {
					//掴んでいる状態で且つ左ボタンが押されている場合は表示領域のサイズをマウスカーソルの位置に応じて変更する。
					if((g_ToolManage.MouseInput & (1<<0)/*MOUSE_INPUT_LEFT*/) != 0) {
						g_ToolManage.BaseRightX = g_ToolManage.BaseRightGripX + (g_ToolManage.MouseX - g_ToolManage.BaseRightGripMouseX);
						//画面のサイズを取得する。
						ToolFunc_GetDrawScreenSize(out ScreenWidth, out ScreenHeight);
						//サイズが初期サイズよりも小さくならないようにする。
						if(g_ToolManage.BaseRightX < TOOL_BASE_RIGHT_X) {
						   g_ToolManage.BaseRightX = TOOL_BASE_RIGHT_X;
						//サイズが「画面横幅－余白」より大きくならないようにする。
						} else if(g_ToolManage.BaseRightX > (ScreenWidth - TOOL_BASE_RIGHT_X_SPACE)) {
							  g_ToolManage.BaseRightX = (ScreenWidth - TOOL_BASE_RIGHT_X_SPACE);
						}
					//左ボタンが押されていない場合は掴んでいるかどうかのフラグを倒す。
					} else {
						g_ToolManage.BaseRightGrip = false;
					}
				//マウスの左ボタンが押された瞬間の場合はサイズ変更可能な表示領域のサイズ変更帯を掴んでいるかチェックして、掴んでいたら掴み状態にする。
				} else if((((g_ToolManage.MouseEdgeInput & (1<<0)/*MOUSE_INPUT_LEFT*/)) != 0) &&
					   ( g_ToolManage.BaseRightX                              <= g_ToolManage.MouseX) &&
					   ((g_ToolManage.BaseRightX + TOOL_BASE_RIGHT_BAR_WIDTH) >= g_ToolManage.MouseX)) {
						g_ToolManage.BaseRightGrip       = true;
						g_ToolManage.BaseRightGripMouseX = g_ToolManage.MouseX;
						g_ToolManage.BaseRightGripX      = g_ToolManage.BaseRightX;
				}
			}
			//ウインドウ情報の状態推移処理を行う。
			ToolWindow_Step_All(StepTime);
			//ボタン情報の状態推移処理を行う。
			ToolButton_Step_All(StepTime);
			//リスト情報の状態推移処理を行う。
			ToolList_Step_All(StepTime);
		}
		//-----------------------------------------------------------------------------
		//ツール用処理の描画処理を行う。
		public static void Tool_Draw() {
			int ScreenWidth, ScreenHeight;
			//ウインドウ情報の描画処理を行う。
			ToolWindow_Draw_All();
			//ボタン情報の描画処理を行う。
			ToolButton_Draw_All();
			//リスト情報の描画処理を行う。
			ToolList_Draw_All();
			//ツール用処理のサイズ変更可能な表示領域の機能を使用するならば…
			if(g_ToolManage.BaseRightEnable) {
				//サイズ変更可能な表示領域右端のサイズ変更帯を描画する。
				ToolFunc_GetDrawScreenSize(out ScreenWidth, out ScreenHeight);
				ToolFunc_SetDrawBlendMode(1/*DX_BLENDMODE_ALPHA*/, 32);
				ToolFunc_DrawBox(g_ToolManage.BaseRightX,
				                 0,
				                 g_ToolManage.BaseRightX + TOOL_BASE_RIGHT_BAR_WIDTH,
				                 ScreenHeight,
				                 ToolFunc_GetColor(255,255,255),
				                 true);
				ToolFunc_SetDrawBlendMode(0/*DX_BLENDMODE_NOBLEND*/, 255);
			}
		}
		//-----------------------------------------------------------------------------
		//全ての種類のウィジットを全て削除する。
		public static void Tool_Delete() {
			//全てのリスト情報の削除処理を行う。
			ToolList_Delete_All();
			//全てのボタン情報の削除処理を行う。
			ToolButton_Delete_All();
			//全てのウインドウ情報の削除処理を行う。
			ToolWindow_Delete_All();
			//全ての表示状態情報の削除処理を行う。
			ToolVisible_Delete_All();
			//全てのスペース管理情報の削除処理を行う。
			ToolSpaceManage_Delete_All();
		}
		//-----------------------------------------------------------------------------
		//ツール用処理のサイズ変更可能な表示領域の右端のX座標を取得する。
		public static int Tool_GetBaseRightX() {
			int ScreenWidth, ScreenHeight;
			//ツール用処理のサイズ変更可能な表示領域の機能を使用するならば…
			if(g_ToolManage.BaseRightEnable) {
				//ツール用処理のサイズ変更可能な表示領域の右端のX座標を返す。
				return g_ToolManage.BaseRightX;
			//ツール用処理のサイズ変更可能な表示領域の機能を使用しないならば…
			} else {
				//画面の右端を、仮想的なサイズ変更可能な表示領域の右端のX座標とする。
				ToolFunc_GetDrawScreenSize(out ScreenWidth, out ScreenHeight);
				return ScreenWidth;
			}
		}
		//-----------------------------------------------------------------------------
		//ツール用処理のサイズ変更可能な表示領域の機能を使用するかどうかを設定する。
		public static void Tool_EnableBaseRight(bool bEnable) {
			g_ToolManage.BaseRightEnable = bEnable;
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルがいずれかのウィジットの内にあるかどうかをチェックする。
		public static bool Tool_IsAnyHovered() {
			//ツール用処理のサイズ変更可能な表示領域の機能を使用するならば…
			if(g_ToolManage.BaseRightEnable) {
				//サイズ変更可能な表示領域のサイズ変更帯の内にあるかどうかをチェックする。
				if(( g_ToolManage.BaseRightX                              <= g_ToolManage.MouseX) &&
				   ((g_ToolManage.BaseRightX + TOOL_BASE_RIGHT_BAR_WIDTH) >= g_ToolManage.MouseX)) { return true; }
			}
			//マウスカーソルがいずれかのウインドウの内にあるかどうかをチェックする。
			if(ToolWindow_IsAnyHovered()) { return true; }
			//マウスカーソルがいずれかのボタンの内にあるかどうかをチェックする。
			if(ToolButton_IsAnyHovered()) { return true; }
			//マウスカーソルがいずれかのリストの内にあるかどうかをチェックする。
			if(ToolList_IsAnyHovered()) { return true; }
			return false;
		}
		//*****************************************************************************
		//	ツールのGUI処理の内部でだけ使用する定義等				【C#版特有のコメント】C言語版ではToolLibの各モジュールから呼び出すために仕方無くグローバル関数にしていたが、C#では問題無いのでprivateに出来た。ただし、TOOL_SCALEとTOOL_FONT_HEIGHTはレイアウト計算等のためにアプリケーションからも参照出来る方が便利なので、TOOL_SCALEとTOOL_FONT_HEIGHTはpublicとする事にした。
		//*****************************************************************************
#if     !UNITY_5_3_OR_NEWER
		public const int TOOL_SCALE		= 1/*調整可*/;		//各モジュール内のサイズ定義の倍率。	TOOL_SCALEを'1'にするとオリジナル版のToolLibと同じサイズになります。高解像度の環境でUI要素のサイズが小さ過ぎた場合はTOOL_SCALEを'2'以上に変更して下さい。
#else //!UNITY_5_3_OR_NEWER
		public const int TOOL_SCALE		= 2/*調整可*/;		//各モジュール内のサイズ定義の倍率。	TOOL_SCALEを'1'にするとオリジナル版のToolLibと同じサイズになります。高解像度の環境でUI要素のサイズが小さ過ぎた場合はTOOL_SCALEを'2'以上に変更して下さい。	必ずしもUnity環境が高解像度という訳ではないのですが、高解像度で作成する事が多いと思うので、Unity環境ならば2倍にする事にしました。これはとりあえずの設定であり、実態に応じて変更可能です。
#endif//!UNITY_5_3_OR_NEWER
		public const int TOOL_FONT_HEIGHT	= (TOOL_SCALE*(12));	//ボタン用フォントの縦幅。
		//-----------------------------------------------------------------------------
		//通算経過時間を取得する。
		private static double ToolStatic_GetNowTime() {
			return g_ToolManage.NowTime;
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルが指定の矩形の内にあるかどうかをチェックする。
		private static bool ToolStatic_CheckMouseIn(int x1, int y1, int x2, int y2) {
			return ((g_ToolManage.MouseX >= x1) && (g_ToolManage.MouseX <= x2)) &&
			       ((g_ToolManage.MouseY >= y1) && (g_ToolManage.MouseY <= y2));
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルの座標を取得する。
		private static void ToolStatic_GetMousePosition(out int x, out int y) {
			x = g_ToolManage.MouseX;
			y = g_ToolManage.MouseY;
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルの前フレームから移動した距離を取得する。
		private static void ToolStatic_GetMouseMoveVecter(out int MoveX, out int MoveY) {
			MoveX = g_ToolManage.MouseMovX;
			MoveY = g_ToolManage.MouseMovY;
		}
		//-----------------------------------------------------------------------------
		//通常フォントハンドルを取得する。
		private static int ToolStatic_GetNormalFontHandle() {
			return g_ToolManage.pToolInfo.NormalFontHandle;
		}
		//-----------------------------------------------------------------------------
		//ボタン内文字用のフォントハンドルを取得する。
		private static int ToolStatic_GetButtonFontHandle() {
			return g_ToolManage.pToolInfo.ButtonFontHandle;
		}
		//-----------------------------------------------------------------------------
		//マウスのボタン押下状態を取得する。
		private static int ToolStatic_GetMouseButton() {
			return g_ToolManage.MouseInput;
		}
		//-----------------------------------------------------------------------------
		//マウスのボタン押下状態を取得する。(押された瞬間のみの情報)
		private static int ToolStatic_GetMouseEdgeButton() {
			return g_ToolManage.MouseEdgeInput;
		}
		//-----------------------------------------------------------------------------
		//ツール処理のボタンを描画する。
		private static void ToolStatic_DrawButton(int x, int y, int w, int h, int LeftTopColor1, int LeftTopColor2, int RightBottomColor1, int RightBottomColor2, int CenterColor) {
			//中央部分を描画。
			ToolFunc_SetDrawBlendMode(1/*DX_BLENDMODE_ALPHA*/, 128);
			ToolFunc_DrawBox(x + 2, y + 2, x + w - 2, y + h - 2, (uint)CenterColor, true);
			ToolFunc_SetDrawBlendMode(1/*DX_BLENDMODE_ALPHA*/, 200);
			//左端と上端を描画。
			ToolFunc_DrawBox(x,     y,     x + w - 1, y + 1,     (uint)LeftTopColor1, true);
			ToolFunc_DrawBox(x + 1, y + 1, x + w - 2, y + 2,     (uint)LeftTopColor2, true);
			ToolFunc_DrawBox(x,     y + 1, x + 1,     y + h - 1, (uint)LeftTopColor1, true);
			ToolFunc_DrawBox(x + 1, y + 2, x + 2,     y + h - 2, (uint)LeftTopColor2, true);
			//右端と下端を描画。
			ToolFunc_DrawBox(x,         y + h - 1,  x + w,     y + h,     (uint)RightBottomColor1, true);
			ToolFunc_DrawBox(x + 1,     y + h - 2,  x + w,     y + h - 1, (uint)RightBottomColor2, true);
			ToolFunc_DrawBox(x + w - 1, y,          x + w,     y + h - 1, (uint)RightBottomColor1, true);
			ToolFunc_DrawBox(x + w - 2, y + 1,      x + w - 1, y + h - 2, (uint)RightBottomColor2, true);
			ToolFunc_SetDrawBlendMode(0/*DX_BLENDMODE_NOBLEND*/, 0);
		}
		//*****************************************************************************
		//	アプリケーション定義の関数呼び出し					【C#版特有のコメント】C言語版ではToolLibの各モジュールから呼び出すために仕方無くグローバル関数にしていたが、C#では問題無いのでprivateに出来た。
		//*****************************************************************************
		private static int ToolFunc_DrawBox(int x1, int y1, int x2, int y2, uint Color, bool FillFlag) { return g_ToolManage.pToolInfo.fnDrawBox.Invoke(x1, y1, x2, y2, Color, FillFlag); }
		private static int ToolFunc_DrawStringToHandle(int x, int y, string String, uint Color, int FontHandle/*, uint EdgeColor = 0, bool VerticalFlag = 0*/) { return g_ToolManage.pToolInfo.fnDrawStringToHandle.Invoke(x, y, String, Color, FontHandle); }
		private static int ToolFunc_DrawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, uint Color, bool FillFlag) { return g_ToolManage.pToolInfo.fnDrawTriangle.Invoke(x1, y1, x2, y2, x3, y3, Color, FillFlag); }
		private static uint ToolFunc_GetColor(int Red, int Green, int Blue) { return g_ToolManage.pToolInfo.fnGetColor.Invoke(Red, Green, Blue); }
		private static int ToolFunc_GetDrawScreenSize(out int XBuf, out int YBuf) { return g_ToolManage.pToolInfo.fnGetDrawScreenSize.Invoke(out XBuf, out YBuf); }
		private static int ToolFunc_GetDrawStringWidthToHandle(string String, int StrLen, int FontHandle/*, bool VerticalFlag = 0*/) { return g_ToolManage.pToolInfo.fnGetDrawStringWidthToHandle.Invoke(String, StrLen, FontHandle); }
		private static int ToolFunc_GetMouseInput() { return g_ToolManage.pToolInfo.fnGetMouseInput.Invoke(); }
		private static int ToolFunc_GetMousePoint(out int XBuf, out int YBuf) { return g_ToolManage.pToolInfo.fnGetMousePoint.Invoke(out XBuf, out YBuf); }
		private static int ToolFunc_SetDrawArea(int x1, int y1, int x2, int y2) { return g_ToolManage.pToolInfo.fnSetDrawArea.Invoke(x1, y1, x2, y2); }
		private static int ToolFunc_SetDrawAreaFull() { return g_ToolManage.pToolInfo.fnSetDrawAreaFull.Invoke(); }
		private static int ToolFunc_SetDrawBlendMode(int BlendMode, int BlendParam) { return g_ToolManage.pToolInfo.fnSetDrawBlendMode.Invoke(BlendMode, BlendParam); }
	}
}
