/*	
 *	clipmenu.h
 *
 *	汎用メニュー
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2006 Naoyuki Sawa
 *
 *	* Sat Jul 01 20:20:32 JST 2006 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sun Jul 02 15:36:40 JST 2006 Naoyuki Sawa
 *	- スクロール位置(MENU.top)の設定を、描画直前(menu_disp())に行うよう変更。
 *	* Tue Nov 07 13:03:08 JST 2006 Naoyuki Sawa
 *	- clipmisc.hのARRAY→LIST名前変更に追従しました。
 */
#ifndef __CLIP_MENU_H__
#define __CLIP_MENU_H__

/*****************************************************************************
 *	汎用メニュー
 *****************************************************************************/

/* メニューパレット構造体です。
 * - menu_set_palette()への引数として使います。
 *   通常の4階調、および、16階調モード用の、標準パレットが定義済みです。
 *   または、アプリケーションプログラムにて、独自に定義することも可能です。
 */
typedef struct _MENUPALETTE {
	unsigned char item;	/* メニュー項目文字 */
	unsigned char back;	/* メニュー項目背景 */
	unsigned char title;	/* タイトル文字 */
	unsigned char border;	/* タイトル背景、および、枠 */
} MENUPALETTE;
extern const MENUPALETTE menu_palette_std;	/*  4階調標準メニューパレット */
extern const MENUPALETTE menu_palette_ldir;	/* 16階調標準メニューパレット */

/* メニュー構造体です。
 * - アプリケーションプログラムが、構造体メンバを設定・参照してはいけません。
 *   必ず、menu_*()関数を使用してください。
 */
typedef struct _MENU {
	int sel;		/* 現在の選択項目 */
	int top;		/* 現在の最上段項目 (スクロール) */
	//			/* topは、menu_disp()の中だけで利用します。                                        */
	//			/* topの設定も、描画直前に行います。これは“見た目”のためだけの属性だからです。   */
	//			/* menu_set_sel()等による選択変更時に、明示的にtopを変更することはありません。     */
	//			/* すなわち、topは常に正しいスクロール位置(最上段項目)を指しているとは限りません。 */
	//			/* アプリケーションが直接、topを参照したり設定したりしないよう注意してください。   */
	//
	int x;			/* メニュー領域 */
	int y;
	int w;
	int h;
	int font;		/* フォント (0 or 1 or 2) */
	MENUPALETTE palette;	/* パレット */
	//
	char* title;		/* タイトル (複製して保持。NULL = 無し) */
	LIST* items;		/* メニュー項目のリスト */
} MENU;

/* メニューを作成します。
 * [out]
 *	戻り値		作成したメニュー。
 * [note]
 *	* メニュー作成直後の初期状態は、以下の通りです。
 *		選択状態	選択無し
 *		メニュー領域	横画面全体表示
 *		フォント	10ドット日本語フォント
 *		パレット	4階調標準メニューパレット
 *		タイトル	無し
 *		メニュー項目	無し
 *	  メニュー作成後に、必要に応じて、設定の変更とメニュー項目の追加を行ってください。
 *	* メニューが不要になったら、menu_delete()を呼び出して、メニューを削除してください。
 */
MENU* menu_create();

/* メニューを削除します。
 * [in]
 *	menu		削除するメニュー。
 */
void menu_delete(MENU* menu);

/* 選択状態を設定します。
 * [in]
 *	menu		メニュー。
 *	sel		0〜メニュー項目数-1・・・選択項目。
 *			                 -1・・・選択無し。
 */
void menu_set_sel(MENU* menu, int sel);

/* 選択状態を取得します。
 * [in]
 *	menu		メニュー。
 * [out]
 *	戻り値		0〜メニュー項目数-1・・・選択項目。
 *			                 -1・・・選択無し。
 * [note]
 *	* メニュー処理完了前、および、メニュー処理完了後のいつでも呼び出し可能です。
 */
int menu_get_sel(MENU* menu);

