//
//	ToolLib_Button.cs
//
//	エディター共通処理 - ツールのGUIのウインドウ
//
//	* Wed Apr 26 21:33:29 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//	* Tue May 02 22:54:46 JST 2017 Naoyuki Sawa
//	- 各モジュール内のサイズ定義の倍率を一律で調整出来るように、ToolLib.csにTOOL_SCALEの定義を追加しました。
//	  詳細は、/clip/ToolLib/ToolLib.hの同日のコメントを参照して下さい。
//	* Sun May 14 23:23:22 JST 2017 Naoyuki Sawa
//	- ToolButton_IsAnyHovered(),ToolButton_IsHovered()関数を追加しました。
//	  詳細は、ToolLib.hの同日のコメントを参照して下さい。
//
using System;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	定数、マクロ、構造体
		//*****************************************************************************
		private const double TOOL_FIRST_REPEAT_WAIT	= (0.2);	//ボタンリピートの最初の待ち時間。
		private const double TOOL_REPEAT_WAIT		= (0.017);	//2回目以降のボタンリピートの間隔。
		//-----------------------------------------------------------------------------
		//ボタン構造体
		public class SToolButton {
			public SToolVisible	TVisible;		//関連付けられている表示状態情報。
			public SToolWindow	TWindow;		//関連付けられているウインドウ情報。
			public bool		On_Off_SwitchType;	//ON状態とOFF状態が押すたびに切り替わるタイプのボタンかどうか。
			public POINT		Position;		//ボタンの位置。
			public SIZE		Size;			//ボタンのサイズ。
			public string		Name;			//ボタンの名前の文字列が格納されているメモリアドレスを保存しているポインタ。
			public bool		Visible;		//表示状態。
			public bool		Bottom;			//ボタンが押下状態かどうか。
			public double		BottomTime;		//ボタンが押下されている時間。
			public bool		FirstRepeat;		//最初のリピート処理が行われたかどうか。
			public bool		RepeatBottom;		//リピート入力も考慮したボタン押下状態。
			public bool		Click;			//ボタンがクリックされたかどうか。
			public bool		OnOffFlag;		//ボタンのON/OFF状態。
		}
		//*****************************************************************************
		//	ローカル変数
		//*****************************************************************************
		private static GSList	g_TButton;
		//*****************************************************************************
		//	アプリケーション用関数
		//*****************************************************************************
		//ボタン情報を作成する。
		public static SToolButton ToolButton_Create(bool On_Off_SwitchType, string Name, int x, int y, int w, int h) {
			SToolButton TButton;
			//新しいボタン情報を格納するためのメモリの確保。
			TButton = new SToolButton();
			//確保したメモリ領域を保存。
			g_TButton = g_slist_append(g_TButton, TButton);
			//情報を初期化。
		//不要	TButton.TVisible          = null;
		//不要	TButton.TWindow           = null;
			TButton.On_Off_SwitchType = On_Off_SwitchType;
			TButton.Position.x        = x;
			TButton.Position.y        = y;
			TButton.Size.cx           = w;
			TButton.Size.cy           = h;
			TButton.Visible           = true;
		//不要	TButton.Bottom            = 0;
		//不要	TButton.BottomTime        = 0.0;
		//不要	TButton.FirstRepeat       = 0;
		//不要	TButton.Click             = 0;
		//不要	TButton.OnOffFlag         = 0;
			ToolButton_SetName(TButton, Name);
			//ボタン情報を返す。
			return TButton;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報を削除する。
		public static void ToolButton_Delete(SToolButton TButton) {
			//名前保存用にメモリを確保していた場合は解放。
			/** no job **/
			//確保していたメモリを解放する。
			g_TButton = g_slist_remove(g_TButton, TButton);
		}
		//-----------------------------------------------------------------------------
		//全てのボタン情報を削除する。
		public static void ToolButton_Delete_All() {
			//有効な全てのボタンを削除する。
			while(g_TButton != null) { ToolButton_Delete((SToolButton)g_TButton.data); }
		}
		//-----------------------------------------------------------------------------
		//ボタン情報に関連付ける表示状態情報をセットする。
		public static void ToolButton_SetVisibleHandle(SToolButton TButton, SToolVisible TVisible) {
			TButton.TVisible = TVisible;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報の名前を設定する。
		public static void ToolButton_SetName(SToolButton TButton, string Name) {
			//既に名前用にメモリを確保していた場合は解放する。
			/** no job **/
			//名前のアドレスが有効な場合はメモリを確保して保存する。
			TButton.Name = Name;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報と関連付けるウインドウ情報を設定する。
		public static void ToolButton_SetWindow(SToolButton TButton, SToolWindow TWindow) {
			TButton.TWindow = TWindow;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報の位置を変更する。
		public static void ToolButton_SetPosition(SToolButton TButton, int x, int y) {
			TButton.Position.x = x;
			TButton.Position.y = y;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報のON/OFF状態を変更する。
		public static void ToolButton_SetOnOffFlag(SToolButton TButton, bool Flag) {
			TButton.OnOffFlag = Flag;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報のON/OFF状態を取得する。
		public static bool ToolButton_GetOnOffFlag(SToolButton TButton) {
			return TButton.OnOffFlag;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報のボタンがクリックされたかどうかを取得する。
		public static bool ToolButton_GetClick(SToolButton TButton, bool Reset) {
			bool Ret = TButton.Click;
			if(Reset) { TButton.Click = false; }
			return Ret;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報のボタンが押下されているかどうかを取得する。
		public static bool ToolButton_GetBottom(SToolButton TButton) {
			return TButton.Bottom;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報のボタンが押下されているかどうかを取得する。(リピート機能付き版)
		public static bool ToolButton_GetRepeatBottom(SToolButton TButton) {
			return TButton.RepeatBottom;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報の表示状態を変更する。
		public static void ToolButton_SetVisible(SToolButton TButton, bool Visible) {
			//新しい表示状態を保存する。
			TButton.Visible = Visible;
		}
		//-----------------------------------------------------------------------------
		//ボタン情報の表示状態を取得する。
		public static bool ToolButton_GetVisible(SToolButton TButton) {
			//表示状態が0の場合は0を返す。
			if(!TButton.Visible) { return false; }
			//関連付けられているウインドウ情報の表示状態が0の場合は0を返す。
			if(!ToolWindow_GetVisible(TButton.TWindow)) { return false; }
			//表示状態情報が登録されていて、且つ表示状態情報の表示状態が0の場合は0を返す。
			if(!ToolVisible_GetVisible(TButton.TVisible)) { return false; }
			//ここにきていたら非表示ではないということなので0以外を返す。
			return true;
		}
		//-----------------------------------------------------------------------------
		//全てのボタン情報の状態推移処理を行う。
		public static void ToolButton_Step_All(double StepTime) {
			GSList list = g_TButton;
			while(list != null) {
				ToolButton_Step((SToolButton)list.data, StepTime);
				list = list.next;
			}
		}
		//-----------------------------------------------------------------------------
		//全てのボタン情報の描画移処理を行う。
		public static void ToolButton_Draw_All() {
			GSList list = g_TButton;
			while(list != null) {
				ToolButton_Draw((SToolButton)list.data);
				list = list.next;
			}
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルがいずれかのボタンの内にあるかどうかをチェックする。
		public static bool ToolButton_IsAnyHovered() {
			GSList list = g_TButton;
			while(list != null) {
				if(ToolButton_IsHovered((SToolButton)list.data)) { return true; }
				list = list.next;
			}
			return false;
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルがボタンの内にあるかどうかをチェックする。
		public static bool ToolButton_IsHovered(SToolButton TButton) {
			int MouseX, MouseY;
			int TempX, TempY;
			bool In;
			//表示状態が0の場合は何もせず終了。
			if(!ToolButton_GetVisible(TButton)) { return false; }	//ここまで
			//マウスカーソルの位置を取得。
			ToolStatic_GetMousePosition(out MouseX, out MouseY);
			//ボタンの表示位置とボタンの表示領域にマウスカーソルがあるかどうかを取得。
			if(TButton.TWindow != null) {
				ToolWindow_GetDrawLeftUpPos(TButton.TWindow, out TempX, out TempY);
				TempX += TButton.Position.x;
				TempY += TButton.Position.y;
				In = ToolStatic_CheckMouseIn(TempX,
				                             TempY,
				                             TempX + TButton.Size.cx,
				                             TempY + TButton.Size.cy) &&
				     ToolWindow_CheckInfoAreaIn(TButton.TWindow,
				                                MouseX,
				                                MouseY);
			} else {
				TempX = TButton.Position.x;
				TempY = TButton.Position.y;
				In = ToolStatic_CheckMouseIn(TempX,
				                             TempY,
				                             TempX + TButton.Size.cx,
				                             TempY + TButton.Size.cy);
			}
			return In;
		}
		//*****************************************************************************
		//	ローカル関数
		//*****************************************************************************
		//ボタン情報の状態推移処理を行う。
		private static void ToolButton_Step(SToolButton TButton, double StepTime) {
			int MouseX, MouseY;
			bool MouseRepeatInput, MouseInput, MouseEdgeInput;
			int TempX, TempY;
			bool In;
			//表示状態が0の場合は何もせず終了。
			if(!ToolButton_GetVisible(TButton)) { return; }	//ここまで
			//マウスカーソルの位置を取得。
			ToolStatic_GetMousePosition(out MouseX, out MouseY);
			//マウスの入力状態を取得。
			MouseRepeatInput = false;
			MouseInput       = (ToolStatic_GetMouseButton()     & (1<<0)/*MOUSE_INPUT_LEFT*/) != 0;
			MouseEdgeInput   = (ToolStatic_GetMouseEdgeButton() & (1<<0)/*MOUSE_INPUT_LEFT*/) != 0;
			//ボタンの表示領域にマウスカーソルがあるかどうかを調べる。
			if(TButton.TWindow != null) {
				ToolWindow_GetDrawLeftUpPos(TButton.TWindow, out TempX, out TempY);
				TempX += TButton.Position.x;
				TempY += TButton.Position.y;
				In = ToolStatic_CheckMouseIn(TempX,
				                             TempY,
				                             TempX + TButton.Size.cx,
				                             TempY + TButton.Size.cy) &&
				     ToolWindow_CheckInfoAreaIn(TButton.TWindow,
				                                MouseX,
				                                MouseY);
			} else {
				In = ToolStatic_CheckMouseIn(TButton.Position.x,
				                             TButton.Position.y,
				                             TButton.Position.x + TButton.Size.cx,
				                             TButton.Position.y + TButton.Size.cy);
			}
			//左ボタンが押されているかどうかで処理を分岐。
			if(MouseInput) {
				//左ボタンが押されている場合はリピート処理を行う。
				TButton.BottomTime += StepTime;
				if(TButton.FirstRepeat) {
					if(TButton.BottomTime >= TOOL_REPEAT_WAIT) {
						MouseRepeatInput     = true;
						TButton.BottomTime  -= TOOL_REPEAT_WAIT;
					}
				} else {
					if(TButton.BottomTime >= TOOL_FIRST_REPEAT_WAIT) {
						MouseRepeatInput     = true;
						TButton.FirstRepeat  = true;
						TButton.BottomTime  -= TOOL_FIRST_REPEAT_WAIT;
					}
				}
				//左ボタンが押された瞬間は必ずリピート入力考慮のボタン押下状態も0以外にする。
				if(MouseEdgeInput) { MouseRepeatInput = true; }
				//ボタン表示領域にカーソルがあり、左ボタンが押された瞬間の場合はボタン押下状態にする。
				if(MouseEdgeInput && In) { TButton.Bottom = true; }
			} else {
				//左ボタンが押されていない場合はリピート処理をリセットする。
				TButton.FirstRepeat = false;
				TButton.BottomTime  = 0.0;
				//マウスカーソルがボタンの表示領域にあり、且つ今までボタンが押下状態だった場合はクリックフラグを立て、ON/OFF状態を反転する。
				if(In && TButton.Bottom) {
					TButton.Click     = true;
					TButton.OnOffFlag = !TButton.OnOffFlag;
				}
				//ボタン押下状態をリセットする。
				TButton.Bottom = false;
			}
			//リピート入力がされていて、且つマウスカーソルがボタンの表示領域にあったらリピート入力考慮のボタン押下状態を0以外にする。
			if(MouseRepeatInput && In) {
				TButton.RepeatBottom = true;
			} else {
				TButton.RepeatBottom = false;
			}
		}
		//-----------------------------------------------------------------------------
		//ボタン情報を画面に描画する。
		private static void ToolButton_Draw(SToolButton TButton) {
			int MouseX, MouseY;
			int ButtonFontHandle;
			int DrawWidth;
			int TempX, TempY;
			bool In;
			int addx, addy;
			int CenterColor;
			int TopLeftC1, TopLeftC2;
			int RightBottomC1, RightBottomC2;
			//表示状態が0の場合は何もせず終了。
			if(!ToolButton_GetVisible(TButton)) { return; }	//ここまで
			//マウスカーソルの位置を取得。
			ToolStatic_GetMousePosition(out MouseX, out MouseY);
			//ボタン名描画用のフォントハンドルを取得。
			ButtonFontHandle = ToolStatic_GetButtonFontHandle();
			//ボタン名の描画幅を取得。
			DrawWidth = ToolFunc_GetDrawStringWidthToHandle(TButton.Name, -1, ButtonFontHandle);
			//ボタンの表示位置とボタンの表示領域にマウスカーソルがあるかどうかを取得。
			if(TButton.TWindow != null) {
				ToolWindow_GetDrawLeftUpPos(TButton.TWindow, out TempX, out TempY);
				TempX += TButton.Position.x;
				TempY += TButton.Position.y;
				In = ToolStatic_CheckMouseIn(TempX,
				                             TempY,
				                             TempX + TButton.Size.cx,
				                             TempY + TButton.Size.cy) &&
				     ToolWindow_CheckInfoAreaIn(TButton.TWindow,
				                                MouseX,
				                                MouseY);
			} else {
				TempX = TButton.Position.x;
				TempY = TButton.Position.y;
				In = ToolStatic_CheckMouseIn(TempX,
				                             TempY,
				                             TempX + TButton.Size.cx,
				                             TempY + TButton.Size.cy);
			}
			//ボタンが押されているか、若しくはON/OFF切り替えモードのON状態の場合は押されているボタンの配色にする。
			if((In && TButton.Bottom) ||
			   (TButton.On_Off_SwitchType && TButton.OnOffFlag)) {
				addx          = 1;
				addy          = 1;
				CenterColor   = (int)ToolFunc_GetColor(192,192,192);
				TopLeftC1     = (int)ToolFunc_GetColor(  0,  0,  0);
				TopLeftC2     = (int)ToolFunc_GetColor( 64, 64, 64);
				RightBottomC1 = (int)ToolFunc_GetColor(255,255,255);
				RightBottomC2 = (int)ToolFunc_GetColor(191,191,191);
			} else {
				addx          = 0;
				addy          = 0;
				CenterColor   = (int)ToolFunc_GetColor(255,255,255);
				RightBottomC1 = (int)ToolFunc_GetColor(  0,  0,  0);
				RightBottomC2 = (int)ToolFunc_GetColor( 64, 64, 64);
				TopLeftC1     = (int)ToolFunc_GetColor(255,255,255);
				TopLeftC2     = (int)ToolFunc_GetColor(191,191,191);
			}
			//ボタン情報にウインドウ情報が関連付けられている場合は描画領域の制限設定を行う。
			if(TButton.TWindow != null) { ToolWindow_SetupDrawArea(TButton.TWindow); }
			//ボタンの描画。
			ToolStatic_DrawButton(TempX,
			                      TempY,
			                      TButton.Size.cx,
			                      TButton.Size.cy,
			                      TopLeftC1,
			                      TopLeftC2,
			                      RightBottomC1,
			                      RightBottomC2,
			                      CenterColor);
			//ボタン名の描画。
			ToolFunc_SetDrawBlendMode(1/*DX_BLENDMODE_ALPHA*/, 180);
			ToolFunc_DrawStringToHandle(TempX + (TButton.Size.cx - DrawWidth       ) / 2 + addx,
			                            TempY + (TButton.Size.cy - TOOL_FONT_HEIGHT) / 2 + addy,
			                            TButton.Name,
			                            ToolFunc_GetColor(0,0,0),
			                            ButtonFontHandle);
			//ブレンドモードと描画可能領域を元に戻す。
			ToolFunc_SetDrawBlendMode(0/*DX_BLENDMODE_NOBLEND*/, 0);
			ToolFunc_SetDrawAreaFull();
		}
	}
}
