//
//	ToolLib_ParamBar.c
//
//	エディター共通処理 - ツールのGUIのパラメーターバー
//
//	* Tue Apr 18 21:46:46 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//	* Wed Apr 19 22:11:14 JST 2017 Naoyuki Sawa
//	- 「①DxLibに依存しないようにする」と「②C言語でコンパイル出来るようにする」を対応しました。
//	  詳細は、/clip/ToolLib/README.TXT の、同日のコメントを参照して下さい。
//	* Thu Apr 20 21:31:57 JST 2017 Naoyuki Sawa
//	- 当ライブラリが生成するオブジェクトの識別子を、整数ハンドル⇒ポインタに変更しました。
//	  オリジナル版では生成したオブジェクトを固定長配列に格納して管理していたのですが、メモリ節約のためにリストで管理するように変更し、そのためには整数ハンドルよりもポインタの方が都合が良いからです。
//	  尚、フォントハンドルと文字列入力ハンドルは、当ライブラリが生成するオブジェクトではなくバックエンドのオブジェクトなので、今回の変更には関係無く整数ハンドルのままです。
//	* Tue May 02 22:54:46 JST 2017 Naoyuki Sawa
//	- 各モジュール内のサイズ定義の倍率を一律で調整出来るように、ToolLib.hにTOOL_SCALEの定義を追加しました。
//	  詳細は、ToolLib.hの同日のコメントを参照して下さい。
//	* Sun May 14 23:23:22 JST 2017 Naoyuki Sawa
//	- ToolParamBar_IsAnyHovered(),ToolParamBar_IsHovered()関数を追加しました。
//	  詳細は、ToolLib.hの同日のコメントを参照して下さい。
//
#include "clip.h"
#ifdef  TOOLLIB_USE_STRINGINPUT
//*****************************************************************************
//	定数、マクロ、構造体
//*****************************************************************************
#define TOOL_BAR_CURSOR_HEIGHT		(TOOL_SCALE*(12))	//バーのつまみの高さ。
#define TOOL_BAR_CURSOR_HALF_WIDTH	(TOOL_SCALE*(3))	//バーのつまみの幅の半分。
#define TOOL_BAR_Y			(TOOL_SCALE*(5))	//バーのY座標。
//-----------------------------------------------------------------------------
//パラメータバー構造体
/*typedef*/ struct _SToolParamBar {
	SToolVisible*		TVisible;		//関連付けられている表示状態情報。
	SToolWindow*		TWindow;		//関連付けられているウインドウ情報。
	SToolStringInput*	NumberTStringInput;	//数値直接編集用の文字列入力情報。
	char*			Name;			//名前の文字列が格納されているメモリアドレスを保存しているポインタ。
	int			PositionX, PositionY;	//パラメータバーの表示位置。
	int			BarPositionX;		//バーを表示する相対X座標。
	int			BarWidth;		//バーの横幅。
	double			ParamMin, ParamMax;	//バーで操作できる範囲の値の最小値と最大値。
	double			Param;			//現在の数値。
	int			Change;			//数値に変化があったかどうか。
	int			Grips;			//バーのつまみを掴んでいるかどうか。
	int			GripsX;			//バーのつまみを掴んだときのバー左端からみたX座標。
} /*SToolParamBar*/;
//*****************************************************************************
//	ローカル変数
//*****************************************************************************
static GSList*	g_TParamBar;
//*****************************************************************************
//	ローカル関数宣言
//*****************************************************************************
static void ToolParamBar_Step(SToolParamBar* TParamBar, double StepTime);
static void ToolParamBar_Draw(SToolParamBar* TParamBar);
//*****************************************************************************
//	アプリケーション用関数
//*****************************************************************************
//パラメータバー情報を作成する。
//[in]
//	Name			名前の文字列が格納されたメモリアドレス。
//	PositionX,PositionY	表示座標。
//	BarPositionX		バーを表示する相対X座標。
//	BarWidth		バーの横幅。
//	NumberLength		表示する数値の桁数。
//	ParamMin,ParamMax	バーで操作できる範囲の値の最小値と最大値。
//	InitParam		初期値。
//[out]
//	戻り値			パラメータバー情報。
SToolParamBar* ToolParamBar_Create(const char* Name, int PositionX, int PositionY, int BarPositionX, int BarWidth, int NumberLength, double ParamMin, double ParamMax, double InitParam) {
	SToolParamBar* TParamBar;
	//新しいボタン情報を格納するためのメモリの確保。
	TParamBar = calloc(1, sizeof(SToolParamBar));
	if(!TParamBar) { DIE(); }
	//確保したメモリ領域を保存。
	g_TParamBar = g_slist_append(g_TParamBar, TParamBar);
	//情報を初期化。
//不要	TParamBar->TVisible     = NULL;
//不要	TParamBar->TWindow      = NULL;
	TParamBar->PositionX    = PositionX;
	TParamBar->PositionY    = PositionY;
	TParamBar->BarPositionX = BarPositionX;
	TParamBar->BarWidth     = BarWidth;
	TParamBar->ParamMin     = ParamMin;
	TParamBar->ParamMax     = ParamMax;
	TParamBar->Param        = InitParam;
//不要	TParamBar->Change       = 0;
//不要	TParamBar->Grips        = 0;
	if(Name) {
		TParamBar->Name = strdup(Name);
		if(!TParamBar->Name) { DIE(); }
	}
	//数値編集用の文字列入力情報を作成する。
	TParamBar->NumberTStringInput = ToolStringInput_Create(NULL,
	                                                       PositionX + BarPositionX + BarWidth + 8,
	                                                       PositionY,
	                                                       1,
	                                                       NumberLength,
	                                                       0);
	//初期値を設定。
	ToolStringInput_SetFloatNumber(TParamBar->NumberTStringInput, InitParam);
	//パラメータバー情報を返す。
	return TParamBar;
}
//-----------------------------------------------------------------------------
//パラメータバー情報を削除する。
//[in]
//	TParamBar		パラメータバー情報。
void ToolParamBar_Delete(SToolParamBar* TParamBar) {
	//名前保存用にメモリを確保していた場合は解放。
	free(TParamBar->Name);
	//数値編集用の文字列入力情報を削除する。
	ToolStringInput_Delete(TParamBar->NumberTStringInput);
	//確保していたメモリを解放する。
	g_TParamBar = g_slist_remove(g_TParamBar, TParamBar);
	free(TParamBar);
}
//-----------------------------------------------------------------------------
//全てのパラメータバー情報を削除する。
void ToolParamBar_Delete_All() {
	//有効な全てのパラメータバーを削除する。
	while(g_TParamBar) { ToolParamBar_Delete(g_TParamBar->data); }
}
//-----------------------------------------------------------------------------
//パラメータバー情報に関連付ける表示状態情報をセットする。
//[in]
//	TParamBar		パラメータバー情報。
//	TVisible		表示状態情報。
void ToolParamBar_SetVisibleHandle(SToolParamBar* TParamBar, SToolVisible* TVisible) {
	//表示状態情報を保存。
	TParamBar->TVisible = TVisible;
	//数値編集用の文字列入力情報にも設定する。
	ToolStringInput_SetVisibleHandle(TParamBar->NumberTStringInput, TVisible);
}
//-----------------------------------------------------------------------------
//パラメータバー情報の表示状態を変更する。
//[in]
//	TParamBar		パラメータバー情報。
//	Visible			新しい表示状態。
void ToolParamBar_SetVisible(SToolParamBar* TParamBar, int Visible) {
	//数値編集用の文字列入力情報に対して表状態設定を行う。
	ToolStringInput_SetVisible(TParamBar->NumberTStringInput, Visible);
}
//-----------------------------------------------------------------------------
//パラメータバー情報の表示状態を取得する。
//[in]
//	TParamBar		パラメータバー情報。
//[out]
//	戻り値			表示状態。(0以外:表示,0:非表示)
int ToolParamBar_GetVisible(SToolParamBar* TParamBar) {
	//数値編集用の文字列入力情報が非表示状態だったら0を返す。
	if(!ToolStringInput_GetVisible(TParamBar->NumberTStringInput)) { return 0; }
	//関連付けられているウインドウ情報の表示状態が0の場合は0を返す。
	if(!ToolWindow_GetVisible(TParamBar->TWindow)) { return 0; }
	//表示状態情報が登録されていて、且つ表示状態情報の表示状態が0の場合は0を返す。
	if(!ToolVisible_GetVisible(TParamBar->TVisible)) { return 0; }
	//ここにきていたら非表示ではないということなので0以外を返す。
	return 1;
}
//-----------------------------------------------------------------------------
//パラメータバー情報と関連付けるウインドウ情報を設定する。
//[in]
//	TParamBar		パラメータバー情報。
//	TWindow			ウインドウ情報。
void ToolParamBar_SetWindow(SToolParamBar* TParamBar, SToolWindow* TWindow) {
	//ウインドウ情報を保存。
	TParamBar->TWindow = TWindow;
	//数値編集用の文字列入力情報にもウインドウ情報をセット。
	ToolStringInput_SetWindow(TParamBar->NumberTStringInput, TParamBar->TWindow);
}
//-----------------------------------------------------------------------------
//パラメータバー情報の座標を変更する。
//[in]
//	TParamBar		パラメータバー情報。
//	PositionX,PositionY	変更後の座標。
void ToolParamBar_SetPosition(SToolParamBar* TParamBar, int PositionX, int PositionY) {
	//座標を保存。
	TParamBar->PositionX = PositionX;
	TParamBar->PositionY = PositionY;
	//数値編集用の文字列入力情報の座標も変更。
	ToolStringInput_SetPosition(TParamBar->NumberTStringInput,
	                            TParamBar->PositionX + TParamBar->BarPositionX + TParamBar->BarWidth + 8,
	                            TParamBar->PositionY);
}
//-----------------------------------------------------------------------------
//パラメータバー情報の数値を変更する。
//[in]
//	TParamBar		パラメータバー情報。
//	Param			変更後の数値。
void ToolParamBar_SetParam(SToolParamBar* TParamBar, double Param) {
	//パラメータを保存。
	TParamBar->Param = Param;
	//数値編集用の文字列入力情報にも数値をセット。
	ToolStringInput_SetFloatNumber(TParamBar->NumberTStringInput, Param);
}
//-----------------------------------------------------------------------------
//パラメータバー情報のバーで変更できる数値の最大値と最小値を変更する。
//[in]
//	TParamBar		パラメータバー情報。
//	ParamMin,ParamMax	新しい最小値と最大値。
void ToolParamBar_SetMinMax(SToolParamBar* TParamBar, double ParamMin, double ParamMax) {
	TParamBar->ParamMin = ParamMin;
	TParamBar->ParamMax = ParamMax;
}
//-----------------------------------------------------------------------------
//パラメータバー情報の数値編集が行われていた場合に無条件で終了させる。
//[in]
//	TParamBar		パラメータバー情報。
void ToolParamBar_AlwaysEnd(SToolParamBar* TParamBar) {
	//数値編集用の文字列入力情報に対して無条件終了の処理を行う。
	ToolStringInput_AlwaysEnd(TParamBar->NumberTStringInput);
}
//-----------------------------------------------------------------------------
//パラメータバー情報の数値に変化があったかどうかを取得する。
//[in]
//	TParamBar		パラメータバー情報。
//[out]
//	戻り値			数値に変化があったかどうか。(0以外:変化あり,0:変化なし)
int ToolParamBar_CheckChange(SToolParamBar* TParamBar) {
	//数値に変化があったかどうかのフラグをローカル変数にコピーしておく。
	int Result = TParamBar->Change;
	//数値に変化があったかどうかのフラグを倒す。
	TParamBar->Change = 0;
	//コピーしておいた変数の内容を返す。
	return Result;
}
//-----------------------------------------------------------------------------
//パラメータバー情報の現在の数値を取得する。
//[in]
//	TParamBar		パラメータバー情報。
//[out]
//	戻り値			パラメータバーの値。
double ToolParamBar_GetParam(SToolParamBar* TParamBar) {
	return TParamBar->Param;
}
//-----------------------------------------------------------------------------
//全てのパラメータバー情報の状態推移処理を行う。
//[in]
//	StepTime		進める時間。(単位:秒)
void ToolParamBar_Step_All(double StepTime) {
	GSList* list = g_TParamBar;
	while(list) {
		ToolParamBar_Step(list->data, StepTime);
		list = list->next;
	}
}
//-----------------------------------------------------------------------------
//全てのパラメータバー情報の描画移処理を行う。
void ToolParamBar_Draw_All() {
	GSList* list = g_TParamBar;
	while(list) {
		ToolParamBar_Draw(list->data);
		list = list->next;
	}
}
//-----------------------------------------------------------------------------
//マウスカーソルがいずれかのパラメータバーの内にあるかどうかをチェックする。
//[out]
//	戻り値			いずれかのパラメータバーの内にマウスカーソルがあるかどうか。(0以外:内にある,0:外にある)
int ToolParamBar_IsAnyHovered() {
	GSList* list = g_TParamBar;
	while(list) {
		if(ToolParamBar_IsHovered(list->data)) { return 1; }
		list = list->next;
	}
	return 0;
}
//-----------------------------------------------------------------------------
//マウスカーソルがパラメータバーの内にあるかどうかをチェックする。
//[in]
//	TParamBar		パラメータバー情報。
//[out]
//	戻り値			パラメータバーの内にマウスカーソルがあるかどうか。(0以外:内にある,0:外にある)
int ToolParamBar_IsHovered(SToolParamBar* TParamBar) {
	//※TODO:未実装
	return 0;
}
//*****************************************************************************
//	ローカル関数
//*****************************************************************************
//パラメータバー情報の状態推移処理を行う。
//[in]
//	TParamBar		パラメータバー情報。
//	StepTime		進める時間。(単位:秒)
static void ToolParamBar_Step(SToolParamBar* TParamBar, double StepTime) {
	int MouseX, MouseY;
	double TempF;
	int WinDrawX, WinDrawY;
	int In;
	int AreaX, AreaY;
	int CursorX;
	//非表示状態だった場合は何もせず終了。
	if(!ToolParamBar_GetVisible(TParamBar)) { return; }	//ここまで
	//マウスカーソルの位置を取得。
	ToolStatic_GetMousePosition(&MouseX, &MouseY);
	//数値編集用文字列入力情報に変化があった場合はバーにも反映する。
	if(ToolStringInput_CheckEnd(TParamBar->NumberTStringInput, 1)) {
		//数値に変化があったかどうかのフラグを立てる。
		TParamBar->Change = 1;
		//数値編集用文字列入力情報の現在の数値を取得する。
		TempF = ToolStringInput_GetFloatNumber(TParamBar->NumberTStringInput);
		//数値が最小値や最大値の範囲からはみ出ていたら補正する。
		if(TempF < TParamBar->ParamMin) { TempF = TParamBar->ParamMin; }
		if(TempF > TParamBar->ParamMax) { TempF = TParamBar->ParamMax; }
		//数値を設定する関数で値を反映。
		ToolParamBar_SetParam(TParamBar, TempF);
	}
	//マウスの左ボタンが押されていなかったらバーのつまみを掴んでいるかどうかのフラグを倒して終了。
	if(!(ToolStatic_GetMouseButton() & (1<<0)/*MOUSE_INPUT_LEFT*/)) {
		TParamBar->Grips = 0;
		return;	//ここまで
	}
	//バーのつまみを掴んでいない場合はマウスの左ボタンを押した瞬間ではない場合はここで終了。
	if(!TParamBar->Grips &&
	   !(ToolStatic_GetMouseEdgeButton() & (1<<0)/*MOUSE_INPUT_LEFT*/)) { return; }	//ここまで
	//ウインドウ情報に関連付けられている場合はウインドウ情報の座標やウインドウ内にマウスカーソルがあるかどうかなどを取得する。
	if(TParamBar->TWindow) {
		ToolWindow_GetDrawLeftUpPos(TParamBar->TWindow, &WinDrawX, &WinDrawY);
		In = ToolWindow_CheckInfoAreaIn(TParamBar->TWindow, MouseX, MouseY);
	} else {
		WinDrawX = 0;
		WinDrawY = 0;
		In       = 1;
	}
	//バー表示領域の左上座標を算出。
	AreaX = TParamBar->PositionX + WinDrawX + TParamBar->BarPositionX;
	AreaY = TParamBar->PositionY + WinDrawY;
	//つまみの位置を算出。
	CursorX = TParamBar->BarWidth * (TParamBar->Param    - TParamBar->ParamMin)
	                              / (TParamBar->ParamMax - TParamBar->ParamMin);
	//つまみを掴んでいるかどうかで処理を分岐。
	if(!TParamBar->Grips) {
		//つまみを掴んでいない場合はバーの表示領域にカーソルが無い場合は終了。
		if(!In) { return; }	//ここまで
		//バーの表示領域からずれていたら終了。
		if((MouseX < (AreaX - TOOL_BAR_CURSOR_HALF_WIDTH)) ||
		   (MouseX > (AreaX + TOOL_BAR_CURSOR_HALF_WIDTH + TParamBar->BarWidth)) ||
		   (MouseY <  AreaY) ||
		   (MouseY > (AreaY + TOOL_BAR_CURSOR_HEIGHT))) { return; }	//ここまで
		//つまみの外側をクリックした場合はつまみの位置をクリックした位置に移動する。
		if((MouseX <  (CursorX + AreaX - TOOL_BAR_CURSOR_HALF_WIDTH)) ||
		   (MouseX >= (CursorX + AreaX + TOOL_BAR_CURSOR_HALF_WIDTH))) {
			CursorX           = MouseX - AreaX;
			TParamBar->GripsX = 0;
		} else {
			TParamBar->GripsX = MouseX - (AreaX + CursorX);
		}
		//つまみを掴んでいるかどうかのフラグを立てる。
		TParamBar->Grips = 1;
	} else {
		//つまみを掴んでいる場合は掴み始めたマウスカーソル位置と現在のマウスカーソル位置から現在のつまみの位置を決定する。
		if(       (MouseX - TParamBar->GripsX) < (AreaX                       - TOOL_BAR_CURSOR_HALF_WIDTH)) {
			CursorX = 0;
		} else if((MouseX - TParamBar->GripsX) > (AreaX + TParamBar->BarWidth + TOOL_BAR_CURSOR_HALF_WIDTH)) {
			CursorX = TParamBar->BarWidth;
		} else {
			CursorX = MouseX - TParamBar->GripsX - AreaX;
			if(CursorX <                   0) { CursorX =                   0; }
			if(CursorX > TParamBar->BarWidth) { CursorX = TParamBar->BarWidth; }
		}
	}
	//つまみの位置に応じてパラメータを算出する。
	TempF = CursorX * (TParamBar->ParamMax - TParamBar->ParamMin) / TParamBar->BarWidth + TParamBar->ParamMin;
	//値が変化していたら値が変化したかどうかのフラグを立て、数値編集用の文字列入力情報にも反映する。
	if(TempF != TParamBar->Param) {
		TParamBar->Change = 1;
		TParamBar->Param  = TempF;
		ToolStringInput_SetFloatNumber(TParamBar->NumberTStringInput, TParamBar->Param);
	}
}
//-----------------------------------------------------------------------------
//パラメータバー情報を画面に描画する。
//[in]
//	TParamBar		パラメータバー情報。
static void ToolParamBar_Draw(SToolParamBar* TParamBar) {
	int CursorX;
	int WinDrawX, WinDrawY;
	//非表示設定になっていたら何もせずに終了。
	if(!ToolParamBar_GetVisible(TParamBar)) { return; }	//ここまで
	//ウインドウ情報に関連付けられている場合はウインドウ情報の座標を取得する。
	if(TParamBar->TWindow) {
		ToolWindow_GetDrawLeftUpPos(TParamBar->TWindow, &WinDrawX, &WinDrawY);
		//ウインドウ情報を基にした描画範囲制限設定を行う。
		ToolWindow_SetupDrawArea(TParamBar->TWindow);
	} else {
		WinDrawX = 0;
		WinDrawY = 0;
	}
	//名前がある場合は名前を描画する。
	if(TParamBar->Name) {
		ToolFunc_DrawStringToHandle(TParamBar->PositionX + WinDrawX,
		                            TParamBar->PositionY + WinDrawY,
		                            TParamBar->Name,
		                            ToolFunc_GetColor(255,255,255),
		                            ToolStatic_GetNormalFontHandle());
	}
	//バーのつまみの位置を算出。
	CursorX = TParamBar->BarWidth * (TParamBar->Param    - TParamBar->ParamMin)
	                              / (TParamBar->ParamMax - TParamBar->ParamMin);
	//バーを描画。
	ToolFunc_SetDrawBlendMode(1/*DX_BLENDMODE_ALPHA*/, 200);
	ToolFunc_DrawBox(TParamBar->PositionX + WinDrawX + TParamBar->BarPositionX,
	                 TParamBar->PositionY + WinDrawY + TOOL_BAR_Y,
	                 TParamBar->PositionX + WinDrawX + TParamBar->BarPositionX + TParamBar->BarWidth,
	                 TParamBar->PositionY + WinDrawY + TOOL_BAR_Y + 1,
	                 ToolFunc_GetColor(255,255,255),
	                 1);
	//バーのつまみを描画。
	ToolFunc_DrawBox(TParamBar->PositionX + WinDrawX + TParamBar->BarPositionX + CursorX - TOOL_BAR_CURSOR_HALF_WIDTH,
	                 TParamBar->PositionY + WinDrawY,
	                 TParamBar->PositionX + WinDrawX + TParamBar->BarPositionX + CursorX + TOOL_BAR_CURSOR_HALF_WIDTH,
	                 TParamBar->PositionY + WinDrawY + TOOL_BAR_CURSOR_HEIGHT,
	                 ToolFunc_GetColor(255,255,255),
	                 1);
	//描画設定を元に戻す。
	ToolFunc_SetDrawBlendMode(0/*DX_BLENDMODE_NOBLEND*/, 0);
	ToolFunc_SetDrawAreaFull();
}
#endif//TOOLLIB_USE_STRINGINPUT
