// MainNavigator.cpp :
// メインウインドウのナビゲータ

#include "stdafx.h"
#include "RNSF7.h"
#include "MainWindow.h" 
#include "MainNavigator.h"
#include "MainStatusBar.h"
#include "OpenSetting.h"
#include "symbol.h"
#include "commfunc.h"

bool StartNavigator = 0;
HFONT ui_font = NULL, bold_font = NULL, uline_font = NULL;
static char *item, *info, *rsc_fname, *author, *url, *category, *bitmap, *wavsound;
static int  MLVNavColor = 2; // グラデーションカラー（デフォルト：緑）
static int  MLVNavItemY = 10;	 // アイテム名の表示されるY座標
static int  MLVNavInfoY = 80;	 // 情報の表示されるY座標
static int  MLVNavBitmapY = 130; // 絵の表示されるY座標
static int  MLVNavLinkY = 130;	 // クリッカブルテキストのY座標
static bool flag_from_on = 0;

typedef struct {
	char *navlink;			// クリッカブルテキストのデフォルト文字列
	char *ClickableNavi_s;	// クリッカブルテキストの可変文字列
	int   ClickableNavi_y;  // クリッカブルテキストの左上Y座標
	int   ClickableNavi_x;  // クリッカブルテキストの左上X座標
	int   ClickableNavi_h;  // クリッカブルテキストの高さ
	int   ClickableNavi_r;	// クリッカブルテキストの右下X座標
	int   ClickableNavi_m;	// hWndへWM_COMMANDで飛ばすパラメタ
} NAVCT, *PNAVCT;

#define NUM_NAVCT	3
static NAVCT navct[NUM_NAVCT];

void OpenNavigator(HWND hWnd, HWND hCategoryTreeView, HWND hMainListView, HWND hStatusBar)
{
	// ナビゲータの表示
	if ( bNavigator ) {
		HDC hdc = GetDC( hWnd );
		if ( hdc ) {
			flag_from_on = 1;
			ShowNavigator(hWnd, hdc, hCategoryTreeView, hMainListView, hStatusBar);
			flag_from_on = 0;
			ReleaseDC(hWnd, hdc);
		}
	}
}

void callback_nav( void )
{
	setVariable_d( "NAVIGATOR_ITEM$", item );
	setVariable_d( "NAVIGATOR_INFORMATION$", info );
	setVariable_d( "NAVIGATOR_RSCFILE$", rsc_fname );
	setVariable_d( "NAVIGATOR_AUTHOR$", author );
	setVariable_d( "NAVIGATOR_URL$", url );
	setVariable_d( "NAVIGATOR_CATEGORY$", category );
	setVariable_d( "NAVIGATOR_BITMAP$", bitmap );
	setVariable_d( "NAVIGATOR_SOUND$", wavsound );

	setVariable_d( "NAVIGATOR_LINK_1$", navct[0].navlink );
	setVariable_d( "NAVIGATOR_LINK_2$", navct[1].navlink );
	setVariable_d( "NAVIGATOR_LINK_3$", navct[2].navlink );

	setVariable( "NAVIGATOR_COLOR", MLVNavColor );
	setVariable( "NAVIGATOR_ITEM_Y", MLVNavItemY );
	setVariable( "NAVIGATOR_INFO_Y", MLVNavInfoY );
	setVariable( "NAVIGATOR_BITMAP_Y", MLVNavBitmapY );
	setVariable( "NAVIGATOR_LINK_Y", MLVNavLinkY );
}