/* メニュー領域を設定します。
 * [in]
 *	menu		メニュー。
 *	(x,y,w,h)	メニュー領域。
 *			タイトル(有れば)、および、枠の領域を含みます。
 */
void menu_set_pos(MENU* menu, int x, int y, int w, int h);

/* フォントを設定します。
 * [in]
 *	menu		メニュー。
 *	font		0または0x80・・・5×10ドット日本語フォント。
 *			1または0x81・・・8×10ドット英語フォント。
 *			2または0x82・・・4× 6ドット英語フォント。
 * [note]
 *	* フォント番号のbit7(改行フラグ)は無視されます。
 *	  bit7をセットしてもしなくても、影響ありません。
 */
void menu_set_font(MENU* menu, int font);

/* パレットを設定します。
 * [in]
 *	menu		メニュー。
 *	palette		パレット。
 * [note]
 *	* menu_set_palette()は、指定されたパレットを複製して格納します。
 *	  呼び出し側にて、paletteに指定したメモリの内容を維持する必要はありません。
 */
void menu_set_palette(MENU* menu, const MENUPALETTE* palette);

/* タイトルを設定します。
 * [in]
 *	menu		メニュー。
 *	title		タイトル文字列。
 *			NULLを指定すると、タイトル無しとなります。
 * [note]
 *	* menu_set_title()は、titleに指定された文字列を複製して格納します。
 *	  呼び出し側にて、titleに指定したメモリの内容を維持する必要はありません。
 */
void menu_set_title(MENU* menu, const char* title);

/* 末尾に、メニュー項目を追加します。
 * [in]
 *	menu		メニュー。
 *	item		メニュー項目文字列。
 *			NULLを指定することはできません。
 * [note]
 *	* 「menu_insert_item(menu, menu_num_items(menu), item);」と等価です。
 */
void menu_add_item(MENU* menu, const char* item);

/* 指定された位置に、メニュー項目を追加します。
 * [in]
 *	menu		メニュー。
 *	i_item		メニュー項目インデクス。
 *			  0〜メニュー項目数-1・・・途中にメニュー項目を追加します。
 *			     メニュー項目数  ・・・末尾にメニュー項目を追加します。
 *	item		メニュー項目文字列。
 *			NULLを指定することはできません。
 * [note]
 *	* menu_add_item()、および、menu_insert_item()は、itemに指定された文字列を複製して格納します。
 *	  呼び出し側にて、itemに指定したメモリの内容を維持する必要はありません。
 *	* メニュー項目が無い状態から、一つめの項目を追加したとき、自動的にその項目を選択します。
 *	  二つめ以降のメニュー項目を追加したときは、選択状態を変更しません。
 *	- 選択無しの状態であっても、一つめのメニュー項目追加でなければ、選択状態を変更しません。
 *	  次の例を参考にしてください。
 *	  (menu_add_item()を使って例示していますが、menu_insert_item()でも同様です。)
 *
 *		menu = menu_create();
 *		menu_add_item(menu, "いぬ"); // 一つめなので、自動的に選択する
 *		menu_add_item(menu, "さる"); // "いぬ"が選択されたまま
 *		menu_set_sel(menu, -1);      // 明示的に選択無しにした
 *		menu_add_item(menu, "きじ"); // 選択無しのまま
 *		menu_clear_items(menu);      // メニュー項目が無い状態に戻った
 *		menu_add_item(menu, "おに"); // 一つめなので、自動的に選択する
 */
void menu_insert_item(MENU* menu, int i_item, const char* item);

/* メニュー項目を変更します。
 * [in]
 *	menu		メニュー。
 *	i_item		メニュー項目インデクス。(0〜メニュー項目数-1)
 *	item		メニュー項目文字列。
 *			NULLを指定することはできません。
 */
void menu_set_item(MENU* menu, int i_item, const char* item);

