//
//	ToolLib_List.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
//	- ToolList_IsAnyHovered(),ToolList_IsHovered()関数を追加しました。
//	  詳細は、ToolLib.hの同日のコメントを参照して下さい。
//
using System;
using System.Collections.Generic;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	定数、マクロ、構造体
		//*****************************************************************************
		private const int TOOL_ONE_LINE_HEIGHT	= (TOOL_SCALE*(16));	//リスト1行辺りの縦幅。
		//-----------------------------------------------------------------------------
		//リスト構造体
		public class SToolList {
			public SToolVisible	TVisible;	//関連付けられている表示状態情報。
			public SToolWindow	TWindow;	//関連付けられているウインドウ情報。
			public List<string>	ObjList;	//追加されている行の文字列のアドレスが格納されているポインタ配列。(strv形式)
			public int		Width;		//追加されている文字列の中で最大の横幅。
			public int		SelectIndex;	//選択されている行。
			public bool		Change;		//リストの状態に変化があったかどうか。
			public bool		Visible;	//表示状態。
		}
		//*****************************************************************************
		//	ローカル変数
		//*****************************************************************************
		private static GSList	g_TList;
		//*****************************************************************************
		//	アプリケーション用関数
		//*****************************************************************************
		//リスト情報を作成する。
		public static SToolList ToolList_Create() {
			SToolList TList;
			//新しいリスト情報を格納するためのメモリの確保。
			TList = new SToolList();
			//確保したメモリ領域を保存。
			g_TList = g_slist_append(g_TList, TList);
			//情報を初期化。
		//不要	TList.TVisible    = null;
		//不要	TList.TWindow     = null;
			TList.ObjList     = new List<string>();
		//不要	TList.Width       = 0;
			TList.SelectIndex = -1;
		//不要	TList.Change      = false;
			TList.Visible     = true;
			//リスト情報を返す。
			return TList;
		}
		//-----------------------------------------------------------------------------
		//リスト情報を削除する。
		public static void ToolList_Delete(SToolList TList) {
			//行情報用に確保していたメモリを解放。
			/** no job **/
			//確保していたメモリを解放する。
			g_TList = g_slist_remove(g_TList, TList);
		}
		//-----------------------------------------------------------------------------
		//全てのリスト情報を削除する。
		public static void ToolList_Delete_All() {
			//有効な全てのリストを削除する。
			while(g_TList != null) { ToolList_Delete((SToolList)g_TList.data); }
		}
		//-----------------------------------------------------------------------------
		//リスト情報に関連付ける表示状態情報をセットする。
		public static void ToolList_SetVisibleHandle(SToolList TList, SToolVisible TVisible) {
			TList.TVisible = TVisible;
		}
		//-----------------------------------------------------------------------------
		//リスト情報を初期化する。
		public static void ToolList_Initialize(SToolList TList, SToolWindow TWindow) {
			//行情報用に確保していたメモリを解放。
			/** no job **/
			//情報を初期化する。
			TList.TWindow     = TWindow;
			TList.ObjList     = new List<string>();
			TList.Width       = 0;
			TList.SelectIndex = -1;
			TList.Change      = false;
			//ウインドウのクライアント領域を初期化。
			ToolWindow_SetClientSize(TList.TWindow, 16, 16);
		}
		//-----------------------------------------------------------------------------
		//リスト情報の選択されている行の変更などが発生したかどうかを取得する。
		public static bool ToolList_GetChange(SToolList TList, bool Reset) {
			bool Result = TList.Change;
			if(Reset) { TList.Change = false; }
			return Result;
		}
		//-----------------------------------------------------------------------------
		//リスト情報に行情報を追加する。
		public static void ToolList_AddObj(SToolList TList, string String, params object[] VaList) {
			string FixString;
			int DrawWidth;
			//可変個引数から追加する文字列を構築する。
			FixString = string.Format(String, VaList);
			//追加する行の文字列の横幅を取得する。
			DrawWidth = ToolFunc_GetDrawStringWidthToHandle(FixString, -1, ToolStatic_GetNormalFontHandle());
			//今までの最大横幅より大きい場合は最大横幅を更新。
			if(DrawWidth > TList.Width) { TList.Width = DrawWidth; }
			//新しい行の情報を保存。
			TList.ObjList.Add(FixString);
			//ウインドウのクライアント領域を更新。
			ToolWindow_SetClientSize(TList.TWindow, TList.Width, ToolList_GetHeight(TList));
			//一つ目の行だった場合は、追加した行を選択状態にする。
			if(ToolList_GetObjNum(TList) == 1) { ToolList_SetSelectIndex(TList, 0); }
		}
		//-----------------------------------------------------------------------------
		//リスト情報の表示状態を変更する。
		public static void ToolList_SetVisible(SToolList TList, bool Visible) {
			//新しい表示状態を保存する。
			TList.Visible = Visible;
		}
		//-----------------------------------------------------------------------------
		//リスト情報の表示状態を取得する。
		public static bool ToolList_GetVisible(SToolList TList) {
			//表示状態が0の場合は0を返す。
			if(!TList.Visible) { return false; }
			//関連付けられているウインドウ情報の表示状態が0の場合は0を返す。
			if(!ToolWindow_GetVisible(TList.TWindow)) { return false; }
			//表示状態情報が登録されていて、且つ表示状態情報の表示状態が0の場合は0を返す。
			if(!ToolVisible_GetVisible(TList.TVisible)) { return false; }
			//ここにきていたら非表示ではないということなので0以外を返す。
			return true;
		}
		//-----------------------------------------------------------------------------
		//リスト情報の選択行を変更する。
		public static void ToolList_SetSelectIndex(SToolList TList, int Index) {
			TList.SelectIndex = Index;
		}
		//-----------------------------------------------------------------------------
		//リスト情報の選択している行を取得する。
		public static int ToolList_GetSelectIndex(SToolList TList) {
			return TList.SelectIndex;
		}
		//-----------------------------------------------------------------------------
		//リスト情報に追加した行の数を取得する。
		public static int ToolList_GetObjNum(SToolList TList) {
			return TList.ObjList.Count;
		}
		//-----------------------------------------------------------------------------
		//リスト情報に追加した全ての行をあわせた縦幅を取得する。
		public static int ToolList_GetHeight(SToolList TList) {
			return TOOL_ONE_LINE_HEIGHT * ToolList_GetObjNum(TList);
		}
		//-----------------------------------------------------------------------------
		//リスト情報に追加した全ての行をあわせた横幅を取得する。
		public static int ToolList_GetWidth(SToolList TList) {
			return TList.Width;
		}
		//-----------------------------------------------------------------------------
		//全てのリスト情報の状態推移処理を行う。
		public static void ToolList_Step_All(double StepTime) {
			GSList list = g_TList;
			while(list != null) {
				ToolList_Step((SToolList)list.data, StepTime);
				list = list.next;
			}
		}
		//-----------------------------------------------------------------------------
		//全てのリスト情報の描画移処理を行う。
		public static void ToolList_Draw_All() {
			GSList list = g_TList;
			while(list != null) {
				ToolList_Draw((SToolList)list.data);
				list = list.next;
			}
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルがいずれかのリストの内にあるかどうかをチェックする。
		public static bool ToolList_IsAnyHovered() {
			GSList list = g_TList;
			while(list != null) {
				if(ToolList_IsHovered((SToolList)list.data)) { return true; }
				list = list.next;
			}
			return false;
		}
		//-----------------------------------------------------------------------------
		//マウスカーソルがリストの内にあるかどうかをチェックする。
		public static bool ToolList_IsHovered(SToolList TList) {
			int MouseX, MouseY;
			//表示状態が0の場合は何もせず終了。
			if(!ToolList_GetVisible(TList)) { return false; }	//ここまで
			//リストはウインドウの情報表示領域全体を占めるように描画するので、情報表示領域に対するチェックと同じです。
			ToolStatic_GetMousePosition(out MouseX, out MouseY);
			return ToolWindow_CheckInfoAreaIn(TList.TWindow,
			                                  MouseX,
			                                  MouseY);
		}
		//*****************************************************************************
		//	ローカル関数
		//*****************************************************************************
		//リスト情報の状態推移処理を行う。
		private static void ToolList_Step(SToolList TList, double StepTime) {
			int MouseX, MouseY;
			RECT InfoArea;
			int DrawX, DrawY;
			int MouseOffsetX, MouseOffsetY;
			int Index;
			//表示状態が0の場合は何もせず終了。
			if(!ToolList_GetVisible(TList)) { return; }	//ここまで
			//マウスの左ボタンが押された瞬間ではない場合は特に何もしない。
			if((ToolStatic_GetMouseEdgeButton() & (1<<0)/*MOUSE_INPUT_LEFT*/) == 0) { return; }	//ここまで
			//マウスカーソルの位置を取得。
			ToolStatic_GetMousePosition(out MouseX, out MouseY);
			//関連付けされているウインドウ情報の情報表示領域を取得。
			InfoArea = ToolWindow_GetInfoArea(TList.TWindow);
			//関連付けされているウインドウ情報のスクロールバーの状態も考慮したクライアント領域の描画原点となるスクリーン座標を取得する。
			ToolWindow_GetDrawLeftUpPos(TList.TWindow, out DrawX, out DrawY);
			//リスト情報上でのマウスの位置を算出。
			MouseOffsetX = MouseX - DrawX;
			MouseOffsetY = MouseY - DrawY;
			//マウスのボタンを押した瞬間がリストの領域から外れていたら何もせず終了。
			if((MouseX < InfoArea.left) || (MouseX >= InfoArea.right ) ||
			   (MouseY < InfoArea.top ) || (MouseY >= InfoArea.bottom) ||
			   ( MouseOffsetY                         <  0) ||
			   ((MouseOffsetY / TOOL_ONE_LINE_HEIGHT) >= ToolList_GetObjNum(TList))) { return; }	//ここまで
			//マウスカーソルの位置に該当する行を算出。
			Index = MouseOffsetY / TOOL_ONE_LINE_HEIGHT;
			//マウスカーソルの位置にある行の文字列部分にカーソルがなかったら何もせずに終了。
			if((MouseOffsetX <  0) ||
			    MouseOffsetX >= ToolFunc_GetDrawStringWidthToHandle(TList.ObjList[Index], -1, ToolStatic_GetNormalFontHandle())) { return; }	//ここまで
			//選択している行の変更。
			ToolList_SetSelectIndex(TList, Index);
			//状態に変化があったかどうかのフラグを立てる。
			TList.Change = true;
		}
		//-----------------------------------------------------------------------------
		//リスト情報を画面に描画する。
		private static void ToolList_Draw(SToolList TList) {
			int WinDrawX, WinDrawY;
			int ClientX, ClientY;
			RECT InfoArea;
			int NormalColor, SelectColor;
			int NormalFontHandle;
			int i, n;
			//表示状態が0の場合は何もせず終了。
			if(!ToolList_GetVisible(TList)) { return; }	//ここまで
			//ウインドウ情報のスクロールバーの状態も考慮したクライアント領域の描画原点となるスクリーン座標を取得する。
			ToolWindow_GetDrawLeftUpPos(TList.TWindow, out WinDrawX, out WinDrawY);
			//ウインドウ情報のスクロールバーの状態も考慮したクライアント領域の描画原点となる座標を取得する。
			ToolWindow_GetClientArea(TList.TWindow, out ClientX, out ClientY);
			//ウインドウ情報を元に SetDrawArea で描画領域を制限する設定を行う。
			ToolWindow_SetupDrawArea(TList.TWindow);
			//ウインドウ情報の情報表示領域を取得する。
			InfoArea = ToolWindow_GetInfoArea(TList.TWindow);
			//通常の文字列の描画色と選択されている文字列の描画色を取得する。
			NormalColor = (int)ToolFunc_GetColor(255,255,255);
			SelectColor = (int)ToolFunc_GetColor(255,  0,  0);
			//文字列描画用のフォントハンドルを取得。
			NormalFontHandle = ToolStatic_GetNormalFontHandle();
			//行の描画ループ。
			n = ToolList_GetObjNum(TList);
			for(i = ClientY / TOOL_ONE_LINE_HEIGHT; i < n; i++) {
				//描画位置が情報表示領域から外れていたらループを抜ける。
				if((i * TOOL_ONE_LINE_HEIGHT + WinDrawY) > InfoArea.bottom) { break; }
				//行の文字列を描画。
				ToolFunc_DrawStringToHandle(WinDrawX,
				                            WinDrawY + i * TOOL_ONE_LINE_HEIGHT,
				                            TList.ObjList[i],
				                    (uint)((TList.SelectIndex == i) ? SelectColor : NormalColor),
				                            NormalFontHandle);
			}
			//描画可能範囲を元に戻す。
			ToolFunc_SetDrawAreaFull();
		}
	}
}