void ShowNavigator(HWND hWnd, HDC hdc, HWND hCategoryTreeView, HWND hMainListView, HWND hStatusBar)
{
	int gx, gy, gw, gh, i, n, curSel;
	HPEN    hPen;
	HGDIOBJ OldPen, OldBrush;
	RECT    rt, rt2;
	static int last_gx = -2, last_gy = -2, last_gw = -2, last_gh = -2, lastSel = -2;
	static char *sitem, *sinfo, *sbitmap, *swavsound;
	bool    bDefNav = true;	// デフォルトのナビゲータか？

	if ( hdc && StartNavigator && bNavigator ) {
		// ナビゲータ表示領域の位置とサイズを調べる。
		// カテゴリが表示されている場合はサイズの取得は比較的容易だが、そうでない場合は境界線の太さをだいたいで求めることになる。
		if ( hCategoryTreeView ) {
			// カテゴリを表示している
			GetWindowRect(hCategoryTreeView, &rt);
			gx = 0;
			gy = rt.bottom - rt.top + RBAR_WIDTH;
			gw = rt.right - rt.left;
		}
		else {
			// カテゴリを表示していない
			GetWindowRect(hMainListView, &rt);
			GetWindowRect(hWnd, &rt2);
			gx = gy = 0;

			int border = GetSystemMetrics(SM_CXSIZEFRAME)*3/2;
			if (border < 8) border = 8;

			gw = rt.left - rt2.left - border;
		}

		GetClientRect(hWnd      , &rt);
		GetClientRect(hStatusBar, &rt2);
		gh = rt.bottom - gy - rt2.bottom;

		// gx,gy:ナビゲータ領域の左上  gw,gh:ナビゲータ領域の幅と高さ

		if ( !ui_font ) {
			ui_font = CreateFont(12,0,0,0, FW_NORMAL,0,0,0,SHIFTJIS_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,VARIABLE_PITCH  | FF_DONTCARE,/*(winver >= 410 && rnsf7RegRead("NoDefFont", 0) == 0)?"MS UI Gothic":*/"ＭＳ Ｐゴシック");
		}
		if ( !bold_font ) {
			bold_font = CreateFont(16,0,0,0,FW_BOLD | FW_NORMAL,0,0,0,SHIFTJIS_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,VARIABLE_PITCH  | FF_DONTCARE,/*(winver >= 410 && rnsf7RegRead("NoDefFont", 0) == 0)?"MS UI Gothic":*/"ＭＳ Ｐゴシック");
		}
		if ( !uline_font ) {
			uline_font = CreateFont(12,0,0,0, FW_NORMAL,0,1,0,SHIFTJIS_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,VARIABLE_PITCH  | FF_DONTCARE,/*(winver >= 410 && rnsf7RegRead("NoDefFont", 0) == 0)?"MS UI Gothic":*/"ＭＳ Ｐゴシック");
		}

		curSel = GetLVCursor( hMainListView );

		if ( curSel >= 0 ) {
			// リストビューの指された番号が、メモリ中の何番目の項目かを調べる
			curSel = (int)lvGetLParam(hMainListView, curSel);
		}

		// 前回の描画と変化がなければ、前回のまま表示
		if ( running_settingdialog == 0 && (lastSel != curSel || last_gx != gx || last_gy != gy || last_gw != gw || last_gh != gh) ) {
			// 変化があれば、表示内容を書き換える（ここではrscを実行する。WM_PAINTが理由となってrscが呼び出されないようにする。WM_PAINTは編集ダイアログ表示中にも呼ばれてしまうから）
			if ( mlvi && curSel >= 0 ) {
				item = mlvi[curSel].item;
				info = mlvi[curSel].info;
				rsc_fname = mlvi[curSel].rsc_fname;
				author = mlvi[curSel].author;
				url = mlvi[curSel].url;
				category = mlvi[curSel].category;
			}
			else {
				item = "";
				info = bCategory?"左のカテゴリ一覧から分類名を選択し、右の一覧から設定を編集したい項目を開いて下さい。":"設定を編集したい項目を開いて下さい。";;
				rsc_fname = "";
				author = "";
				url = "";
				category = "";
			}

			MLVNavColor = 2; // グラデーションカラー（デフォルト：緑）
			MLVNavItemY = 10;	 // アイテム名の表示されるY座標
			MLVNavInfoY = 80;	 // 情報の表示されるY座標
			MLVNavBitmapY = 130; // 絵の表示されるY座標
			MLVNavLinkY = 130; // クリッカブルテキストのY座標
			bitmap = "";
			wavsound = "";
			if ( curSel >= 0 ) {
				navct[0].navlink = "この項目を開く";
				navct[0].ClickableNavi_m = ID_SETTINGS_OPEN;
				navct[1].navlink = "ソースを表示する";
				navct[1].ClickableNavi_m = IDM_VIEWSOURCE;

				// 「この項目のヘルプ」が利用可能かどうか判定
				if ( !mlvi || mlvi[curSel].help == 0 || _stricmp(mlvi[curSel].help, "none") == 0 || _stricmp(mlvi[curSel].help, "dynamic") == 0 ) {
					navct[2].navlink = "プロパティ";
					navct[2].ClickableNavi_m = IDM_ITEMPROP; // ヘルプを表示する代わりに、アイテムのプロパティを表示
				}
				else { // 利用可能
					navct[2].navlink = "この項目のヘルプ";
					navct[2].ClickableNavi_m = IDM_ITEMHELP;
				}
			}
			else {
				navct[0].navlink = "オプション";
				navct[0].ClickableNavi_m = ID_SETTINGS_SETTING;
				navct[1].navlink = "ヘルプ";
				navct[1].ClickableNavi_m = IDM_HELP_HELP;
				navct[2].navlink = "終了";
                navct[2].ClickableNavi_m = IDM_SETTINGS_EXIT;
			}

			lastSel = curSel;
			last_gx = gx;
			last_gy = gy;
			last_gw = gw;
			last_gh = gh;

			REG reg;
			char *navigator;

			safefree( sitem );
			sitem      = _strdup( item );
			safefree( sinfo );
			sinfo      = _strdup( info );
			safefree( sbitmap );
			sbitmap    = _strdup( bitmap );
			safefree( swavsound );
			swavsound  = _strdup( wavsound );

			safefree( navct[0].ClickableNavi_s );
			navct[0].ClickableNavi_s = _strdup( navct[0].navlink );
			safefree( navct[1].ClickableNavi_s );
			navct[1].ClickableNavi_s = _strdup( navct[1].navlink );
			safefree( navct[2].ClickableNavi_s );
			navct[2].ClickableNavi_s = _strdup( navct[2].navlink );

			if ( reg.OpenKey(HKEY_CURRENT_USER, RNSF7REGKEY,TREG_OPEN_READONLY) ) {
				navigator = reg.new_ReadString( "navigator", "デフォルト" );
				if ( navigator ) {
					// ナビゲーションrscを実行する
					if ( tFileExist( navigator ) && 0 == rsc( hWnd, navigator, NULL, 0, callback_nav ) ) {
						safefree( sitem );
						sitem      = _strdup(getVariable_d( "NAVIGATOR_ITEM$" ));
						safefree( sinfo );
						sinfo      = _strdup(getVariable_d( "NAVIGATOR_INFORMATION$" ));
						safefree( sbitmap );
						sbitmap    = _strdup(getVariable_d( "NAVIGATOR_BITMAP$" ));
						safefree( swavsound );
						swavsound  = _strdup(getVariable_d( "NAVIGATOR_SOUND$" ));

						safefree( navct[0].ClickableNavi_s );
						navct[0].ClickableNavi_s = _strdup(getVariable_d( "NAVIGATOR_LINK_1$" ));
						safefree( navct[1].ClickableNavi_s );
						navct[1].ClickableNavi_s = _strdup(getVariable_d( "NAVIGATOR_LINK_2$" ));
						safefree( navct[2].ClickableNavi_s );
						navct[2].ClickableNavi_s = _strdup(getVariable_d( "NAVIGATOR_LINK_3$" ));

						MLVNavColor = getVariable( "NAVIGATOR_COLOR" );
						MLVNavItemY = getVariable( "NAVIGATOR_ITEM_Y" );
						MLVNavInfoY = getVariable( "NAVIGATOR_INFO_Y" );
						MLVNavBitmapY = getVariable( "NAVIGATOR_BITMAP_Y" );
						MLVNavLinkY = getVariable( "NAVIGATOR_LINK_Y" );

						if ( swavsound && swavsound[0] ) {
							PlaySound(NULL, 0, 0);
							PlaySound(swavsound, 0, SND_ASYNC | SND_FILENAME | SND_NODEFAULT);
						}
						else {
							PlaySound(NULL, 0, 0);
						}

						bDefNav = false;
					}
					safedelete( navigator );
				}
				reg.CloseKey();
			}
		}
		else {
			if ( flag_from_on ) {
				// 前回と比べてカーソル位置に変化が無く、WM_PAINTからの呼び出しでなければ、描画を行わない
                return;
			}
		}

		// ナビゲータ領域
		n = (gh<64)?gh:64;

		// グラデーションするエリアより下は白く
		OldPen = SelectObject(hdc, GetStockObject(WHITE_PEN));
		OldBrush = SelectObject(hdc, GetStockObject(WHITE_BRUSH));

		if ( n == 64 ) {
			Rectangle(hdc, gx, gy+n, gx+gw, gy+gh);
		}
		// グラデーション
		for(i=0 ; i<n ; i++) {
			hPen = CreatePen(PS_SOLID,1,RGB((MLVNavColor&4)?255:i*4,(MLVNavColor&2)?255:i*4,(MLVNavColor&1)?255:i*4));
			if ( hPen ) {
				SelectObject(hdc, hPen);
				MoveToEx(hdc, gx, gy+i, NULL);
				LineTo(hdc, gw + gx, gy+i);
				SelectObject(hdc, OldPen);
				DeleteObject(hPen);
			}
		}
		SelectObject(hdc, OldBrush);

		// ビットマップ
		if (bDefNav) {
			// デフォルトのナビゲータの場合は、画面左下にいじくるつくーるのロゴを表示
			if (gh > 245) {
				static HBITMAP hBmp_logos;
				if (!hBmp_logos) {
					hBmp_logos = (HBITMAP)LoadBitmap(hInst, (LPCSTR)IDB_SMALL_LOGO);
				}
				if (hBmp_logos) {
					HDC memDC;
					BITMAP bitmap;

					memDC = CreateCompatibleDC(hdc);
					if ( memDC ) {
						SelectObject(memDC, hBmp_logos);
						GetObject(hBmp_logos, sizeof(BITMAP), &bitmap);
						BitBlt(hdc, bitmap.bmWidth/16, gy+gh-bitmap.bmHeight-bitmap.bmHeight/4, gw-bitmap.bmWidth/16, bitmap.bmHeight, memDC, 0, 0, SRCCOPY);
						DeleteDC(memDC);
					}
				}
			}
		}
		else {
			if ( MLVNavBitmapY >= 0 && sbitmap && sbitmap[0] ) {
				HBITMAP hBmp = (HBITMAP)LoadImage(hInst, sbitmap, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
				if ( hBmp ) {
					HDC memDC;
					BITMAP bitmap;

					memDC = CreateCompatibleDC(hdc);
					if ( memDC ) {
						SelectObject(memDC, hBmp);
						GetObject(hBmp, sizeof(BITMAP), &bitmap);
						BitBlt(hdc, gx, gy+MLVNavBitmapY, gw, gh-MLVNavBitmapY, memDC, 0, 0, SRCCOPY);
						DeleteDC(memDC);
					}
					DeleteObject( hBmp );
				}
			}
		}

		// クリッカブルテキスト
		SetBkMode(hdc, TRANSPARENT);
		OldPen = SelectObject(hdc, uline_font);

		if ( MLVNavLinkY >= 0 ) {
			int by, j;
			SIZE sz;

			by = gy + MLVNavLinkY + 32;

			for(j=0 ; j<NUM_NAVCT ; j++) {
				// クリッカブルテキストの縦幅を算出
				GetTextExtentPoint32(hdc, "I", 1, &sz);
				navct[j].ClickableNavi_h = sz.cy + 2;

				// クリッカブルテキストの左上座標を算出
				navct[j].ClickableNavi_x = gx + 20;
                navct[j].ClickableNavi_y = by + navct[j].ClickableNavi_h * j;

				// クリッカブルテキストの高さを再計算
				// (領域からはみ出してしまう場合は切る)
				if ( navct[j].ClickableNavi_y + navct[j].ClickableNavi_h >= gy + gh ) {
					if ( navct[j].ClickableNavi_y  < gy + gh ) {
						navct[j].ClickableNavi_h = gy + gh - navct[j].ClickableNavi_y;
					}
				}

				// クリッカブルテキストの横幅を算出
				GetTextExtentPoint32(hdc, navct[j].ClickableNavi_s, lstrlen(navct[j].ClickableNavi_s), &sz);
				navct[j].ClickableNavi_r = ( navct[j].ClickableNavi_x + sz.cx > gx + gw - 1 ) ? gx + gw - 1 : navct[j].ClickableNavi_x + sz.cx;

				// ヘルプがない or ナビゲータ領域の都合で利用可能かどうか
				if ( navct[j].ClickableNavi_m == 0 || navct[j].ClickableNavi_y >= gy + gh ) {
					navct[j].ClickableNavi_y = -1;
				}
			}

			// ナビゲータ領域のうち、クリッカブルテキスト部分の描画を行う
			MoveMouseOnNavigator( hWnd, -1, -1 ); // 描画のみ
		}
		else { // ナビゲータスクリプトの指示でMLVNavLinkYが負の数にセットされたら、ナビゲータは非表示
			for(int j=0 ; j<NUM_NAVCT ; j++) {
				navct[j].ClickableNavi_y = -1;
			}
		}

		// テキスト部分（アイテム名と説明）の表示
		SetTextColor( hdc, RGB(0,0,0) );
		SetBkMode( hdc, TRANSPARENT );
		
		rt.left = gx + 4;
		rt.right = gx + gw - 4;
		rt.bottom = gy + gh;
		if ( MLVNavItemY >= 0 ) {
			rt.top = gy + MLVNavItemY;
			SelectObject(hdc, bold_font);
			DrawText(hdc, sitem, -1, &rt, DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | DT_EXPANDTABS);
		}
		if ( MLVNavInfoY >= 0 ) {
			rt.top = gy + MLVNavInfoY;
			SelectObject(hdc, ui_font);
			DrawText(hdc, sinfo, -1, &rt, DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | DT_EXPANDTABS);
		}
		SelectObject(hdc, OldPen);
	}
}

// ナビゲータ上でマウスが動いた
void MoveMouseOnNavigator( HWND hWnd, int mx, int my )
{
	if ( StartNavigator && bNavigator ) {
		HDC hdc;
		HGDIOBJ hOldFont;
		RECT rt;
		bool mcursorf = 0;
		HCURSOR hCursor;
		static bool last_statusbar_state = 0;

		hdc = GetDC( hWnd );
		if ( hdc ) {
			hOldFont = SelectObject(hdc, uline_font);
			SetBkMode( hdc, TRANSPARENT );

			for(int j=0 ; j<NUM_NAVCT ; j++) {
				if ( navct[j].ClickableNavi_y >= 0 ) {
					rt.top    = navct[j].ClickableNavi_y;
					rt.left   = navct[j].ClickableNavi_x;
					rt.bottom = navct[j].ClickableNavi_y+navct[j].ClickableNavi_h;
					rt.right  = navct[j].ClickableNavi_r;
					if ( rt.left <= mx && mx < rt.right && rt.top <= my && my < rt.bottom ) {
						// マウスカーソルがクリッカブルテキスト上にあったら
						// 文字を赤くし、カーソルの形状をハンドカーソルにする
						SetTextColor( hdc, RGB(0xff, 0, 0) );
						mcursorf = 1;
						setStatusBarHelp( navct[j].ClickableNavi_m );
					}
					else {
						// マウスカーソルがクリッカブルテキスト上にあったら
						// 文字を青くする
						SetTextColor( hdc, RGB(0, 0, 0xff) );
					}

					// クリッカブルテキストを描画（改行はしない）
					DrawText(hdc, navct[j].ClickableNavi_s, -1, &rt, DT_LEFT | DT_NOPREFIX | DT_EXPANDTABS);
				}
			}

			SelectObject(hdc, hOldFont);
			ReleaseDC(hWnd, hdc);

			// マウスカーソルを変化
			if ( NULL != (hCursor = LoadCursor(NULL, (winver>400 && mcursorf)?IDC_HAND:IDC_ARROW)) ) {
				SetCursor( hCursor );
			}

			// ステータスバーの表示
			if ( mcursorf == 0 ) {
				if ( last_statusbar_state == 1 ) {
					setStatusBarText( NULL, 0 );
					last_statusbar_state = 0;
				}
			}
			else {
				last_statusbar_state = 1;
			}
		}
	}
}

// ナビゲータ上でマウスがクリックされた
void ClickButtonOnNavigator( HWND hWnd, int mx, int my )
{
	if ( StartNavigator && bNavigator ) {
		for(int j=0 ; j<NUM_NAVCT ; j++) {
			if ( navct[j].ClickableNavi_y >= 0 ) {
				if ( navct[j].ClickableNavi_x <= mx && mx < navct[j].ClickableNavi_r && navct[j].ClickableNavi_y <= my && my < navct[j].ClickableNavi_y+navct[j].ClickableNavi_h ) {
					MoveMouseOnNavigator( hWnd, -1, -1 );// 赤い文字を青くする（でないと、中途半端にダイアログがクリッカブルテキストに被さって、ダイアログが消えたときに、赤い部分が中途半端に残ってしまうから）
					SendMessage(hWnd, WM_COMMAND, MAKELONG(navct[j].ClickableNavi_m, 0), 0); // メッセージ送信
					break;
				}
			}
		}
	}
}