/* メニュー項目を削除します。
 * [in]
 *	menu		メニュー。
 *	i_item		メニュー項目インデクス。(0〜メニュー項目数-1)
 * [note]
 *	* 削除前の選択項目と、削除する項目によって、選択状態は適切に変化します。
 *	  たぶん、直観どおりの挙動であると思います。
 *	  詳細は、関数内コメントを参照してください。
 */
void menu_remove_item(MENU* menu, int i_item);

/* メニュー項目をすべて破棄します。
 * [in]
 *	menu		メニュー。
 */
void menu_clear_items(MENU* menu);

/* メニュー項目を取得します。
 * [in]
 *	menu		メニュー。
 *	i_item		メニュー項目インデクス。(0〜メニュー項目数-1)
 *	buf		メニュー項目文字列を格納するバッファ。
 *			NULLを指定すると、メニュー項目文字列を格納しません。
 *	buflen		バッファのバイト数。
 *			メニュー項目文字数が(buflen-1)文字よりも多い場合、先頭の(buflen-1)文字のみ格納し、
 *			buflen文字目に'\0'を格納します。
 * [out]
 *	戻り値		メニュー項目文字数。(終端の'\0'は含まない)
 *			バッファに格納した文字数ではなく、実際のメニュー項目文字数を返します。
 * [note]
 *	* 確実にメニュー項目文字列すべてを受け取るためには、次のように使用してください。
 *
 *		len = menu_get_item(menu, i_item, NULL, 0);
 *		buf = malloc(len + 1);
 *		menu_get_item(menu, i_item, buf, len + 1);
 *		** bufに格納された文字列を使用する **
 *		free(buf);
 *
 *	  あらかじめ、充分大きなバッファが用意できる場合は、単純に一回呼び出すだけでも構いません。
 */
int menu_get_item(MENU* menu, int i_item, char* buf, int buflen);

/* メニュー項目数を取得します。
 * [in]
 *	menu		メニュー。
 * [out]
 *	戻り値		メニュー項目数。
 */
int menu_num_items(MENU* menu);

/* メニュー処理を1ステップ実行します。
 * [in]
 *	menu		メニュー。
 * [out]
 *	戻り値		メニュー処理が完了したら、0以外を返します。
 *			メニュー処理を継続する場合は、0を返します。
 * [note]
 *	* メニュー処理が完了する要因は、以下の通りです。
 *	- 選択決定・・・メニュー項目が選択された状態でAボタンが押された。
 *	  メニュー項目が選択されていない状態では、選択決定できません。
 *	  従って、メニュー項目が無い場合は、キャンセルしかできません。
 *	- キャンセル・・・Bボタンが押された。
 *	  キャンセルは、いつでも可能です。
 *	  キャンセル不可としたい場合は、次のように呼び出してください。
 *
 *		retval = menu_action(menu, joy & ~TRG_B);
 *
 *	* メニュー処理が完了した後に、menu_get_sel()を呼び出してください。
 *	  menu_get_sel()の戻り値が-1ならば、完了要因はキャンセルです。
 *	  menu_get_sel()の戻り値が0以上ならば、完了要因は選択決定であり、
 *	  menu_get_sel()の戻り値が、選択されたメニュー項目のインデクスです。
 *
 *		menu = menu_create();
 *		menu_set_title(menu, "Sample Menu");
 *		menu_add_item(menu, "One");
 *		menu_add_item(menu, "Two");
 *		menu_add_item(menu, "Three");
 *		for(;;) {
 *			schedule();
 *			if(menu_action(menu)) { // メニュー処理
 *				break;
 *			}
 *			menu_disp(menu); // メニュー描画
 *		}
 *		retval = menu_get_sel(menu);
 *		if(retval >= 0) {
 *			// メニュー項目[retval]が選択決定されました。
 *		} else {
 *			// キャンセルされました。
 *		}
 *		menu_delete(menu);
 */
int menu_action(MENU* menu, int joy);

/* メニューを描きます。
 * [in]
 *	menu		メニュー。
 */
void menu_disp(MENU* menu, RENDER* render);

#endif/*__CLIP_MENU_H__*/
