code:
;≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
; タグ指定が可能な文字列
;
;	関数名	:	FuncTagSetText_～～
;
; @@でタグ指定する。対応するタグは以下。
;	@C:value@		: 色指定。                "value"はタグで囲んだ部分のテキスト色を 0xRRGGBB で指定する。この時 -1 を指定すると RESETCOLOR する。
;
;	@B:value@		: ボタン指定。            "value"はタグで囲んだ部分をクリックした際に入力される文字列を指定する。
;
;	@F:value@		: フォント指定。          "value"はタグで囲んだ部分のフォント名称を指定する
;
;	@I:value@		: 画像指定。              "value"は描画する画像のリソース名を指定する。
;												","区切りでタグの他の属性も指定できる。（例：value="画像リソース名,height='600',ypos='-600'"）
;												タグで囲んだ部分は捨てられるが、FuncTagSetText_GetPrintLength()を使用する場合は、「(画像の幅÷フォントサイズ)個の全角スペース」を挿入すること
;												（例 @I:画像のリソース名@　　　　　@/I@）リソースで指定した画像の幅が高さの5倍の場合
;
;												また、複数行に跨る画像を描画する場合、yposの値は [-1 * 画像の高さ] にすることを推奨する。
;												これは、画像指定よりも下の行で、なんらかの描画を行った場合、その内容で画像の描画が上書きされてしまうためである
;
;	@S:value@		: フォントスタイル指定。  "value"はタグで囲んだ部分のスタイル値を指定する（スタイル値はFONTSTYLEで指定する値）
;												※Html版は、value値に関係なく太字として扱う
;
;
; 使用例)
;		CALLF TAG_PRINT( "あいう@C:0xFF8888@@B:Red@赤ボタン@/B@@C:0x88FF88@@B:Green@緑ボタン@/B@@C:0x8888FF@@B:Blue@青ボタン@/B@@/C@", 0x01 )
;	で以下の記述と同じ描画行える
;		LOCAL = GETCOLOR()
;		PRINTFORM あいう
;		SETCOLOR 0xFF8888
;		PRINTBUTTON "赤ボタン", "Red"
;		SETCOLOR 0x88FF88
;		PRINTBUTTON "緑ボタン", "Green"
;		SETCOLOR 0x8888FF
;		PRINTBUTTON "青ボタン", "Blue"
;		SETCOLOR LOCAL
;		PRINTL
;≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

;================================================================
; カラーバー用の文字列を生成する
;--------------------------------
;[引数]
;	nBarVol			: バー現在値
;	nBarVolMax		: バー最大値（0以下指定だとnBarVolと同値として扱う）
;	nScaleNum		: 目盛数（半角文字の個数）
;	colorLeft		: バーの左端の色
;	colorRigth		: バーの右端(100%)の色
;	colorEmpty		: バーのEmpty部分の色
;	flgExtra		: 特殊表示フラグ（ビット演算。）
;						0x01	: カラーバーの後ろに現在値と最大値を記述する	" ({nBarVol,5}/{nBarVolMax,5})"
;	strScaleText	: メモリ文字（半角文字。未指定時は%UNICODE(0x2586)%）
;--------------------------------
;[戻り値など]
;	カラーバー用の文字列（色指定タグと■で構成された文字列）
;================================================================
@FuncTagSetText_CreateColorBarText( nBarVol, nBarVolMax, nScaleNum, colorLeft, colorRigth, colorEmpty, flgExtra, strScaleText = "" )
#FUNCTIONS
#DIM  nBarVol
#DIM  nBarVolMax
#DIM  nScaleNum
#DIM  colorLeft
#DIM  colorRigth
#DIM  colorEmpty
#DIM  flgExtra
#DIMS strScaleText

#DIM  colorLeft_RGB, 3
#DIM  colorRigth_RGB, 3
#DIM  colorCalc_RGB, 3
#DIM  colorBuf
#DIM  flgEmpty
#DIM  nLoop
#DIMS strBarText

IF STRLENS( strScaleText ) <= 0
	strScaleText '= UNICODE(0x2586)
	;strScaleText '= UNICODE(0x220E)
	;strScaleText '= UNICODE(0x2588)
	;strScaleText '= UNICODE(0x2585)
ENDIF

VARSET strBarText, ""

colorLeft_RGB:0 = colorLeft / 256 / 256
colorLeft_RGB:1 = colorLeft / 256 % 256
colorLeft_RGB:2 = colorLeft % 256
colorRigth_RGB:0 = colorRigth / 256 / 256
colorRigth_RGB:1 = colorRigth / 256 % 256
colorRigth_RGB:2 = colorRigth % 256

flgEmpty = 0
FOR nLoop, 0, nScaleNum
	IF nBarVol > nLoop * nBarVolMax / nScaleNum
		colorCalc_RGB:0 = (colorRigth_RGB:0 - colorLeft_RGB:0) * nLoop / MAX( nScaleNum - 1 )
		colorCalc_RGB:1 = (colorRigth_RGB:1 - colorLeft_RGB:1) * nLoop / MAX( nScaleNum - 1 )
		colorCalc_RGB:2 = (colorRigth_RGB:2 - colorLeft_RGB:2) * nLoop / MAX( nScaleNum - 1 )
		colorBuf = FuncColor_ChangeColor( colorLeft, colorCalc_RGB:0, colorCalc_RGB:1, colorCalc_RGB:2 )
		strBarText += @"@C:{colorBuf}@"
	ELSE
		IF flgEmpty == 0
			strBarText += @"@C:{colorEmpty}@"
			flgEmpty = 1
		ENDIF
	ENDIF
	strBarText += strScaleText
	IF flgEmpty == 0 || nLoop == nScaleNum - 1
		strBarText += @"@/C@"
	ENDIF
NEXT

IF (flgExtra & 0x01) > 0
	strBarText += @" ({nBarVol,5}/{nBarVolMax,5})"
ENDIF

RETURNF strBarText

;================================================================
; 指定したタグ指定テキスト文字列に設定されているボタン情報を取得する
;--------------------------------
;[引数]
;	strText		: タグ指定を含んだ表示テキスト
;					※ @@で囲むことでタグ指定として扱う
;--------------------------------
;[戻り値など]
;	ボタン数が返る
;
;	RESULT:0	: ボタン数が格納される
;	RESULTS:0~	: ボタン値が格納される
;================================================================
@FuncTagSetText_GetButtonData( strText )
#FUNCTION
#DIMS strText

#DIMS strSplitBuf, 500
#DIM  nSplitCount
#DIM  nLoop

#DIMS arrTagInfo, 20
#DIMS arrButtonValue, 500
#DIM  nButtonCount

VARSET strSplitBuf, ""
SPLIT strText, "@", strSplitBuf
nSplitCount = RESULT

VARSET arrTagInfo, ""
VARSET arrButtonValue, ""
nButtonCount = 0
FOR nLoop, 0, nSplitCount
	IF nLoop % 2 == 0
		; 表示する文字列は無視する
	ELSE
		CALLF FuncTagSetText_SetTagInfo( strSplitBuf:nLoop, arrTagInfo )
		IF STRLENS(arrTagInfo:1) > 0
			IF FINDELEMENT(arrButtonValue, arrTagInfo:1, 0, VARSIZE( "arrButtonValue" ), 1) == -1
				arrButtonValue:nButtonCount '= arrTagInfo:1
				nButtonCount += 1
			ENDIF
		ENDIF
	ENDIF
NEXT

VARSET RESULTS, ""
VARSET RESULT, 0
ARRAYCOPY "arrButtonValue", "RESULTS"
RESULT = nButtonCount
RETURNF nButtonCount

;================================================================
; 指定したタグ指定テキスト文字列の表示文字数を取得する
;--------------------------------
;[引数]
;	strText		: タグ指定を含んだ表示テキスト
;					※ @@で囲むことでタグ指定として扱う
;--------------------------------
;[戻り値など]
;	指定したタグ指定テキスト文字列の表示文字数（全角文字は2文字でカウントする）
;================================================================
@FuncTagSetText_GetPrintLength( strText )
#FUNCTION
#DIMS strText

#DIMS strSplitBuf, 500
#DIM  nSplitCount
#DIM  nLoop
#DIM  nPrintTextLen

VARSET strSplitBuf, ""
nPrintTextLen = 0

SPLIT strText, "@", strSplitBuf
nSplitCount = RESULT

FOR nLoop, 0, nSplitCount
	IF nLoop % 2 == 0
		nPrintTextLen += FuncString_GetLength( strSplitBuf:nLoop )
	ELSE
		; タグの内容は無視する
	ENDIF
NEXT

RETURNF nPrintTextLen

;================================================================
; 指定したタグ指定テキスト文字列の非タグ部分を取得する
;--------------------------------
;[引数]
;	strText		: タグ指定を含んだ表示テキスト
;					※ @@で囲むことでタグ指定として扱う
;--------------------------------
;[戻り値など]
;	指定したタグ指定テキスト文字列の非タグ部分
;================================================================
@FuncTagSetText_GetPlainText( strText )
#FUNCTIONS
#DIMS strText

#DIMS strSplitBuf, 500
#DIM  nSplitCount
#DIM  nLoop
#DIM  nPrintTextLen
#DIMS strPlainText

VARSET strSplitBuf, ""
nPrintTextLen = 0

SPLIT strText, "@", strSplitBuf
nSplitCount = RESULT

strPlainText '= ""
FOR nLoop, 0, nSplitCount
	IF nLoop % 2 == 0
		strPlainText += strSplitBuf:nLoop
	ELSE
		; タグの内容は無視する
	ENDIF
NEXT

RETURNF strPlainText

;================================================================
; タグ指定テキストを指定の文字数となるように整形する
; ※ 文字数が多い場合は、複数の文字列に分割して返す
;--------------------------------
;[引数]
;	strText		: タグ指定を含んだ表示テキスト
;					※ @@で囲むことでタグ指定として扱う
;	nShapeSize	: 分割する長さを指定する（2以上の値を指定すること。全角は2文字扱い）
;	nPadding	: 分割後の文字列の長さが指定文字数になるように半角スペースで埋めるかどうか（0=埋めない, 1=半角スペース埋め, ）
;	nAlign		: 左詰め,右詰め,中央寄せ
;					0 = 左詰め
;					1 = 右詰め
;					2 = 中央寄せ（不足文字数が奇数の場合、左側の埋め文字が1文字多くなる）
;--------------------------------
;[戻り値など]
;	成形後のタグ指定テキスト。RESULTS:0の内容と同じ
;
;	RESULT		: 成形後の文字列の個数。分割しなければ 1 が返る
;	RESULTS:0~	: 分割後のタグ指定テキスト。文字数が多い場合は、サイズ内に収まるように分割し、RESULTS:0,1と順番に格納していく
;================================================================
@TAG_PRINT_SHAPE( strText, nShapeSize, nPadding, nAlign=0 )
#FUNCTIONS
#DIMS strText
#DIM  nShapeSize
#DIM  nPadding
#DIM  nAlign

#DIMS strShapeText, 200
#DIM  nShapeTextCnt

#DIMS arrTagInfo, 20
#DIMS strSplitBuf, 500
#DIM  nSplitCount
#DIM  nLoop

#DIMS strTextBuf
#DIM  nCheckedTextLen

#DIMS strAlign

VARSET strShapeText, ""
nShapeTextCnt = 0
VARSET arrTagInfo, ""
VARSET strSplitBuf, ""

VARSET RESULT, 0
VARSET RESULTS, ""

; サイズが2未満の場合は、分割せず、指定されたサイズに整形した文字列を返す
SELECTCASE nShapeSize
	CASE IS <= 0
		RESULTS:0 '= ""
		RESULT = 1
		RETURNF RESULTS:0
	CASE 1
		LOCALS '= SUBSTRINGU(strText, 0, 1)
		RESULTS:0 '= (STRLENS(LOCALS) == 1 ? LOCALS # " ")
		RESULT = 1
		RETURNF RESULTS:0
ENDSELECT

SELECTCASE nAlign
	CASE 1
		strAlign '= "R"
	CASE 2
		strAlign '= "C"
	CASEELSE
		strAlign '= "L"
ENDSELECT

SPLIT strText, "@", strSplitBuf
nSplitCount = RESULT

nCheckedTextLen = 0
FOR nLoop, 0, nSplitCount
	IF nLoop % 2 == 0
		strTextBuf '= strSplitBuf:nLoop
		WHILE STRLENSU( strTextBuf ) > 0
			nCheckedTextLen = FuncTagSetText_GetPrintLength( strShapeText:nShapeTextCnt )
			LOCAL = FuncString_GetLength( strTextBuf )
			IF nCheckedTextLen + LOCAL <= nShapeSize
				strShapeText:nShapeTextCnt += strTextBuf
				nCheckedTextLen += LOCAL
				strTextBuf '= ""
			ELSE
				; 格納できる分だけ、格納領域へ格納する
				WHILE 1
					LOCALS '= SUBSTRINGU( strTextBuf, 0, 1 )
					SIF nCheckedTextLen + FuncString_GetLength( LOCALS ) > nShapeSize
						BREAK
					strShapeText:nShapeTextCnt += LOCALS
					nCheckedTextLen += FuncString_GetLength( LOCALS )
					strTextBuf '= SUBSTRINGU( strTextBuf, 1, -1 )
				WEND
				; 格納し終わったので、タグを閉じる
				strShapeText:nShapeTextCnt += FuncTagSetText_TagInfoText_End( arrTagInfo )
				IF nPadding == 1
					IF nShapeSize - nCheckedTextLen > 0
						LOCAL = FuncString_GetLength( strShapeText:nShapeTextCnt ) + nShapeSize - nCheckedTextLen
						strShapeText:nShapeTextCnt '= FuncString_Padding( strShapeText:nShapeTextCnt, LOCAL, " ", strAlign )
					ENDIF
				ENDIF
				; 次の格納領域へ
				nShapeTextCnt += 1
				strShapeText:nShapeTextCnt '= FuncTagSetText_TagInfoText_Start( arrTagInfo )
				nCheckedTextLen = 0
			ENDIF
		WEND
	ELSE
		strShapeText:nShapeTextCnt += "@" + strSplitBuf:nLoop + "@"
		CALLF FuncTagSetText_SetTagInfo( strSplitBuf:nLoop, arrTagInfo )
	ENDIF
NEXT

; 格納し終わったので、タグを閉じる
strShapeText:nShapeTextCnt += FuncTagSetText_TagInfoText_End( arrTagInfo )
IF nPadding == 1
	IF nShapeSize - nCheckedTextLen > 0
		LOCAL = FuncString_GetLength( strShapeText:nShapeTextCnt ) + nShapeSize - nCheckedTextLen
		strShapeText:nShapeTextCnt '= FuncString_Padding( strShapeText:nShapeTextCnt, LOCAL, " ", strAlign )
	ENDIF
ENDIF

VARSET RESULT, 0
VARSET RESULTS, ""
ARRAYCOPY "strShapeText", "RESULTS"

RESULT:0 = nShapeTextCnt + 1
RETURNF RESULTS:0

;================================================================
;【内部処理用】
; タグ指定テキストのタグ情報を設定する
;--------------------------------
;[引数]
;	strText		: タグ指定文字列
;	arrTagInfo	: 現在のタグ情報
;					arrTagInfo:0	= 色指定情報
;					arrTagInfo:1	= ボタン指定情報
;					arrTagInfo:2	= フォント指定
;					arrTagInfo:3	= 画像指定
;					arrTagInfo:4	= フォントスタイル指定
;--------------------------------
;[戻り値など]
;================================================================
@FuncTagSetText_SetTagInfo( strText, arrTagInfo )
#FUNCTION
#DIMS strText
#DIMS REF arrTagInfo, 0

#DIMS strTagType
#DIMS strTagValue

IF SUBSTRINGU( strText, 0, 1 ) == "/"
	; タグ解除
	strTagType  '= SUBSTRINGU( strText, 1, -1 )
	strTagValue '= ""
ELSE
	; タグ設定
	VARSET LOCALS, ""
	SPLIT strText, ":", LOCALS
	strTagType  '= LOCALS:0
	strTagValue '= LOCALS:1
	IF RESULT > 1
		FOR LOCAL ,2 ,RESULT
			strTagValue += ":" + LOCALS:LOCAL
		NEXT
	ENDIF
ENDIF

SELECTCASE strTagType
		; 色指定
	CASE "C"
		arrTagInfo:0 '= strTagValue
		; ボタン指定
	CASE "B"
		arrTagInfo:1 '= strTagValue
		; フォント指定
	CASE "F"
		arrTagInfo:2 '= strTagValue
		; 画像指定
	CASE "I"
		arrTagInfo:3 '= strTagValue
		; フォントスタイル指定
	CASE "S"
		arrTagInfo:4 '= strTagValue
	CASE "T"
		arrTagInfo:5 '= strTagValue
ENDSELECT

RETURNF 0

;================================================================
;【内部処理用】
; タグ指定テキストのタグ指定文字列を生成する
;--------------------------------
;[引数]
;	arrTagInfo	: 現在のタグ情報
;					arrTagInfo:0	= 色指定情報
;					arrTagInfo:1	= ボタン指定情報
;					arrTagInfo:2	= フォント指定
;					arrTagInfo:3	= 画像指定
;					arrTagInfo:4	= フォントスタイル指定
;					arrTagInfo:4	= ボタンなしツールチップ
;--------------------------------
;[戻り値など]
;	RESULTS:0	: タグ指定文字列
;================================================================
@FuncTagSetText_TagInfoText_Start( arrTagInfo )
#FUNCTIONS
#DIMS REF arrTagInfo, 0

#DIMS strTagText
#DIM  nLoop

VARSET strTagText, ""

FOR nLoop, 0, 6
	SIF STRLENS( arrTagInfo:nLoop ) <= 0
		CONTINUE

	SELECTCASE nLoop
		CASE 0
			strTagText '= strTagText + @"@C:%arrTagInfo:nLoop%@"
		CASE 1
			strTagText '= strTagText + @"@B:%arrTagInfo:nLoop%@"
		CASE 2
			strTagText '= strTagText + @"@F:%arrTagInfo:nLoop%@"
		CASE 3
			strTagText '= strTagText + @"@I:%arrTagInfo:nLoop%@"
		CASE 4
			strTagText '= strTagText + @"@S:%arrTagInfo:nLoop%@"
		CASE 5
			strTagText '= strTagText + @"@T:%arrTagInfo:nLoop%@"
		CASEELSE
			; 以降、未使用
	ENDSELECT
NEXT

RESULTS:0 '= strTagText
RETURNF strTagText

;================================================================
;【内部処理用】
; タグ指定テキストのタグクローズ用のタグ指定文字列を生成する
;--------------------------------
;[引数]
;	arrTagInfo	: 現在のタグ情報
;					arrTagInfo:0	= 色指定情報
;					arrTagInfo:1	= ボタン指定情報
;					arrTagInfo:2	= フォント指定
;					arrTagInfo:3	= 画像指定
;					arrTagInfo:4	= フォントスタイル指定
;--------------------------------
;[戻り値など]
;	RESULTS:0	: タグ指定文字列
;================================================================
@FuncTagSetText_TagInfoText_End( arrTagInfo )
#FUNCTIONS
#DIMS REF arrTagInfo, 0

#DIMS strTagText
#DIM  nLoop

VARSET strTagText, ""

FOR nLoop, 0, 5
	SIF STRLENS( arrTagInfo:nLoop ) <= 0
		CONTINUE

	SELECTCASE nLoop
		CASE 0
			strTagText '= strTagText + "@/C@"
		CASE 1
			strTagText '= strTagText + "@/B@"
		CASE 2
			strTagText '= strTagText + "@/F@"
		CASE 3
			strTagText '= strTagText + "@/I@"
		CASE 4
			strTagText '= strTagText + "@/S@"
		CASEELSE
			; 以降、未使用
	ENDSELECT
NEXT

RESULTS:0 '= strTagText
RETURNF strTagText

;/************************************************************************************/
; HTMLでの出力用処理
;/************************************************************************************/
;================================================================
; タグ指定テキストの描画(HTML_PRINT版)
;--------------------------------
;[引数]
;	strText		: タグ指定を含んだ表示テキスト
;					※ @@で囲むことでタグ指定として扱う
;	nExFlag		: 特殊フラグ（ビット指定）
;					0x01 : 描画後に改行を行う
;					0x02 : タグを無視する
;--------------------------------
;[戻り値など]
;================================================================
@TAG_PRINTH( strText, nExFlag )
#FUNCTION
#DIMS strText
#DIM  nExFlag

HTML_PRINT FuncTagSetText_ConvHtmlText( strText ),nExFlag ? 0 # 1

RETURNF 0

;================================================================
; 指定したタグ指定テキスト文字列のHTMLテキストに変換する
;--------------------------------
;[引数]
;	strText		: タグ指定を含んだ表示テキスト
;					※ @@で囲むことでタグ指定として扱う
;--------------------------------
;[戻り値など]
;	HTMLテキスト
;================================================================
@CONV_TAG2H(strText)
#FUNCTIONS
#DIMS strText
RETURNF FuncTagSetText_ConvHtmlText( strText )

@FuncTagSetText_ConvHtmlText( strText )
#FUNCTIONS
#DIMS strText

#DIMS strHtmlTag
#DIMS strHtmlText
#DIMS strTagType

#DIMS strSplitBuf, 1000
#DIM  nSplitCount

#DIM  nLoop

SPLIT strText, "@", strSplitBuf
nSplitCount = RESULT

strTagType '= ""
strHtmlText '= ""
FOR nLoop, 0, nSplitCount
	IF nLoop % 2 == 0
		; 文字列処理
		;MEMO : 画像表示で囲まれた文字は表示文字長の算出用なので、実際の出力文字からは除外する
		IF strTagType != "I"
			strHtmlText += HTML_ESCAPE(strSplitBuf:nLoop)
			;strHtmlText += strSplitBuf:nLoop
		ENDIF
	ELSE
		; タグ文字処理
		strHtmlTag '= FuncTagSetText_ConvHtmlTag( strSplitBuf:nLoop )
		strTagType '= RESULTS:0
		strHtmlText += strHtmlTag
	ENDIF
NEXT

;DEBUGPRINTFORML debug - TAGSET_TEXT_CONVERT_HTMLTEXT( %strText% ) → 『%strHtmlText%』
RETURNF strHtmlText

;================================================================
;【内部処理用】
; タグ指定テキストのタグ情報をHTML形式のタグに変換する
;--------------------------------
;[引数]
;	strTagInfoText	: タグ文字列（"@C:value@"など）
;--------------------------------
;[戻り値など]
;	HTMLテキスト
;
;	RESULTS:0		: タグ判別用文字（"C","B","F","I" etc）
;================================================================
@FuncTagSetText_ConvHtmlTag( strTagInfoText )
#FUNCTIONS
#DIMS strTagInfoText
#DIMS strToolChip

#DIMS strTagType
#DIMS strTagValue
#DIM  nTagClose

#DIMS strHtmlTag

IF SUBSTRINGU( strTagInfoText, 0, 1 ) == "/"
	; タグ解除
	strTagType  '= SUBSTRINGU( strTagInfoText, 1, 1 )
	IF SUBSTRINGU( strTagInfoText, 2, 1 ) == ":"
		strTagValue '= SUBSTRINGU( strTagInfoText, 3, -1 )
	ELSE
		strTagValue '= ""
	ENDIF
	nTagClose = 1
ELSE
	; タグ設定
	strTagType  '= SUBSTRINGU( strTagInfoText, 0, 1 )
	strTagValue '= SUBSTRINGU( strTagInfoText, 2, -1 )
	IF strTagType == "B"
		VARSET RESULTS
		; ツールチップ識別子がある場合ツールチップを設定
		SPLIT strTagValue, "$", RESULTS
		strTagValue '= RESULTS:0
		strToolChip '= RESULTS:1
	ENDIF
	nTagClose = 0
ENDIF

strHtmlTag '= ""
SELECTCASE strTagType
	CASE "C"
		IF nTagClose == 0
			strHtmlTag '= @""
		ELSE
			strHtmlTag '= @""
		ENDIF
	CASE "B"
		; <button value='～' title='～' pos='～'>テキスト</button>    title,posは省略する
		IF STRLENS(strTagValue) > 0
			IF nTagClose == 0
				IF strToolChip != ""
					strHtmlTag '= @"<button value='%strTagValue%' title='%strToolChip%'>"
					strToolChip '= ""
				ELSE
					strHtmlTag '= @"<button value='%strTagValue%'>"
				ENDIF
			ELSE
				strHtmlTag '= @"</button>"
			ENDIF
		ELSE
			IF nTagClose == 0
				strHtmlTag '= @"<button>"
			ELSE
				strHtmlTag '= @"</button>"
			ENDIF
		ENDIF
	CASE "F"
		IF nTagClose == 0
			strHtmlTag '= @""
		ELSE
			strHtmlTag '= @""
		ENDIF
	CASE "S"
		; ; フォントスタイル指定はHtml版ではvalue値に関係なく太字として扱う
		; IF nTagClose == 0
		; 	strHtmlTag '= @""
		; ELSE
		; 	strHtmlTag '= @""
		; ENDIF
		SELECTCASE strTagValue
			CASE "I"
				IF nTagClose == 0
					strHtmlTag '= @""
				ELSE
					strHtmlTag '= @""
				ENDIF
			CASE "U"
				IF nTagClose == 0
					strHtmlTag '= @""
				ELSE
					strHtmlTag '= @""
				ENDIF
			CASE "S"
				IF nTagClose == 0
					strHtmlTag '= @"<s>"
				ELSE
					strHtmlTag '= @"</s>"
				ENDIF
			CASEELSE
				IF nTagClose == 0
					strHtmlTag '= @""
				ELSE
					strHtmlTag '= @""
				ENDIF
		ENDSELECT
	CASE "T"
		IF nTagClose == 0
			strHtmlTag '= @"<nonbutton title='%strTagValue%'>"
		ELSE
			strHtmlTag '= @"</nonbutton>"
		ENDIF
	CASE "I"
		IF nTagClose == 0
			VARSET LOCALS, ""
			SPLIT strTagValue, ",", LOCALS
			IF STRLENS(LOCALS) > 0
				strHtmlTag '= @""
			ELSE
				strHtmlTag '= @""
			ENDIF
		ELSE
			strHtmlTag '= @""
		ENDIF
ENDSELECT

VARSET RESULTS, ""
SIF nTagClose == 0
	RESULTS:0 '= strTagType
RETURNF strHtmlTag

;/************************************************************************************/
; PRINT系での出力用処理
;/************************************************************************************/

;================================================================
; タグ指定テキストの描画
;--------------------------------
;[引数]
;	strText		: タグ指定を含んだ表示テキスト
;					※ @@で囲むことでタグ指定として扱う
;	nExFlag		: 特殊フラグ（ビット指定）
;					0x01 : 描画後に改行を行う
;					0x02 : タグを無視する
;					0x04 : ボタンを数値ボタンで処理する
;--------------------------------
;[戻り値など]
;================================================================
@TAG_PRINT( strText, nExFlag )
#FUNCTION
#DIMS strText
#DIM  nExFlag

#DIMS arrTagInfoDefault, 20
#DIMS arrTagInfo, 20
#DIMS strSplitBuf, 500
#DIM  nSplitCount
#DIM  nLoop
#DIM  nBtnIsNum

VARSET arrTagInfoDefault, ""
arrTagInfoDefault:0 '= "0x" + TOSTR( GETCOLOR(), "X6" )
arrTagInfoDefault:2 '= GETFONT()
arrTagInfoDefault:4 '= TOSTR( GETSTYLE() )
VARSET arrTagInfo, ""
VARSET strSplitBuf, ""
nBtnIsNum = ((nExFlag & 0x04) ? 1 # 0)

SPLIT strText, "@", strSplitBuf
nSplitCount = RESULT
FOR nLoop, 0, nSplitCount
	IF nLoop % 2 == 0
		CALLF TAG_PRINTTagSetText( strSplitBuf:nLoop, arrTagInfo, nBtnIsNum )
	ELSE
		; タグ無視フラグのチェック
		SIF (nExFlag & 0x02) > 0
			CONTINUE
		CALLF FuncTagSetText_SetTagInfo( strSplitBuf:nLoop, arrTagInfo )
		; テキスト色,フォントなどを本関数実行前の状態に戻す
		CALLF TAG_PRINTTagSetText( "", arrTagInfoDefault, nBtnIsNum )		;MEMO : なにかタグが存在するごとに設定し直している。手抜き工事
	ENDIF
NEXT

; テキスト色,フォントなどを本関数実行前の状態に戻す
CALLF TAG_PRINTTagSetText( "", arrTagInfoDefault, nBtnIsNum )

IF (nExFlag & 0x01) > 0
	PRINTL
ENDIF

RETURNF 0

;================================================================
;【内部処理用】
; テキストを指定されたタグ情報に準じた描画を行う
;--------------------------------
;[引数]
;	strText		: 描画文字列
;	arrTagInfo	: 現在のタグ情報
;					arrTagInfo:0	= 色指定情報
;					arrTagInfo:1	= ボタン指定情報
;					arrTagInfo:2	= フォント指定
;					arrTagInfo:3	= 画像指定
;					arrTagInfo:4	= フォントスタイル指定
;	nBtnIsNum	: ボタンを数値ボタンで処理する
;--------------------------------
;[戻り値など]
;================================================================
@TAG_PRINTTagSetText( strText, arrTagInfo, nBtnIsNum )
#FUNCTION
#DIMS strText
#DIMS REF arrTagInfo, 0
#DIM  nBtnIsNum

#DIM  nBuf

; 色指定
IF STRLENS( arrTagInfo:0 ) > 0
	IF ISNUMERIC( arrTagInfo:0 ) == 1
		nBuf = TOINT( arrTagInfo:0 )
		IF nBuf >= 0
			SETCOLOR nBuf
		ELSE
			RESETCOLOR
		ENDIF
	ENDIF
ENDIF

; フォント指定
IF STRLENS( arrTagInfo:2 ) > 0
	IF CHKFONT( arrTagInfo:2 ) == 1
		SETFONT arrTagInfo:2
	ELSE
		;DEBUGPRINTFORML @TAG_PRINTTagSetText %arrTagInfo:2%
	ENDIF
ENDIF

; フォントスタイル指定
IF STRLENS( arrTagInfo:4 ) > 0
	nBuf = TOINT( arrTagInfo:4 )
	IF nBuf >= 0
		FONTSTYLE nBuf
	ELSE
		FONTSTYLE 0
	ENDIF
ENDIF

; 画像 or ボタン指定 or 通常表示
IF STRLENS( arrTagInfo:3 ) > 0
	VARSET LOCALS, ""
	SPLIT arrTagInfo:3, ",", LOCALS
	PRINT_IMG @"%LOCALS:0%"
ELSEIF STRLENS( arrTagInfo:1 ) > 0
	IF nBtnIsNum == 1 && ISNUMERIC( arrTagInfo:1 )
		PRINTBUTTON strText, TOINT( arrTagInfo:1 )
	ELSE
		PRINTBUTTON strText, arrTagInfo:1
	ENDIF
ELSE
	PRINTPLAINFORM %strText%
ENDIF

RETURNF 0

;/************************************************************************************/
;
;/************************************************************************************/

;================================================================


code:
;--------------------------------------------
;IFRAND CODED BY 喚く
;乱数を生成する関数。与えた条件に応じて返却される乱数の範囲を切り替えられる
;あと負数を返させることもできる
;「メッセージをRANDで分岐させたいが、キャラが特定の素質を持っている場合この分岐だけ弾きたい」みたいなときに使える

;返却する値は10000通りまでいける。増やしたければRANDARRAYを増やすこと

;VARSTR:0-5	生成する値をコンマ区切りで指定する。
;			要素1つにつき1000個まで指定子が入る
;			含まれる値が返却候補となるには、対応するCONDITIONが真である必要がある
;			なお、返却候補の値が被っていた場合、単純に二重に入る（その値の選択される確率が倍になる）

;指定子の書き方
;方法①：A, B, C...	単純な追加。返却候補にAとBとCが入る
;方法②：ATOB, ....	単純な返却候補にAからBまでの連続した値が入る
;					なおA<Bである必要はない
;方法③：D1, D2...	指定した値を、返却候補から除外する
;					削除処理は各VARSTRの処理が行われた後、返却直前に行われる
;					したがって、VARSTR:0で除外指定をしたのちVARSTR:1で追加指定をしても、その値は返却候補とならない
;					同じ値が複数返却候補に含まれている場合も同様である
;方法④：D1TO10...	削除指定でもTOでの指定が使える。

;CONDITION:0-5	真偽値。真だった場合、対応するVARSTRを返却候補に含める
;				たとえば「LOCAL:0番のキャラが巨乳のときだけ、VARSTR:1に与えた値を返却候補に含めたい」なら、
;				CONDITION:1にTALENT:(LOCAL:0):巨乳 == 1 を与えればよい

;用例
;LOCAL:0 = IFRAND("0TO5, 7", 1, "6TO10", TALENT:(ARG:0):仮性包茎, "D1, D7, D8", TALENT:(ARG:0):爆乳)
;LOCAL:0に0-5,7のいずれかを代入。ARG:0のキャラが仮性包茎なら6-10も候補に含まれるため、0-10(7だけ確率倍)となる。ただし、ARG:0のキャラが爆乳なら1と7と8は代入させない。

;注意点
;最終的に返すべき値がない場合や、指定子の書き方が不正である場合、エラーを吐いて落ちる。
;---------------------------------------------
@IFRAND(VALSTR:0, CONDITION:0, VALSTR:1 = "", CONDITION:1 = 0, VALSTR:2 = "" , CONDITION:2 = 0, VALSTR:3 = "", CONDITION:3 = 0, VALSTR:4 = "", CONDITION:4 = 0, VALSTR:5 = "", CONDITION:5 = 0, VALSTR:6 = "", CONDITION:6 = 0, VALSTR:7 = "", CONDITION:7 = 0, VALSTR:8 = "", CONDITION:8 = 0, VALSTR:9 = "", CONDITION:9 = 0)
#FUNCTION
;値指定文字列
#DIMS VALSTR, 10
;値指定が有効か　呼び出し側で真偽判定ぶっこんでください（対象が巨乳か？　とか）
#DIM CONDITION, 10
;コンマでSPLITされた後の値指定
#DIMS SPLIT_VALSTR, 1000
;値指定の分割数
#DIM SPLIT_VALSTR_NUM
;今見ている値指定
#DIMS THIS_VALSTR
;値指定で範囲指定を利用した時用
#DIMS RANGESTR, 2
#DIM RANGE, 2
;最終的に生成される乱数を格納する配列
#DIM RANDARRAY, 10000
;最終的に生成される乱数の候補数
#DIM RAND_NUM
;削除する値を格納する配列
#DIM DELETEARRAY, 10000
;削除する値の
#DIM DELETE_NUM
;RESULT保存用(汚染するため)
#DIM SAVED_RESULT

VARSET RANDARRAY
VARSET RAND_NUM
VARSET DELETEARRAY
VARSET DELETE_NUM

SAVED_RESULT = RESULT

FOR LOCAL, 0, VARSIZE("CONDITION")

	;真偽判定が偽であればその値指定を無視する
	SIF !CONDITION:LOCAL
		CONTINUE

	;値指定を分割する
	SPLIT VALSTR:LOCAL, "," , SPLIT_VALSTR
	SPLIT_VALSTR_NUM = RESULT

	FOR LOCAL:1, 0, SPLIT_VALSTR_NUM
		;スペースを除去
		THIS_VALSTR = %SPLIT_VALSTR:(LOCAL:1)%
		THIS_VALSTR = %REPLACE(THIS_VALSTR, "　", "")%
		THIS_VALSTR = %REPLACE(THIS_VALSTR, " ", "")%

		;空文字列になったら無視
		SIF THIS_VALSTR == ""
			CONTINUE

		;消去指定を利用している場合
		IF STRFIND(THIS_VALSTR, "D") == 0
			THIS_VALSTR = %SUBSTRING(THIS_VALSTR, 1)%
			;消去指定で範囲指定
			IF STRFIND(THIS_VALSTR, "TO") != -1
				;ATOBを「値Aと値B」にしてRANGEに格納
				SPLIT THIS_VALSTR, "TO", RANGESTR
				SIF !ISNUMERIC(RANGESTR:0) || !ISNUMERIC(RANGESTR:1)
					THROW 削除範囲指定に不正な値が含まれています %THIS_VALSTR%
				RANGE:0 = TOINT(RANGESTR:0)
				RANGE:1 = TOINT(RANGESTR:1)
				;ATOBをDELETEARRAYに格納
				FOR LOCAL:2, MIN(RANGE:0, RANGE:1), MAX(RANGE:0, RANGE:1) + 1
					DELETEARRAY:DELETE_NUM = LOCAL:2
					DELETE_NUM ++
				NEXT
			;消去指定の単一値指定
			ELSE
				SIF !ISNUMERIC(THIS_VALSTR)
					THROW 削除値指定に不正な値が含まれています %THIS_VALSTR%
				DELETEARRAY:DELETE_NUM = TOINT(THIS_VALSTR)
				DELETE_NUM ++
			ENDIF

		;範囲指定を利用している場合
		ELSEIF STRFIND(THIS_VALSTR, "TO") != -1
			;A-Bを「値Aと値B」にしてRANGEに格納
			SPLIT THIS_VALSTR, "TO", RANGESTR
			SIF !ISNUMERIC(RANGESTR:0) || !ISNUMERIC(RANGESTR:1)
				THROW 範囲指定に不正な値が含まれています %THIS_VALSTR%
			RANGE:0 = TOINT(RANGESTR:0)
			RANGE:1 = TOINT(RANGESTR:1)
			;ATOBをRANDARRAYに格納
			FOR LOCAL:2, MIN(RANGE:0, RANGE:1), MAX(RANGE:0, RANGE:1) + 1
				RANDARRAY:RAND_NUM = LOCAL:2
				RAND_NUM ++
			NEXT

		;単一の値である場合
		ELSE
			SIF !ISNUMERIC(THIS_VALSTR)
				THROW 値指定に不正な値が含まれています %THIS_VALSTR%
			RANDARRAY:RAND_NUM = TOINT(THIS_VALSTR)
			RAND_NUM ++
		ENDIF
	NEXT
NEXT

FOR LOCAL, 0, DELETE_NUM
	WHILE FINDELEMENT(RANDARRAY, DELETEARRAY:LOCAL, 0, RAND_NUM) != -1
		LOCAL:1 = FINDELEMENT(RANDARRAY, DELETEARRAY:LOCAL, 0, RAND_NUM)
;		PRINTFORML {DELETEARRAY:LOCAL} {LOCAL:1},
		IF LOCAL:1 == VARSIZE("RANDARRAY") - 1
			RANDARRAY:(LOCAL:1) = 0
		ELSE
			;こいつなんか第二引数の正負で挙動違うんだけど
			ARRAYSHIFT RANDARRAY, -1, 0, LOCAL:1
		ENDIF
		RAND_NUM -= 1
	WEND
NEXT

SIF RAND_NUM == 0
	THROW IFRANDの返却候補値が一つもありません

;汚染されたRESULTを元に戻す
RESULT = SAVED_RESULT

RETURNF RANDARRAY:(RAND:RAND_NUM)

repo_name: pervysquirrelz/erafl

license: unknown


code:
;_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/#
;
;Module   :_Dictionary.ERB, _Dictionary.ERH
;Facility :文字列を連想配列のように扱うライブラリ
;Licence  :ライセンスフリー(CC0)。
;
;Modification Data:
;  Edit  Date          Author                   Reason
;  001   2018/08/29    MinorShift(Emueraの人)   新規作成
;_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/#

;文字列を使った連想配列もどき
;[キー:値]という形式で雑多なデータを保存する。
;例えば、連想配列用文字列STRが"[髪型:ショート][髪色:緑][瞳色:青]"であるとき、DIC_GET(STR, "髪色")は"緑"を返す。
;また、STRが"[髪型:ショート][髪色:緑][瞳色:青]"であるとき、DIC_SET(STR, "髪型", "ロング")は"[髪型:ロング][髪色:緑][瞳色:青]"を返す。
;制限として、キー又は値には"[", ":", "]"が含まれていてはいけない。当然入れ子にはできない。
;標準では一つの連想配列中のキーの最大数は100個。_Dictionary.ERHを変更すれば増やせるが実行速度が実用的でないと思われる。
;少しでも高速化するためにデータ形式のチェックは省いている。そのため不正な形式のデータが送られてくると何が起こるかわからない。
;データをまとめて格納するためにどうぞ。
;_Listとは独立しているので値として可変長配列を格納する、又は連想配列の可変長配列を作成することはできる。入れ子にすると死ぬ。

;@DIC_SET(_DICTIONARY, _KEY, _VALUE) ;対象の連想配列の_KEYに_VALUEを格納した連想配列を返す。既にキーが存在するなら上書き。
;@DIC_GET(_DICTIONARY, _KEY) ;対象の連想配列の_KEYの値を取得する。キーが存在しなければ空文字列。
;@DIC_REMOVE(_DICTIONARY, _KEY) ;対象の連想配列の_KEYを削除した連想配列を返す。キーが存在しなければ入力のまま返す。
;@DIC_CONTAINSKEY(_DICTIONARY, _KEY) ;対象の連想配列に_KEYが存在するかどうか判定する。存在すれば1、しなければ0。
;@DIC_COUNT(_DICTIONARY) ;対象の連想配列に含まれるキーの数を取得する。
;@DIC_FOREACH(_DICTIONARY, _FUNCNAME);対象の連想配列に含まれる要素全てについて、CALLFORM %FUNCNAME%, _KEY, _VALUE; を実行する。

;================================================
;@DIC_SET (#FUNCTIONS)対象の連想配列の_KEYに_VALUEを格納した連想配列を返す。既にキーが存在するなら上書き。
;_DICTIONARY 対象の連想配列（文字列）
;_KEY        追加する対象のキー
;_VALUE      追加する値
;RETURNF     追加又は変更された連想配列（文字列）
;================================================
@DIC_SET(_DICTIONARY, _KEY, _VALUE)
#FUNCTIONS
#DIMS _DICTIONARY
#DIMS _KEY
#DIMS _VALUE
;_KEYが既に存在するかどうか検証
_DIC_INDEX_OPEN = STRFINDU(_DICTIONARY, "[" + _KEY + ":")
;_KEYが新規なら[KEY:VALUE]を追加した文字列を返して終了
IF _DIC_INDEX_OPEN < 0
	RETURNF _DICTIONARY + "[" + _KEY + ":" + _VALUE + "]"
ENDIF
;_KEYが既に存在するならば_DICTIONARYから既存の[KEY:VALUE]を除いた文字列に新規な[KEY:VALUE]を追加する
IF _DIC_INDEX_OPEN > 0
	_DICTIONARY_LEFT '= SUBSTRINGU(_DICTIONARY,0,_DIC_INDEX_OPEN)
ELSE
	_DICTIONARY_LEFT '= ""
ENDIF
;"[KEY:"以降の最初の"]"をサーチ
_DIC_INDEX_CLOSE = STRFINDU(_DICTIONARY, "]", _DIC_INDEX_OPEN)
;既存の[KEY:VALUE]よりも右のテキストを_DICTIONARY_RIGHTに取得
IF _DIC_INDEX_CLOSE < 0
	THROW 連想配列用文字列が正しくない→%_DICTIONARY%
ELSEIF _DIC_INDEX_CLOSE+1 < STRLENSU(_DICTIONARY)
	_DICTIONARY_RIGHT '= SUBSTRINGU(_DICTIONARY, _DIC_INDEX_CLOSE + 1 , -1)
ELSE
	_DICTIONARY_RIGHT '= ""
ENDIF
;足して返す
RETURNF _DICTIONARY_LEFT + "[" + _KEY + ":" + _VALUE + "]" + _DICTIONARY_RIGHT

;================================================
;@DIC_CONTAINSKEY (#FUNCTION) ;対象の連想配列に_KEYが存在するかどうか判定する。存在すれば1、しなければ0。
;_DICTIONARY 対象の連想配列（文字列）
;_KEY        キー
;RETURNF     追加又は変更された連想配列（文字列）
;================================================
@DIC_CONTAINSKEY(_DICTIONARY, _KEY)
#FUNCTION
#DIMS _DICTIONARY
#DIMS _KEY
RETURNF STRFINDU(_DICTIONARY, "[" + _KEY + ":") >= 0

;================================================
;@DIC_REMOVE (#FUNCTIONS)) ;対象の連想配列の_KEYを削除した連想配列を返す。キーが存在しなければ入力のまま返す。
;_DICTIONARY 対象の連想配列（文字列）
;_KEY        キー
;RETURNF     キーが削除された連想配列（文字列）
;================================================
@DIC_REMOVE(_DICTIONARY, _KEY)
#FUNCTIONS
#DIMS _DICTIONARY
#DIMS _KEY
;_KEYが既に存在するかどうか検証
_DIC_INDEX_OPEN = STRFINDU(_DICTIONARY, "[" + _KEY + ":")
;_KEYが存在しないなら入力をそのまま返して終了
IF _DIC_INDEX_OPEN < 0
	RETURNF _DICTIONARY
ENDIF
;_KEYが既に存在するならば_DICTIONARYから既存の[KEY:VALUE]を返す
IF _DIC_INDEX_OPEN > 0
	_DICTIONARY_LEFT '= SUBSTRINGU(_DICTIONARY,0,_DIC_INDEX_OPEN)
ELSE
	_DICTIONARY_LEFT '= ""
ENDIF
;"[KEY:"以降の最初の"]"をサーチ
_DIC_INDEX_CLOSE = STRFINDU(_DICTIONARY, "]", _DIC_INDEX_OPEN)
;既存の[KEY:VALUE]よりも右のテキストを_DICTIONARY_RIGHTに取得
IF _DIC_INDEX_CLOSE < 0
	THROW _Dictionary.ERB:連想配列用文字列が正しくない→%_DICTIONARY%
ELSEIF _DIC_INDEX_CLOSE+1 < STRLENSU(_DICTIONARY)
	_DICTIONARY_RIGHT '= SUBSTRINGU(_DICTIONARY, _DIC_INDEX_CLOSE + 1 , -1)
ELSE
	_DICTIONARY_RIGHT '= ""
ENDIF
;足して返す
RETURNF _DICTIONARY_LEFT + _DICTIONARY_RIGHT

;================================================
;@DIC_GET (#FUNCTIONS)) ;対象の連想配列の_KEYの値を取得する。キーが存在しなければ空文字列。
;_DICTIONARY 対象の連想配列（文字列）
;_KEY        キー
;RETURNF     キーに対応する値又は空文字列
;================================================
@DIC_GET(_DICTIONARY, _KEY)
#FUNCTIONS
#DIMS _DICTIONARY
#DIMS _KEY
;_KEYが存在するかどうか検証
_DIC_INDEX_OPEN = STRFINDU(_DICTIONARY, "[" + _KEY + ":")
;_KEYが存在しないなら空文字列を返して終了
IF _DIC_INDEX_OPEN < 0
	RETURNF ""
ENDIF
;値の開始位置のインデックスを計算
_DIC_INDEX_OPEN = _DIC_INDEX_OPEN + STRLENSU(_KEY) + 2
;"[KEY:"以降の最初の"]"をサーチ
_DIC_INDEX_CLOSE = STRFINDU(_DICTIONARY, "]", _DIC_INDEX_OPEN)
IF _DIC_INDEX_CLOSE < 0
	THROW _Dictionary.ERB:連想配列用文字列が正しくない→%_DICTIONARY%
ENDIF
RETURNF SUBSTRINGU(_DICTIONARY, _DIC_INDEX_OPEN, _DIC_INDEX_CLOSE - _DIC_INDEX_OPEN)

;================================================
;@DIC_GETINT @DIC_GETの取得値をTOINTして返すラッパー関数
;_DICTIONARY 対象の連想配列（文字列）
;_KEY        キー
;RETURNF     キーに対応する値又は空文字列
;================================================
@DIC_GETINT(_DICTIONARY, _KEY)
#FUNCTION
#DIMS _DICTIONARY
#DIMS _KEY
RETURNF TOINT(DIC_GET(_DICTIONARY, _KEY))

;================================================
;@DIC_COUNT (#FUNCTION) ;対象の連想配列に含まれるキーの数を取得する。
;_DICTIONARY 対象の連想配列（文字列）
;RETURNF     キーの数
;================================================
@DIC_COUNT(_DICTIONARY)
#FUNCTION
#DIMS _DICTIONARY
#DIM _COUNT
_DIC_INDEX_OPEN = -1
_COUNT = 0
WHILE 1
	_DIC_INDEX_OPEN = STRFINDU(_DICTIONARY, "[" , _DIC_INDEX_OPEN + 1)
	IF _DIC_INDEX_OPEN < 0
		BREAK
	ENDIF
	_COUNT ++
WEND
RETURNF _COUNT

;================================================
;@DIC_FOREACH ;対象の連想配列に含まれる要素全てについて、CALLFORM %FUNCNAME%, _KEY, _VALUE; を実行する。
;_DICTIONARY  対象の連想配列（文字列）
;_FUNCNAME    実行する関数名(CALLFORM %FUNCNAME%, _KEY, _VALUE)
;RESULT       特になし
;================================================
@DIC_FOREACH(_DICTIONARY, _FUNCNAME)
#DIMS _DICTIONARY
#DIMS _FUNCNAME
#DIM _KEYCOUNT
#DIM _CNT
#DIMS _DIC_PAIRS,_DIC_MAX

SPLIT _DICTIONARY, "[", _DIC_PAIRS
IF RESULT > _DIC_MAX
	THROW _Dictionary.ERB:連想配列のキー数が多すぎる→%_DICTIONARY%
ENDIF
_KEYCOUNT = RESULT
FOR _CNT,0,_KEYCOUNT
	;空文字列か"キー:値]"のはず
	_DIC_INDEX_OPEN = STRFINDU(_DIC_PAIRS:_CNT, ":")
	IF _DIC_INDEX_OPEN < 0
		CONTINUE
	ENDIF
	;_KEY = SUBSTRINGU(_DIC_PAIRS:_CNT, 0, _DIC_INDEX_OPEN)
	;_VALUE = SUBSTRINGU(_DIC_PAIRS:_CNT, _DIC_INDEX_OPEN + 1, STRLENSU(_DIC_PAIRS:_CNT) - (_DIC_INDEX_OPEN + 1) -1)
	;CALLFORM %_FUNCNAME%, _KEY, _VALUE
	CALLFORM %_FUNCNAME%, SUBSTRINGU(_DIC_PAIRS:_CNT, 0, _DIC_INDEX_OPEN), SUBSTRINGU(_DIC_PAIRS:_CNT, _DIC_INDEX_OPEN + 1, STRLENSU(_DIC_PAIRS:_CNT) - (_DIC_INDEX_OPEN + 1) -1)
NEXT

;================================================
;@DIC_KEYS ;対象の連想配列に含まれるキーを全て取得する
;_DICTIONARY  対象の連想配列（文字列）
;_FUNCNAME    実行する関数名(CALLFORM %FUNCNAME%, _KEY, _VALUE)
;RESULT       キーの数
;RESULTS:0~   キー
;================================================
@DIC_KEYS(_DICTIONARY)
#DIMS _DICTIONARY
#DIMS _FUNCNAME
#DIM _KEYCOUNT
#DIM _CNT
#DIMS _DIC_PAIRS,_DIC_MAX
VARSET RESULTS

SPLIT _DICTIONARY, "[", _DIC_PAIRS
IF RESULT > _DIC_MAX
	THROW _Dictionary.ERB:連想配列のキー数が多すぎる→%_DICTIONARY%
ENDIF
_KEYCOUNT = RESULT
FOR _CNT, 0, _KEYCOUNT
	;空文字列か"キー:値]"のはず
	_DIC_INDEX_OPEN = STRFINDU(_DIC_PAIRS:_CNT, ":")
	IF _DIC_INDEX_OPEN < 0
		CONTINUE
	ENDIF
	RESULTS:(_CNT - 1) = %SUBSTRINGU(_DIC_PAIRS:_CNT, 0, _DIC_INDEX_OPEN)%
NEXT

RETURN _KEYCOUNT - 1

;式中関数版
@DIC_KEYSF(_DICTIONARY)
#FUNCTION
#DIMS _DICTIONARY
#DIMS _FUNCNAME
#DIM _KEYCOUNT
#DIM _CNT
#DIMS _DIC_PAIRS,_DIC_MAX
VARSET RESULTS

SPLIT _DICTIONARY, "[", _DIC_PAIRS
IF RESULT > _DIC_MAX
	THROW _Dictionary.ERB:連想配列のキー数が多すぎる→%_DICTIONARY%
ENDIF
_KEYCOUNT = RESULT
FOR _CNT, 0, _KEYCOUNT
	;空文字列か"キー:値]"のはず
	_DIC_INDEX_OPEN = STRFINDU(_DIC_PAIRS:_CNT, ":")
	IF _DIC_INDEX_OPEN < 0
		CONTINUE
	ENDIF
	RESULTS:(_CNT - 1) = %SUBSTRINGU(_DIC_PAIRS:_CNT, 0, _DIC_INDEX_OPEN)%
NEXT

RETURNF _KEYCOUNT - 1


code:
;DIC関連で用いる一時変数

#DIM CONST _DIC_MAX = 1000 ;必要に応じて適宜増やしてください

#DIMS _DICTIONARY_LEFT
#DIMS _DICTIONARY_RIGHT
#DIM _DIC_INDEX_OPEN
#DIM _DIC_INDEX_CLOSE


code:
;_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/#
;
;Module   :_LIST.ERB, _LIST.ERH
;Facility :文字列を可変長配列のように扱うライブラリ
;Licence  :ライセンスフリー(CC0)。
;
;Modification Data:
;  Edit  Date          Author                   Reason
;  001   2018/08/29    MinorShift(Emueraの人)   新規作成
;_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/#

;文字列を使った可変長配列もどき
;"値,値,値,"という形式でデータを保存する。（要素数が1以上なら終端にカンマが必須）
;例えば、可変長配列用文字列STRが"ショート,セミロング,ロング,"であるとき、LIST_GET(STR, 1)は"セミロング"を返す。
;また、STRが"ショート,セミロング,ロング,"であるとき、LIST_ADD(STR, "ロングウェーブ")は"ショート,セミロング,ロング,ロングウェーブ,"を返す。
;制限として、格納する値にはカンマが含まれていてはいけない。当然入れ子にはできない。
;標準では一つの可変長配列中の要素の最大数は100個。_LIST.ERHを変更すれば増やせるが実行速度が実用的でないと思われる。
;少しでも高速化するためにデータ形式のチェックは省いている。そのため不正な形式のデータが送られてくると何が起こるかわからない。
;データをまとめて格納するためにどうぞ。
;_Dictionaryとは独立しているので値として連想配列を格納する、又は可変長配列を連想配列に格納することはできる。入れ子にすると死ぬ。

;@LIST_ADD(_LIST, _VALUE) ;対象の可変長配列の末尾に_VALUEを追加した可変長配列を返す。
;@LIST_SET(_LIST, _INDEX, _VALUE) ;対象の可変長配列の_INDEX番目の要素を_VALUEで上書きした可変長配列を返す。配列サイズが不足していれば自動的に拡張される。
;@LIST_ADDLIST(_LIST, _LIST_OTHER) ;対象の可変長配列の末尾に_LIST_OTHERを結合した可変長配列を返す。
;@LIST_GET(_LIST, _INDEX) ;対象の可変長配列の_INDEX番目の要素を返す。配列の範囲外である場合、空文字列を返す。
;@LIST_INDEXOF(_LIST, _VALUE) ;対象の可変長配列に_VALUEと完全一致する要素が存在すればその最初のINDEX、存在しなければ-1を返す。
;@LIST_COUNT(_LIST) ;対象の可変長配列のサイズ（要素数）を返す。
;@LIST_INSERTAT(_LIST, _INDEX, _VALUE) ;対象の可変長配列の_INDEX番目に_VALUEを追加した可変長配列を返す。
;@LIST_REMOVEAT(_LIST, _INDEX) ;対象の可変長配列の_INDEX番目の要素を削除した可変長配列を返す。配列の範囲外である場合、_LISTをそのまま返す。
;@LIST_REMOVEALL(_LIST, _VALUE) ;対象の可変長配列から_VALUEと一致する要素を全て削除した可変長配列を返す。
;@LIST_SORT(_LIST) ;対象の可変長配列を昇順でソートした可変長配列を返す。
;@LIST_SORT_R(_LIST) ;対象の可変長配列を逆順（降順）でソートした可変長配列を返す。
;@LIST_FOREACH(_LIST, _FUNCNAME) ;対象の可変長配列に含まれる要素全てについて、順番にCALLFORM %_FUNCNAME%, _VALUE; を実行する。

;================================================
;@LIST_SET (#FUNCTIONS);対象の可変長配列の_INDEX番目の要素を_VALUEで上書きした可変長配列を返す。配列サイズが不足していれば自動的に拡張される。
;_LIST       対象の可変長配列（文字列）
;_INDEX      追加又は変更する場所のインデックス
;_VALUE      追加又は変更する値
;RETURNF     追加又は変更された可変長配列（文字列）
;================================================
@LIST_SET(_LIST, _INDEX, _VALUE)
#FUNCTIONS
#DIMS _LIST
#DIM _INDEX
#DIMS _VALUE
#DIM _COUNT
IF _INDEX < 0
	THROW _List.ERB:_INDEXに負の値({_INDEX})が指定された→%_LIST%
ENDIF
_LIST_LENGTH = STRCOUNT(_LIST, ",")
;配列数不足なら拡張（,を増やす）して終了
IF _INDEX >= _LIST_LENGTH
	RETURNF _LIST + ("," * (_INDEX - _LIST_LENGTH)) + _VALUE + ","
ENDIF
;(_INDEX-1)番目のカンマと_INDEX番目のカンマを探索して_LIST_INDEX_LEFT,_LIST_INDEX_RIGHTに代入
_LIST_INDEX_COMMA = -1
_LIST_INDEX_LEFT = -1
_COUNT = 0
WHILE 1
	_LIST_INDEX_COMMA = STRFINDU(_LIST, "," , _LIST_INDEX_COMMA + 1)
	IF _COUNT == _INDEX
		_LIST_INDEX_RIGHT = _LIST_INDEX_COMMA
		BREAK
	ENDIF
	_LIST_INDEX_LEFT = _LIST_INDEX_COMMA
	_COUNT ++
WEND
IF _INDEX > 0
	;右端にカンマを含む形で切り取る
	_LIST_LEFT '= SUBSTRINGU(_LIST,0,_LIST_INDEX_LEFT+1)
ELSE
	_LIST_LEFT '= ""
ENDIF
;左端にカンマを含む形で切り取る
_LIST_RIGHT '= SUBSTRINGU(_LIST, _LIST_INDEX_RIGHT , -1)

;足して返す
RETURNF _LIST_LEFT + _VALUE + _LIST_RIGHT

;================================================
;@LIST_ADD (#FUNCTIONS);対象の可変長配列の末尾に_VALUEを追加した可変長配列を返す。
;_LIST       対象の可変長配列（文字列）
;_VALUE      追加する値
;RETURNF     追加された可変長配列（文字列）
;================================================
@LIST_ADD(_LIST, _VALUE)
#FUNCTIONS
#DIMS _LIST
#DIMS _VALUE
RETURNF _LIST + _VALUE + ","

;================================================
;@LIST_ADDLIST (#FUNCTIONS);対象の可変長配列の末尾に_LIST_OTHERを結合した可変長配列を返す。
;_LIST       対象の可変長配列（文字列）
;_LIST_OTHER 追加する可変長配列
;RETURNF     追加された可変長配列（文字列）
;================================================
@LIST_ADDLIST(_LIST, _LIST_OTHER)
#FUNCTIONS
#DIMS _LIST
#DIMS _LIST_OTHER
RETURNF _LIST + _LIST_OTHER

;@LIST_GET(_LIST, _INDEX) ;対象の可変長配列の_INDEX番目の要素を返す。配列の範囲外である場合、空文字列を返す。
;================================================
;@LIST_GET (#FUNCTIONS);対象の可変長配列の_INDEX番目の要素を返す。配列の範囲外である場合、空文字列を返す。
;_LIST       対象の可変長配列（文字列）
;_INDEX      取得する要素のインデックス
;RETURNF     取得した要素
;================================================
@LIST_GET(_LIST, _INDEX)
#FUNCTIONS
#DIMS _LIST
#DIM _INDEX
#DIM _COUNT
IF _INDEX < 0
	THROW _List.ERB:_INDEXに負の値({_INDEX})が指定された→%_LIST%
ENDIF
;(_INDEX-1)番目のカンマと_INDEX番目のカンマを探索して_LIST_INDEX_LEFT,_LIST_INDEX_RIGHTに代入
_LIST_INDEX_COMMA = -1
_LIST_INDEX_LEFT = -1
_COUNT = 0
WHILE 1
	_LIST_INDEX_COMMA = STRFINDU(_LIST, "," , _LIST_INDEX_COMMA + 1)
	IF _COUNT == _INDEX
		_LIST_INDEX_RIGHT = _LIST_INDEX_COMMA
		BREAK
	ENDIF
	;_INDEXが配列外参照
	IF _LIST_INDEX_COMMA < 0
		RETURNF ""
	ENDIF
	_LIST_INDEX_LEFT = _LIST_INDEX_COMMA
	_COUNT ++
WEND
RETURNF SUBSTRINGU(_LIST,_LIST_INDEX_LEFT + 1, _LIST_INDEX_RIGHT - _LIST_INDEX_LEFT - 1)

;INT型に変換して取得。文字列かどうかは特に判定せずTOINTの挙動に沿う
@LIST_GETINT(_LIST, _INDEX)
#FUNCTION
#DIMS _LIST
#DIM _INDEX
RETURNF TOINT(LIST_GET(_LIST, _INDEX))

;@LIST_COUNT(_LIST) ;対象の可変長配列のサイズ（要素数）を返す。
;================================================
;@LIST_COUNT (#FUNCTION);対象の可変長配列のサイズ（要素数）を返す。
;_LIST       対象の可変長配列（文字列）
;RETURNF     サイズ（要素数）
;================================================
@LIST_COUNT(_LIST)
#FUNCTION
#DIMS _LIST
RETURNF STRCOUNT(_LIST, ",")

;================================================
;@LIST_INSERTAT (#FUNCTIONS);対象の可変長配列の_INDEX番目に_VALUEを追加した可変長配列を返す。
;_LIST       対象の可変長配列（文字列）
;_INDEX      追加する場所のインデックス
;_VALUE      追加する値
;RETURNF     追加された可変長配列（文字列）
;================================================
@LIST_INSERTAT(_LIST, _INDEX, _VALUE)
#FUNCTIONS
#DIMS _LIST
#DIM _INDEX
#DIMS _VALUE
#DIM _COUNT
IF _INDEX < 0
	THROW _List.ERB:_INDEXに負の値({_INDEX})が指定された→%_LIST%
ENDIF
_LIST_LENGTH = STRCOUNT(_LIST, ",")
;配列数不足なら拡張（,を増やす）して終了。LIST_SETと同じ処理
IF _INDEX >= _LIST_LENGTH
	RETURNF _LIST + ("," * (_INDEX - _LIST_LENGTH)) + _VALUE + ","
ENDIF

;(_INDEX-1)番目のカンマと_INDEX番目のカンマを探索して_LIST_INDEX_LEFT,_LIST_INDEX_RIGHTに代入
_LIST_INDEX_COMMA = -1
_LIST_INDEX_LEFT = -1
_COUNT = 0
WHILE 1
	_LIST_INDEX_COMMA = STRFINDU(_LIST, "," , _LIST_INDEX_COMMA + 1)
	IF _COUNT == _INDEX
		_LIST_INDEX_RIGHT = _LIST_INDEX_COMMA
		BREAK
	ENDIF
	_LIST_INDEX_LEFT = _LIST_INDEX_COMMA
	_COUNT ++
WEND
IF _INDEX > 0
	;右端にカンマを含む形で切り取る
	_LIST_LEFT '= SUBSTRINGU(_LIST,0,_LIST_INDEX_LEFT+1)
ELSE
	_LIST_LEFT '= ""
ENDIF
;左端にカンマを含む形で切り取る
_LIST_RIGHT '= SUBSTRINGU(_LIST, _LIST_INDEX_LEFT , -1); _LIST_INDEX_RIGHTじゃなくてLEFT。元のINDEX番目の要素を含む
SIF _INDEX == 0
	_LIST_RIGHT '= "," + _LIST_RIGHT

;足して返す
RETURNF _LIST_LEFT + _VALUE + _LIST_RIGHT

;================================================
;@LIST_REMOVEAT (#FUNCTIONS);対象の可変長配列の_INDEX番目の要素を削除した可変長配列を返す。配列の範囲外である場合、_LISTをそのまま返す。
;_LIST       対象の可変長配列（文字列）
;_INDEX      削除する場所のインデックス
;RETURNF     削除された可変長配列（文字列）
;================================================
@LIST_REMOVEAT(_LIST, _INDEX)
#FUNCTIONS
#DIMS _LIST
#DIM _INDEX
#DIM _COUNT
IF _INDEX < 0
	THROW _List.ERB:_INDEXに負の値({_INDEX})が指定された→%_LIST%
ENDIF
_LIST_LENGTH = STRCOUNT(_LIST, ",")
;配列外なら_LISTをそのまま返す
IF _INDEX > _LIST_LENGTH - 1
	RETURNF _LIST
ENDIF
;配列の唯一の要素を削除しようとしているなら空配列（空文字列）を返す
IF _LIST_LENGTH == 1 && _INDEX == 0
	RETURNF ""
ENDIF
;(_INDEX-1)番目のカンマと_INDEX番目のカンマを探索して_LIST_INDEX_LEFT,_LIST_INDEX_RIGHTに代入
_LIST_INDEX_COMMA = -1
_LIST_INDEX_LEFT = -1
_COUNT = 0
WHILE 1
	_LIST_INDEX_COMMA = STRFINDU(_LIST, "," , _LIST_INDEX_COMMA + 1)
	IF _COUNT == _INDEX
		_LIST_INDEX_RIGHT = _LIST_INDEX_COMMA
		BREAK
	ENDIF
	_LIST_INDEX_LEFT = _LIST_INDEX_COMMA
	_COUNT ++
WEND
IF _INDEX > 0
	;右端にカンマを"含まない"形で切り取る
	_LIST_LEFT '= SUBSTRINGU(_LIST,0,_LIST_INDEX_LEFT)
ELSE
	_LIST_LEFT '= ""
ENDIF
;左端にカンマを含む形で切り取る
IF _INDEX > 0
	_LIST_RIGHT '= SUBSTRINGU(_LIST, _LIST_INDEX_RIGHT , -1)
	;_INDEXが0の場合は左端にカンマを"含まない"形で切り取る
ELSE
	_LIST_RIGHT '= SUBSTRINGU(_LIST, _LIST_INDEX_RIGHT + 1, -1)
ENDIF
;足して返す
RETURNF _LIST_LEFT + _LIST_RIGHT

;================================================
;@LIST_INDEXOF (#FUNCTION) ;対象の可変長配列に_VALUEと完全一致する要素が存在すればその最初のINDEX、存在しなければ-1を返す。
;_LIST       対象の可変長配列（文字列）
;_VALUE      探索する値
;RETURNF     発見されたINDEX又は-1
;================================================
@LIST_INDEXOF(_LIST, _VALUE)
#FUNCTION
#DIMS _LIST
#DIMS _VALUE
#DIM _KEYCOUNT
#DIM _CNT
;手抜きして「_VALUE + ","」をFINDすると_VALUEが空文字列の時に爆死する
SPLIT _LIST, ",", _LIST_ELEMENT
IF RESULT > _LIST_MAX
	THROW _List.ERB:リストの要素数が多すぎる→%_LIST%
ENDIF
_KEYCOUNT = RESULT-1 ;末尾が,なのでSPLITした末端は空文字列になる
IF _KEYCOUNT <= 0
	RETURNF -1
ENDIF
FOR _CNT,0,_KEYCOUNT
	IF _LIST_ELEMENT:_CNT == _VALUE
		RETURNF _CNT
	ENDIF
NEXT
RETURNF -1

;================================================
;@LIST_REMOVEALL (#FUNCTIONS) ;対象の可変長配列から_VALUEと一致する要素を全て削除した可変長配列を返す。
;_LIST       対象の可変長配列（文字列）
;_VALUE      削除する値
;RETURNF     削除された可変長配列（文字列）
;================================================
@LIST_REMOVEALL(_LIST, _VALUE)
#FUNCTIONS
#DIMS _LIST
#DIMS _VALUE
#DIM _KEYCOUNT
#DIM _CNT
;手抜きして「_VALUE + ","」を空文字列でREPLACEすると_VALUEが空文字列の時に爆死する
SPLIT _LIST, ",", _LIST_ELEMENT
IF RESULT > _LIST_MAX
	THROW _List.ERB:リストの要素数が多すぎる→%_LIST%
ENDIF
_KEYCOUNT = RESULT-1 ;末尾が,なのでSPLITした末端は空文字列になる
IF _KEYCOUNT <= 0
	RETURNF _LIST
ENDIF
_LIST '= ""
FOR _CNT,0,_KEYCOUNT
	IF _LIST_ELEMENT:_CNT == _VALUE
		CONTINUE
	ENDIF
	_LIST += _LIST_ELEMENT:_CNT + ","
NEXT
RETURNF _LIST

;================================================
;@LIST_SORT (#FUNCTIONS) ;対象の可変長配列を昇順でソートした可変長配列を返す。
;_LIST       対象の可変長配列（文字列）
;RETURNF     ソートされた可変長配列（文字列）
;================================================
@LIST_SORT(_LIST)
#FUNCTIONS
#DIMS _LIST
#DIMS _FUNCNAME
#DIM _KEYCOUNT
#DIM _CNT
SPLIT _LIST, ",", _LIST_ELEMENT
IF RESULT > _LIST_MAX
	THROW _List.ERB:リストの要素数が多すぎる→%_LIST%
ENDIF
_KEYCOUNT = RESULT-1 ;末尾が,なのでSPLITした末端は空文字列になる
IF _KEYCOUNT <= 0
	RETURNF _LIST
ENDIF
ARRAYSORT _LIST_ELEMENT, FORWARD, 0, _KEYCOUNT
_LIST '= ""
FOR _CNT,0,_KEYCOUNT
	_LIST += _LIST_ELEMENT:_CNT + ","
NEXT
RETURNF _LIST

;================================================
;@LIST_SORT_R (#FUNCTIONS) ;対象の可変長配列を逆順（降順）でソートした可変長配列を返す。
;_LIST       対象の可変長配列（文字列）
;RETURNF     ソートされた可変長配列（文字列）
;================================================
@LIST_SORT_R(_LIST)
#FUNCTIONS
#DIMS _LIST
#DIMS _FUNCNAME
#DIM _KEYCOUNT
#DIM _CNT
SPLIT _LIST, ",", _LIST_ELEMENT
IF RESULT > _LIST_MAX
	THROW _List.ERB:リストの要素数が多すぎる→%_LIST%
ENDIF
_KEYCOUNT = RESULT-1 ;末尾が,なのでSPLITした末端は空文字列になる
IF _KEYCOUNT <= 0
	RETURNF _LIST
ENDIF
ARRAYSORT _LIST_ELEMENT, BACK, 0, _KEYCOUNT
_LIST '= ""
FOR _CNT,0,_KEYCOUNT
	_LIST += _LIST_ELEMENT:_CNT + ","
NEXT
RETURNF _LIST

;================================================
;@LIST_FOREACH ;対象の可変長配列に含まれる要素全てについて、順番にCALLFORM %_FUNCNAME%, _VALUE; を実行する。
;_LIST  対象の連想配列（文字列）
;_FUNCNAME    実行する関数名(CALLFORM %_FUNCNAME%, _VALUE)
;RESULT       特になし
;================================================
@LIST_FOREACH(_LIST, _FUNCNAME)
#DIMS _LIST
#DIMS _FUNCNAME
#DIM _KEYCOUNT
#DIM _CNT
#DIMS _LIST_ELEMENT_P,_LIST_MAX ;ERHの変数を使うとFOREACH中に他の配列のSORTとかできなくなるので。再帰の需要はたぶんないからDYNAMICにはしない

SPLIT _LIST, ",", _LIST_ELEMENT_P
IF RESULT > _LIST_MAX
	THROW _List.ERB:リストの要素数が多すぎる→%_LIST%
ENDIF

_KEYCOUNT = RESULT-1 ;末尾が,なのでSPLITした末端は空文字列になる
IF _KEYCOUNT <= 0
	RETURN
ENDIF
FOR _CNT,0,_KEYCOUNT
	CALLFORM %_FUNCNAME%, _LIST_ELEMENT_P:_CNT
NEXT
RETURN


code:
;LIST関連で用いる一時変数

#DIM CONST _LIST_MAX = 300 ;必要に応じて適宜増やしてください
#DIMS _LIST_LEFT
#DIMS _LIST_RIGHT
#DIM _LIST_INDEX_COMMA
#DIM _LIST_INDEX_LEFT
#DIM _LIST_INDEX_RIGHT
#DIM _LIST_LENGTH

#DIMS _LIST_ELEMENT,_LIST_MAX


code:
;----------------------
; 汎用関数
;----------------------
@IS_FALL(CHARA_ID)
#FUNCTION
#DIM CHARA_ID
SIF TALENT:CHARA_ID:恋慕 == 1 || TALENT:CHARA_ID:親愛 == 1 || TALENT:CHARA_ID:服従 == 1 || TALENT:CHARA_ID:隷属 == 1
	RETURNF 1
RETURNF 0

@ASK_YESNO(MESSAGE)
#DIMS MESSAGE

$INPUT_LOOP
PRINTFORML %MESSAGE%
PRINTBUTTON "[0] はい", 0
PRINTL
PRINTBUTTON "[1] いいえ", 1
INPUT
IF RESULT == 0
	RETURN 1
ELSEIF RESULT == 1
	RETURN 0
ELSE
	GOTO INPUT_LOOP
ENDIF

@ASK_SELECT(MESSAGE, SELECT1, SELECT2)
#DIMS MESSAGE
#DIMS SELECT1
#DIMS SELECT2

$INPUT_LOOP
PRINTFORML %MESSAGE%
PRINTBUTTON @"[1] %SELECT1%", 1
PRINTL
PRINTBUTTON @"[2] %SELECT2%", 2
PRINTL

INPUT
IF RESULT == 1
	RETURN 1
ELSEIF RESULT == 2
	RETURN 2
ELSE
	GOTO INPUT_LOOP
ENDIF

@GET_BUSTSIZE_STR(BREAST_SIZE)
#FUNCTIONS
#DIM BREAST_SIZE
SELECTCASE BREAST_SIZE
	CASE -2
		RETURNF "絶壁"
	CASE -1
		RETURNF "貧乳"
	CASE 0
		RETURNF "並乳"
	CASE 1
		RETURNF "巨乳"
	CASE 2
		RETURNF "爆乳"
	CASE 3
		RETURNF "超乳"
	CASE 4
		RETURNF "奇乳"
ENDSELECT

;タイプした風に引数の文字列を一文字ずつ出力する関数
@TYPE_PRINT(STRING, WAITTIME)
#DIMS STRING
#DIM WAITTIME
#DIM DYNAMIC STR_CNT

VARSET LOCALS
FOR LOCAL, 0, STRLENSU(STRING) + 1
	SIF LOCAL > 1
		CLEARLINE 1
	TWAIT WAITTIME, 1
	LOCALS '= LOCALS + CHARATU(STRING, LOCAL)
	PRINTFORM %LOCALS%
NEXT
CLEARLINE 1
RETURN

;-------------------------------------------------
; マウスクリックの座標を起点にオプション選択メニューの画面を表示する
;   引数:  _LIST_OPTIONS=オプション名一覧(LIST形式)
;   戻り値: オプション番号(0番目から開始)。オプションが選択されなかった場合は-1を返却する。
; 引数を文字列で直指定する場合は、EMUERAのLIST形式の仕様上"オプション1,オプション2,"のように末尾の,が必要
;-------------------------------------------------
@OPTION_POPUP(_LIST_OPTIONS)
#DIMS DYNAMIC _LIST_OPTIONS
#DIMS DYNAMIC ATR
#DIMS DYNAMIC BODY
#DIMS DYNAMIC HTML

VARI I
FOR I, 0, LIST_COUNT(_LIST_OPTIONS)
    BODY += @"<button value = '[OPTION:{I}]'>[%LIST_GET(_LIST_OPTIONS,I)%]</button>"
    BODY += "
"
NEXT
BODY += @"
"
BODY += @"<button value = '[EXIT:1]'>[閉じる]</button>"
BODY += @"

"
ATR += @"
"

HTML = %ATR + BODY + "
"%
CLEARLINE 1
HTML_PRINT HTML, 1

WHILE 1
    INPUTS ,1
    VARS INPUT_VALUES
    VARI MOUSE_BTN = RESULT:1
    INPUT_VALUES = %RESULTS%

    IF INPUT_VALUES != ""
        CLEARLINE 1
    ELSE
        BREAK
    ENDIF
    ;クリック時処理
    IF MOUSE_BTN == 1
        IF DIC_CONTAINSKEY(INPUT_VALUES, "OPTION")
            CLEARLINE 1
            RETURN DIC_GETINT(INPUT_VALUES, "OPTION")
            BREAK
        ENDIF
        IF DIC_CONTAINSKEY(INPUT_VALUES, "EXIT")
            CLEARLINE 1
            BREAK
        ENDIF
        ;右クリック時処理
    ELSEIF MOUSE_BTN == 2
        CLEARLINE 1
        BREAK
    ENDIF
WEND

RETURN -1


code:
;≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
; 複数のウィンドウを管理し、まとめて描画するための関数群
;
;	関数名	:	WndMgr_～～(), FuncWndMgr_～～()
;
;	※ 要 TagSetText.ERB
;
;--------------------------------
; 注意事項)
;	・@WndMgr_Display()の nDisplayWidth はヴァリアントの設定に応じて変更すること
;
;	・ウィンドウは100個まで作成可能（WindowDrawer.ERHのDEF_WINDOW_DRAWER_MAX_WND_LENGTHで設定）
;
;	・一画面に収まる程度のサイズでの使用を想定している
;
;	・枠ありにする場合は、その分ウィンドウの大きさを増やすこと（縦:+2,横:+4）
;
;	・また、太字などのフォント修飾を使用すると文字の横幅が少し増えるため、ウィンドウサイズには少し余裕を持たせると良い
;
;	・枠無しの場合でも、描画の左位置を設定するために半角スペースを設定している。そのため枠無しウィンドウの左側に半角スペースが一文字設定される。
;
;	・ウィンドウの背景は全て半角スペースのボタンとなっている。これはウィンドウが重なった際に、ウィンドウに隠れている下のウィンドウのボタンが押下できてしまう現象を防ぐため
;	　そのため、INPUTSなどの処理では、ウィンドウ枠内をクリックすると、半角スペースが入力されたとしてINPUTSを抜けてしまう。
;	　INPUTS使用時は半角スペースの入力を無効とし再入力させるなどして対応すること。
;
;	・ウィンドウが重なる状態では、上にウィンドウが重なるウィンドウでは画像の描画が無効化される。
;	　これは下のウィンドウで描画される画像が、上のウィンドウを突きぬけてしまう現象を回避するための処置。
;	　複数行に跨る画像描画を禁止し、resourcesのcsv登録を一行単位で行うようにすれば現象は発生しなくなるが、画像登録の手間と現象によるデメリットを考慮し、仕様とした。
;
;--------------------------------
; 使い方)
;	以下のような流れで複数のウィンドウを生成しまとめて描画する。
;	ウィンドウの領域が重なっていた場合、基本的には新しく生成したウィンドウが上になる。
;	ウィンドウ内に表示する文字列はタグ指定することで、色変更やボタン化を行える。タグ指定については TagSetText.ERB を参照。
;	----------------
;		ウィンドウ生成 → 行数を指定して文字列を設定 → 行数を指定して文字列を設定 → 行数を指定して文字列を設定
;		 → ウィンドウ生成 → 行数を指定して文字列を設定
;		 → 全てのウィンドウを描画
;		 → 生成したウィンドウを破棄
;	----------------
;
;--------------------------------
; サンプル)
;	以下のコードは2つのウィンドウを描画するコードです
;		CALL WndMgr_CreateWindow( 0, 0, 0, 32, 10, 1 )			; ウィンドウを生成（ID=0, 左上Ｘ値=0, 左上Ｙ値=0, 幅=32, 高さ=10, 枠あり）
;		CALL WndMgr_TextSet( 0, 0, "ウィンドウ０" )				; 「ID=0」のウィンドウの 0 行目の文字列を "ウィンドウ１" に設定
;		CALL WndMgr_TextSet( 0, 1, "あいうえお" )				; 「ID=0」のウィンドウの 1 行目の文字列を "あいうえお" に設定
;		CALL WndMgr_CreateWindow( 1, 36, 2, 32, 10, 1 )			; ウィンドウを生成（ID=1, 左上Ｘ値=36, 左上Ｙ値=2, 幅=32, 高さ=10, 枠あり）
;		CALL WndMgr_TextSet( 1, 0, "ウィンドウ１" )				; 「ID=1」のウィンドウの 0 行目の文字列を "ウィンドウ２" に設定
;		CALL WndMgr_TextSet( 1, 1, "かきくけこ" )				; 「ID=1」のウィンドウの 1 行目の文字列を "かきくけこ" に設定
;		CALL WndMgr_DisplayAll()								; ウィンドウ０とウィンドウ１を描画する
;		CALL WndMgr_DestroyWindow( 0 )							; ウィンドウを破棄する
;		CALL WndMgr_DestroyWindow( 1 )							; ウィンドウを破棄する
;≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

;================================================================
; 未生成のウィンドウIDを取得する
;--------------------------------
;--------------------------------
;[戻り値など]
;	RESULT:0	: 未生成（CREATEされていない）ウィンドウIDの内、最も若いIDを返す。
;				  未生成のウィンドウIDがない場合は -1 を返す
;================================================================
@WndMgr_VacantId()
#DIM nWndId

FOR nWndId, 0, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
	CALL WndMgr_WindowMgrMain( "EXIST", nWndId, 0, "" )
	SIF RESULT == 0
		RETURN nWndId
NEXT

DEBUGPRINTFORML ★★★ Windowの領域に空きがありません
RETURN -1

;================================================================
; 生成済みのウィンドウIDのリストを取得する
;--------------------------------
;--------------------------------
;[戻り値など]
;	RESULT:0	: 生成済みのウィンドウIDの個数
;	RESULT:1~	: 生成済みのウィンドウIDのリスト
;================================================================
@WndMgr_CheckExistWindow()
#DIM nWndId
#DIM arrWndIdList, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
#DIM nIdx

nIdx = 0
VARSET arrWndIdList, -1
FOR nWndId, 0, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
	CALL WndMgr_WindowMgrMain( "EXIST", nWndId, 0, "" )
	IF RESULT == 1
		arrWndIdList:nIdx = nWndId
		nIdx += 1
	ENDIF
NEXT

VARSET RESULT, -1
ARRAYCOPY "arrWndIdList", "RESULT"
ARRAYSHIFT RESULT, 1, 0
RESULT:0 = nIdx

RETURN RESULT

;================================================================
; 表示中の有効なウィンドウに存在するボタン情報の取得/設定
;--------------------------------
;	strMode				: 処理モード（"GET"or"SET"）
;	arrButtonValue		: (REF) 表示中の有効なウィンドウに存在するボタンのボタン値
;	nButtonCount		: (REF) arrButtonValueの有効値数
;--------------------------------
;[戻り値など]
;	strMode="GET"指定した場合、「arrButtonValue,nButtonCount」に有効なボタンの情報が格納される
;================================================================
@WndMgr_ButtonInfo( strMode, arrButtonValue, nButtonCount )
#DIMS strMode
#DIMS REF arrButtonValue, 0
#DIM REF  nButtonCount

#DIMS arrButtonValueMem, 2000
#DIM  nButtonCountMem
#DIM  nLoop

SELECTCASE strMode
	CASE "GET"
		VARSET arrButtonValue, ""
		ARRAYCOPY "arrButtonValueMem", "arrButtonValue"
		nButtonCount = nButtonCountMem

	CASE "SET"
		VARSET arrButtonValueMem, ""
		nButtonCountMem = 0
		; 重複した値があるかもしれないので、チェックしながら記録
		FOR nLoop, 0, MIN( VARSIZE( "arrButtonValueMem" ), nButtonCount )
			LOCALS '= arrButtonValue:nLoop
			IF STRLENS(LOCALS) > 0
				IF FINDELEMENT(arrButtonValueMem, LOCALS, 0, VARSIZE( "arrButtonValueMem" ), 1) == -1
					arrButtonValueMem:nButtonCountMem '= LOCALS
					nButtonCountMem += 1
				ENDIF
			ENDIF
		NEXT
		;			DEBUGPRINTFORML 　debug - WndMgr_ButtonInfo() 有効ボタンデータ({nButtonCountMem}個)：
		;			DEBUGPRINTFORM
		;			FOR nLoop, 0, nButtonCountMem
		;				DEBUGPRINTFORM [%arrButtonValueMem:nLoop%],
		;			NEXT
		;			DEBUGPRINTFORML
ENDSELECT

RETURN 0

;================================================================
; 指定したウィンドウと描画領域が（一部でも）重なっているウィンドウのリストを取得する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	ARG:0		: 非表示のウィンドウは対象外にする
;--------------------------------
;[戻り値など]
;	RESULT:0	: ウィンドウIDの個数
;	RESULT:1~	: ウィンドウIDのリスト
;================================================================
@WndMgr_CheckOverlapWnd( nWndId, ARG:0 )
#DIM  nWndId

#DIM  nWndA_Left
#DIM  nWndA_Top
#DIM  nWndA_Rigth
#DIM  nWndA_Bottom

#DIM  nWndB_Left
#DIM  nWndB_Top
#DIM  nWndB_Rigth
#DIM  nWndB_Bottom

#DIM  arrWndIdList, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
#DIM  nWndCount
#DIM  arrExistWndIdList, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
#DIM  nExistWndCnt

#DIM  nLoop
#DIM  nCheck

CALL WndMgr_GetRectangle( nWndId )
nWndA_Left   = RESULT:0
nWndA_Top    = RESULT:1
nWndA_Rigth  = RESULT:0 + RESULT:2 - 1
nWndA_Bottom = RESULT:1 + RESULT:3 - 1

VARSET arrExistWndIdList, -1
CALL WndMgr_CheckExistWindow()
nExistWndCnt = RESULT:0
ARRAYCOPY "RESULT", "arrExistWndIdList"
ARRAYSHIFT arrExistWndIdList, -1, -1

nWndCount = 0
VARSET arrWndIdList, -1
FOR nLoop, 0, nExistWndCnt
	nCheck = arrExistWndIdList:nLoop
	SIF nCheck < 0
		CONTINUE
	IF ARG:0 == 1
		; 非表示ウィンドウは対象外
		CALL WndMgr_GetPropertyNum( nCheck, PropIdx_WndHidden )
		SIF RESULT == 1
			CONTINUE
	ENDIF
	; ウィンドウの表示位置とサイズを取得
	CALL WndMgr_GetRectangle( nCheck )
	nWndB_Left   = RESULT:0
	nWndB_Top    = RESULT:1
	nWndB_Rigth  = RESULT:0 + RESULT:2 - 1
	nWndB_Bottom = RESULT:1 + RESULT:3 - 1
	; ウィンドウＡの左端がウィンドウＢの右端よりも右なら重なっていない
	; ウィンドウＡの右端がウィンドウＢの左端よりも左なら重なっていない
	; ウィンドウＡの上端がウィンドウＢの下端よりも下なら重なっていない
	; ウィンドウＡの下端がウィンドウＢの上端よりも上なら重なっていない
	SIF nWndA_Left   > nWndB_Rigth
		CONTINUE
	SIF nWndA_Rigth  < nWndB_Left
		CONTINUE
	SIF nWndA_Top    > nWndB_Bottom
		CONTINUE
	SIF nWndA_Bottom < nWndB_Top
		CONTINUE
	arrWndIdList:nWndCount = nCheck
	nWndCount += 1
NEXT

VARSET RESULT, -1
ARRAYCOPY "arrWndIdList", "RESULT"
ARRAYSHIFT RESULT, 1, 0
RESULT:0 = nWndCount

RETURN RESULT

;================================================================
; ウィンドウが他ウィンドウの背後にあるかのプロパティ値をまとめて設定する
;--------------------------------
;[引数]
;	nWindowCnt				: ウィンドウ数
;	arrDisplayPriority		: 描画対象ウィンドウ（ウィンドウIDを配列で指定する。ここで指定した順番でウィンドウの描画が行われる）
;								※ 若い位置のウィンドウほど下になる
;--------------------------------
;[戻り値など]
;================================================================
@WndMgr_SetBehindProp( nWindowCnt, arrDisplayPriority )
#DIM  nWindowCnt
#DIM REF arrDisplayPriority, 0

#DIM  nWindowCnt_Mem					; 再チェック防止用の前回の対象ウィンドウ情報を保持する
#DIM  arrDisplayPriority_Mem, 1000		; 同上

#DIM  arrWndIdOverlap, 200
#DIM  nOverlapWndCount
#DIM  nTargetWndId

#DIM  nLoop
#DIM  nCheck

; 対象ウィンドウ情報を前回と今回で比較（同じならチェックする必要はない）
IF nWindowCnt_Mem == nWindowCnt
	nCheck = 0
	FOR nLoop, 0, nWindowCnt
		IF arrDisplayPriority_Mem:nLoop != arrDisplayPriority:nLoop
			BREAK
		ENDIF
		nCheck += 1
	NEXT
	; 対象ウィンドウ情報を前回と今回で同じなら、何もせずに抜ける
	IF nCheck == nWindowCnt
		RETURN
	ENDIF
ENDIF

; 全てのウィンドウの他ウィンドウの背後にあるかのプロパティ値をリセットする
FOR nLoop, 0, nWindowCnt
	CALL WndMgr_SetPropertyNum( arrDisplayPriority:nLoop, PropIdx_WndBehindWindow, 0 )
NEXT

; 他ウィンドウの背後にあるかのチェック
FOR nLoop, 0, nWindowCnt
	nTargetWndId = arrDisplayPriority:nLoop
	; 重なっているウィンドウを取得
	VARSET arrWndIdOverlap, -1
	CALL WndMgr_CheckOverlapWnd( nTargetWndId, 1 )
	nOverlapWndCount = RESULT:0
	ARRAYCOPY "RESULT", "arrWndIdOverlap"
	ARRAYSHIFT arrWndIdOverlap, -1, -1
	; 重なっているウィンドウが、チェック対象ウィンドウよりも上に表示されるウィンドウかをチェックする
	FOR nCheck, 0, nOverlapWndCount
		LOCAL = FINDELEMENT( arrDisplayPriority, arrWndIdOverlap:nCheck )
		IF LOCAL > nLoop
			CALL WndMgr_SetPropertyNum( arrDisplayPriority:nLoop, PropIdx_WndBehindWindow, 1 )		; 上に重なっているウィンドウが存在するので、チェック対象ウィンドウは「他ウィンドウの背後にある」
			BREAK
		ENDIF
	NEXT
NEXT

; 今回のチェック対象情報を記憶する
nWindowCnt_Mem = nWindowCnt
VARSET arrDisplayPriority_Mem, -1
ARRAYCOPY "arrDisplayPriority", "arrDisplayPriority_Mem"

RETURN

;================================================================
; 生成したウィンドウを描画する
;--------------------------------
;	nBtnIsNum				: ボタンを数値ボタンで表示するフラグ（0=文字列ボタン, 1=数値ボタン）
;================================================================
@WndMgr_DisplayAll( nBtnIsNum = 0 )
#DIM  nBtnIsNum

#DIM  nWindowCnt
#DIM  arrDisplayPriority, DEF_WINDOW_DRAWER_MAX_WND_LENGTH = -1
#DIM  nLoop
#DIM  nCheck

VARSET arrDisplayPriority, -1
CALL WndMgr_CheckExistWindow()
nWindowCnt = RESULT:0
ARRAYCOPY "RESULT", "arrDisplayPriority"
ARRAYSHIFT arrDisplayPriority, -1, -1

CALL WndMgr_Display( nWindowCnt, arrDisplayPriority, nBtnIsNum )

;================================================================
; 生成したウィンドウの内、指定したものだけを描画する
;--------------------------------
;	nWindowCnt				: ウィンドウ数
;	arrDisplayPriority		: 描画対象ウィンドウ（ウィンドウIDを配列で指定する。ここで指定した順番でウィンドウの描画が行われる）
;								※ 若い位置のウィンドウほど下になる
;	nBtnIsNum				: ボタンを数値ボタンで表示するフラグ（0=文字列ボタン, 1=数値ボタン）
;--------------------------------
;[戻り値など]
;================================================================
@WndMgr_Display( nWindowCnt, arrDisplayPriority, nBtnIsNum = 0 )
#LOCALSSIZE 10
#DIM  nWindowCnt
#DIM REF arrDisplayPriority, 0
#DIM  nBtnIsNum

SELECTCASE DEF_WINDOW_DRAWER_MODE
	CASE 0
		CALL WndMgr_Display_ModeHtml( nWindowCnt, arrDisplayPriority, nBtnIsNum )		; HTML命令使用版
	CASE 1
		CALL WndMgr_Display_ModePrint( nWindowCnt, arrDisplayPriority, nBtnIsNum )		; PRINT系命令使用版
ENDSELECT

RETURN

;================================================================
; 生成したウィンドウの内、指定したものだけを描画する
;	(HTML版)
;--------------------------------
;	nWindowCnt				: ウィンドウ数
;	arrDisplayPriority		: 描画対象ウィンドウ（ウィンドウIDを配列で指定する。ここで指定した順番でウィンドウの描画が行われる）
;								※ 若い位置のウィンドウほど下になる
;	nBtnIsNum				: ボタンを数値ボタンで表示するフラグ（0=文字列ボタン, 1=数値ボタン）
;--------------------------------
;[戻り値など]
;================================================================
@WndMgr_Display_ModeHtml( nWindowCnt, arrDisplayPriority, nBtnIsNum = 0 )
#LOCALSSIZE 10
#DIM  nWindowCnt
#DIM REF arrDisplayPriority, 0
#DIM  nBtnIsNum

#DIMS arrDisplayText, 200
#DIM  nLoop
#DIM  nWndId
#DIM  nWndLine
#DIM  nCheckLine
#DIM  nMaxLine

#DIM  nPosX
#DIM  nPosY
#DIM  nSizeW
#DIM  nSizeH
#DIM  nDisable

#DIMS strPrintText
#DIMS arrButtonValue, 1000
#DIM  nButtonCount

; ウィンドウが背後にあるかどうかのプロパティ値を更新する
CALL WndMgr_SetBehindProp( nWindowCnt, arrDisplayPriority )

VARSET arrButtonValue, ""
nButtonCount = 0

nMaxLine = 0
VARSET arrDisplayText, ""

; 全てのウィンドウの描画内容を１行ずつタグ指定文字列にする
FOR nLoop, 0, nWindowCnt
	nWndId = arrDisplayPriority:nLoop
	SIF nWndId < 0
		CONTINUE
	CALL WndMgr_Exist( nWndId )
	SIF RESULT == 0
		CONTINUE
	CALL WndMgr_GetPropertyNum( nWndId, PropIdx_WndHidden )
	SIF RESULT == 1
		CONTINUE

	CALL WndMgr_GetRectangle( nWndId )
	nPosX   = RESULT:0
	nPosY   = RESULT:1
	nSizeW  = RESULT:2
	nSizeH  = RESULT:3
	SIF nSizeW <= 0 || nSizeH <= 0
		CONTINUE

	CALL WndMgr_GetPropertyNum( nWndId, PropIdx_WndDisabled )
	nDisable = RESULT

	; 表示用テキストの生成
	CALL WndMgr_WindowMgrMain( "PRINT_TEXT_CREATE", nWndId, 0, "" )

	;DEBUGPRINTFORML check WndMgr_Display() PrintWndID={nWndId}
	FOR nWndLine, 0, nSizeH
		nCheckLine = nPosY + nWndLine
		SIF nCheckLine < 0
			CONTINUE
		CALL WndMgr_WindowMgrMain( "PRINT_TEXT_GET", nWndId, nWndLine, "" )
		strPrintText '= RESULTS:0
		arrDisplayText:nCheckLine += strPrintText
		nMaxLine = MAX( nMaxLine, nCheckLine )

		; ボタン情報の取得
		IF nDisable == 0
			CALL WndMgr_WindowMgrMain( "TEXT_GET", nWndId, nWndLine, "" )
			LOCAL = FuncTagSetText_GetButtonData( RESULTS )
			FOR LOCAL:1, 0, LOCAL:0
				arrButtonValue:nButtonCount '= RESULTS:(LOCAL:1)
				nButtonCount += 1
			NEXT
		ENDIF
	NEXT
NEXT

; 全てのウィンドウの描画内容をまとめたタグ指定文字列を描画する
FOR nCheckLine, 0, nMaxLine + 1
	IF STRLENS( arrDisplayText:nCheckLine ) > 0
		;DEBUGPRINTFORML arrDisplayText:nCheckLine = %arrDisplayText:nCheckLine%
		HTML_PRINT @"<nobr>%arrDisplayText:nCheckLine%</nobr>"
	ELSE
		HTML_PRINT @"<nobr> </nobr>"
	ENDIF
	;DEBUGPRINTFORML debug - WndMgr_Display_ModeHtml() 「%arrDisplayText:nCheckLine%」
NEXT

; 表示中の有効なボタン情報の登録
CALL WndMgr_ButtonInfo( "SET", arrButtonValue, nButtonCount )

RETURN

;================================================================
; 生成したウィンドウの内、指定したものだけを描画する
;--------------------------------
;	nWindowCnt				: ウィンドウ数
;	arrDisplayPriority		: 描画対象ウィンドウ（ウィンドウIDを配列で指定する。ここで指定した順番でウィンドウの描画が行われる）
;								※ 若い位置のウィンドウほど下になる
;	nBtnIsNum				: ボタンを数値ボタンで表示するフラグ（0=文字列ボタン, 1=数値ボタン）
;--------------------------------
;[戻り値など]
;================================================================
@WndMgr_Display_ModePrint( nWindowCnt, arrDisplayPriority, nBtnIsNum = 0 )
#LOCALSSIZE 10
#DIM  nWindowCnt
#DIM REF arrDisplayPriority, 0
#DIM  nBtnIsNum

#DIM  nDisplayWidth

#DIMS arrDisplayText, 200
#DIM  nLoop
#DIM  nWndId
#DIM  nWndLine
#DIM  nCheckLine
#DIM  nMaxLine

#DIM  nPosX
#DIM  nPosY
#DIM  nSizeW
#DIM  nSizeH
#DIM  nDisable

#DIMS strPrintText
#DIMS arrButtonValue, 1000
#DIM  nButtonCount

; ウィンドウが背後にあるかどうかのプロパティ値を更新する
CALL WndMgr_SetBehindProp( nWindowCnt, arrDisplayPriority )

VARSET arrButtonValue, ""
nButtonCount = 0

nDisplayWidth = 2 * CLIENTWIDTH() / GETCONFIG("フォントサイズ")		; 1行に出力できる文字数（MSゴシックの半角）

nMaxLine = 0
VARSET arrDisplayText, ""

; 全てのウィンドウの描画内容を１行ずつタグ指定文字列にする
FOR nLoop, 0, nWindowCnt
	nWndId = arrDisplayPriority:nLoop
	SIF nWndId < 0
		CONTINUE
	CALL WndMgr_Exist( nWndId )
	SIF RESULT == 0
		CONTINUE
	CALL WndMgr_GetPropertyNum( nWndId, PropIdx_WndHidden )
	SIF RESULT == 1
		CONTINUE

	CALL WndMgr_GetRectangle( nWndId )
	nPosX   = RESULT:0
	nPosY   = RESULT:1
	nSizeW  = RESULT:2
	nSizeH  = RESULT:3
	SIF nSizeW <= 0 || nSizeH <= 0
		CONTINUE

	CALL WndMgr_GetPropertyNum( nWndId, PropIdx_WndDisabled )
	nDisable = RESULT

	; 表示用テキストの生成
	CALL WndMgr_WindowMgrMain( "PRINT_TEXT_CREATE", nWndId, 0, "" )

	;DEBUGPRINTFORML check WndMgr_Display() PrintWndID={nWndId}
	FOR nWndLine, 0, nSizeH
		VARSET LOCALS, ""
		nCheckLine = nPosY + nWndLine
		SIF nCheckLine < 0
			CONTINUE
		IF nPosX >= 0
			CALLF TAG_PRINT_SHAPE( arrDisplayText:nCheckLine, nPosX, 1 )
			LOCALS:0 '= RESULTS:0
			CALLF TAG_PRINT_SHAPE( arrDisplayText:nCheckLine, nPosX + nSizeW, 0 )
			LOCALS:1 '= RESULTS:1
			CALL WndMgr_WindowMgrMain( "PRINT_TEXT_GET", nWndId, nWndLine, "" )
			CALLF TAG_PRINT_SHAPE( RESULTS, nSizeW, 1 )
			LOCALS:2 '= RESULTS:0
		ELSE
			LOCALS:0 '= ""
			CALLF TAG_PRINT_SHAPE( arrDisplayText:nCheckLine, MAX( 0, nPosX + nSizeW ), 0 )
			LOCALS:1 '= RESULTS:1
			IF nSizeW > nPosX
				CALL WndMgr_WindowMgrMain( "PRINT_TEXT_GET", nWndId, nWndLine, "" )
				CALLF TAG_PRINT_SHAPE( RESULTS, ABS( nPosX ), 0 )
				LOCALS:2 '= RESULTS:1
			ELSE
				LOCALS:2 '= ""
			ENDIF
		ENDIF
		arrDisplayText:nCheckLine '= LOCALS:0 + LOCALS:2 + LOCALS:1
		nMaxLine = MAX( nMaxLine, nCheckLine )
		strPrintText '= LOCALS:2

		; ボタン情報の取得
		IF nDisable == 0
			LOCAL = FuncTagSetText_GetButtonData( strPrintText )
			FOR LOCAL:1, 0, LOCAL:0
				arrButtonValue:nButtonCount '= RESULTS:(LOCAL:1)
				nButtonCount += 1
			NEXT
		ENDIF
	NEXT
NEXT

; 全てのウィンドウの描画内容をまとめたタグ指定文字列を描画する
FOR nCheckLine, 0, nMaxLine + 1
	LOCALS '= TAG_PRINT_SHAPE( arrDisplayText:nCheckLine, nDisplayWidth, 1 )
	CALLF TAG_PRINT( LOCALS, (nBtnIsNum == 0 ? 0x01 # 0x05) )
NEXT

; 表示中の有効なボタン情報の登録
CALL WndMgr_ButtonInfo( "SET", arrButtonValue, nButtonCount )

RETURN

;================================================================
; ウィンドウが存在するかどうか
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;--------------------------------
;[戻り値など]
;		RESULT:0	: 0=存在しない, 1=存在する
;================================================================
@WndMgr_Exist( nWndId )
#DIM  nWndId

SIF nWndId < 0 || nWndId >= DEF_WINDOW_DRAWER_MAX_WND_LENGTH
	RETURN 0
; 指定したウィンドウ番号のウィンドウが生成済みかどうかをチェックする
CALL WndMgr_WindowMgrMain( "EXIST", nWndId, 0, "" )
RETURN RESULT

;================================================================
; ウィンドウを生成する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nLocX		: ウィンドウ座標（左上Ｘ値）
;	nLocY		: ウィンドウ座標（左上Ｙ値）
;	nWidth		: ウィンドウサイズ（幅）※枠を使用する場合、偶数で指定すること
;	nHeigth		: ウィンドウサイズ（高さ）
;	nExFlag		: その他の設定
;					0x01 : 枠あり（太枠。枠の分だけ記述できる領域が小さくなるので注意すること）
;					0x02 : 枠あり（細枠。枠の分だけ記述できる領域が小さくなるので注意すること）
;							※ 0x03の場合は細枠になる
;--------------------------------
;================================================================
@WndMgr_CreateWindow( nWndId, nLocX, nLocY, nWidth, nHeigth, nExFlag )
#DIM  nWndId
#DIM  nLocX
#DIM  nLocY
#DIM  nWidth
#DIM  nHeigth
#DIM  nExFlag

#DIM  nBorder

; 指定したウィンドウ番号のウィンドウが生成済みの場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 1
	THROW WndMgr_CreateWindow() : ウィンドウ（nWndId={nWndId}）は生成済みです
ENDIF

; ウィンドウを生成する
IF (nExFlag & 0x02)
	nBorder = 2
ELSEIF (nExFlag & 0x01)
	nBorder = 1
ELSE
	nBorder = 0
ENDIF
CALL WndMgr_WindowMgrMain( "CREATE", nWndId, 0, @"{nLocX},{nLocY},{nWidth},{nHeigth},{nBorder}" )

RETURN

;================================================================
; ウィンドウを破棄する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ, -1=生成済みの全ウィンドウ対象）
;--------------------------------
;================================================================
@WndMgr_DestroyWindow( nWndId )
#DIM  nWndId

#DIM  arrWndIdList, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
#DIM  nExistWndCnt
#DIM  nLoop

IF nWndId == -1
	CALL WndMgr_CheckExistWindow()
	nExistWndCnt = RESULT:0
	ARRAYSHIFT RESULT, -1, -1
	ARRAYCOPY "RESULT", "arrWndIdList"
ELSE
	nExistWndCnt = 1
	arrWndIdList:0 = nWndId
ENDIF

FOR nLoop, 0, nExistWndCnt
	;--------------------------------
	;※ 初期化としても使うかもしれないのでこのエラーチェックはコメントアウト
	;	; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
	;	CALL WndMgr_Exist( arrWndIdList:nLoop )
	;	IF RESULT == 0
	;		THROW CREATE_WINDOW() : ウィンドウ（nWndId={arrWndIdList:nLoop}）は未生成です
	;	ENDIF
	;--------------------------------

	; ウィンドウを破棄する
	CALL WndMgr_WindowMgrMain( "DESTROY", arrWndIdList:nLoop, 0, "" )
NEXT

RETURN

;================================================================
; ウィンドウの属性とテキストを初期化する
;	※ ウィンドウの位置,サイズ,枠設定は変化しない
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ, -1=生成済みの全ウィンドウ対象）
;--------------------------------
;================================================================
@WndMgr_ResetWindow( nWndId )
#DIM  nWndId

#DIM  arrWndIdList, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
#DIM  nExistWndCnt
#DIM  nLoop

IF nWndId == -1
	CALL WndMgr_CheckExistWindow()
	nExistWndCnt = RESULT:0
	ARRAYSHIFT RESULT, -1, -1
	ARRAYCOPY "RESULT", "arrWndIdList"
ELSE
	nExistWndCnt = 1
	arrWndIdList:0 = nWndId
ENDIF

FOR nLoop, 0, nExistWndCnt
	;--------------------------------
	;※ 初期化としても使うかもしれないのでこのエラーチェックはコメントアウト
	;	; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
	;	CALL WndMgr_Exist( arrWndIdList:nLoop )
	;	IF RESULT == 0
	;		THROW CREATE_WINDOW() : ウィンドウ（nWndId={arrWndIdList:nLoop}）は未生成です
	;	ENDIF
	;--------------------------------

	; ウィンドウの属性とテキストを初期化
	CALL WndMgr_WindowMgrMain( "RESET", arrWndIdList:nLoop, 0, "" )
NEXT

RETURN

;================================================================
; ウィンドウのタイトルを設定する
;	※ タイトルは枠線表示設定時に、右上の枠線上に表示される（┌タイトル────┐）
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	strText		: 設定する文字列（タグ指定文字列(TagSetText.ERBを参照)で指定可能）
;--------------------------------
;[戻り値など]
;================================================================
@WndMgr_WindowTitle( nWndId, strText )
#DIM  nWndId
#DIMS strText

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_TextSet() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; ウィンドウのタイトルを設定する
CALL WndMgr_WindowMgrMain( "TITLE", nWndId, 0, strText )

RETURN

;================================================================
; ウィンドウに表示する文字列を設定する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nLine		: 文字列を設定する行位置
;	strText		: 設定する文字列（タグ指定文字列(TagSetText.ERBを参照)で指定可能）
;--------------------------------
;================================================================
@WndMgr_TextSet( nWndId, nLine, strText )
#DIM  nWndId
#DIM  nLine
#DIMS strText

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_TextSet() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; ウィンドウに表示する文字列を設定する
CALL WndMgr_WindowMgrMain( "TEXT_SET", nWndId, nLine, strText )

RETURN

;================================================================
; ウィンドウに表示する文字列を追加する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nLine		: 文字列を設定する行位置
;	strText		: 設定する文字列（タグ指定文字列(TagSetText.ERBを参照)で指定可能）
;--------------------------------
;================================================================
@WndMgr_TextAdd( nWndId, nLine, strText )
#DIM  nWndId
#DIM  nLine
#DIMS strText

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_TextSet() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; ウィンドウに表示する文字列を設定する
CALL WndMgr_WindowMgrMain( "TEXT_ADD", nWndId, nLine, strText )

RETURN

;================================================================
; ウィンドウに設定されている文字列を全てクリアする
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ, -1=生成済みの全ウィンドウ対象）
;--------------------------------
;================================================================
@WndMgr_TextClear( nWndId )
#DIM  nWndId

#DIM  arrWndIdList, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
#DIM  nExistWndCnt
#DIM  nLoop

IF nWndId == -1
	CALL WndMgr_CheckExistWindow()
	nExistWndCnt = RESULT:0
	ARRAYSHIFT RESULT, -1, -1
	ARRAYCOPY "RESULT", "arrWndIdList"
ELSE
	nExistWndCnt = 1
	arrWndIdList:0 = nWndId
ENDIF

FOR nLoop, 0, nExistWndCnt
	;--------------------------------
	;※ 初期化としても使うかもしれないのでこのエラーチェックはコメントアウト
	;	; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
	;	CALL WndMgr_Exist( arrWndIdList:nLoop )
	;	IF RESULT == 0
	;		THROW CREATE_WINDOW() : ウィンドウ（nWndId={arrWndIdList:nLoop}）は未生成です
	;	ENDIF
	;--------------------------------

	; ウィンドウに設定されている文字列を全てクリア
	CALL WndMgr_WindowMgrMain( "TEXT_CLEAR", arrWndIdList:nLoop, 0, "" )
NEXT

RETURN

;================================================================
; ウィンドウの表示位置,サイズなどを変更する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nLocX		: ウィンドウ座標（左上Ｘ値）
;	nLocY		: ウィンドウ座標（左上Ｙ値）
;	nWidth		: ウィンドウサイズ（幅） ※枠を使用する場合、偶数で指定すること
;	nHeigth		: ウィンドウサイズ（高さ）
;	nExFlag		: その他の設定
;					0x01 : 枠あり（太枠。枠の分だけ記述できる領域が小さくなるので注意すること）
;					0x02 : 枠あり（細枠。枠の分だけ記述できる領域が小さくなるので注意すること）
;							※ 0x03の場合は細枠になる
;--------------------------------
;================================================================
@WndMgr_Rectangle( nWndId, nLocX, nLocY, nWidth, nHeigth, nExFlag )
#DIM  nWndId
#DIM  nLocX
#DIM  nLocY
#DIM  nWidth
#DIM  nHeigth
#DIM  nExFlag

#DIM  nBorder

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Rectangle() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; ウィンドウの表示位置などを再設定する
IF (nExFlag & 0x02)
	nBorder = 2
ELSEIF (nExFlag & 0x01)
	nBorder = 1
ELSE
	nBorder = 0
ENDIF
CALL WndMgr_WindowMgrMain( "RECTANGLE", nWndId, 0, @"{nLocX},{nLocY},{nWidth},{nHeigth},{nBorder}" )

RETURN

;================================================================
; ウィンドウの表示位置を変更する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nLocX		: ウィンドウ座標（左上Ｘ値）
;	nLocY		: ウィンドウ座標（左上Ｙ値）
;--------------------------------
;================================================================
@WndMgr_Move( nWndId, nLocX, nLocY )
#DIM  nWndId
#DIM  nLocX
#DIM  nLocY

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Move() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; 表示位置変更
CALL WndMgr_WindowMgrMain( "MOVE", nWndId, 0, @"{nLocX},{nLocY}" )

RETURN

;================================================================
; ウィンドウの属性を変更する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ, -1=生成済みの全ウィンドウ対象）
;	ARGS:0		: 設定する属性名称
;	ARG:0		: 設定値
;					ARGS="Border"			: ARG … 0=枠無し, 1=太枠, 2=細枠,
;					ARGS="Disabled"			: ARG … 0=ウィンドウ有効化, 1=ウィンドウ無効化（灰色表示、タグ無効化）
;					ARGS="BorderColor"		: ARG … ウィンドウの枠の色を指定する（-1で指定なし）
;					ARGS="Hide"				: ARG … 非表示フラグ（0=表示する, 1=非表示, ）
;					ARGS="LogButton"		: ARG … ログボタン有効化（0=無効化, 1=有効化, ）
;--------------------------------
;================================================================
@WndMgr_Attribute( nWndId, ARGS, ARG )
#DIM  nWndId
#DIM  nExFlag

#DIM  nPropIndex, 5
#DIM  nPropValue, 5

#DIM  arrWndIdList, DEF_WINDOW_DRAWER_MAX_WND_LENGTH
#DIM  nExistWndCnt
#DIM  nLoop

VARSET nPropIndex, -1
VARSET nPropValue, -1
SELECTCASE ARGS
	CASE "Border"
		nPropIndex:0 = PropIdx_WndBorder
		nPropValue:0 = ARG
	CASE "Disabled"
		nPropIndex:0 = PropIdx_WndDisabled
		nPropValue:0 = ARG
	CASE "BorderColor"
		nPropIndex:0 = PropIdx_WndBorderColor
		nPropValue:0 = ARG
		nPropIndex:1 = PropIdx_WndBorderColorSet
		nPropValue:1 = (ARG == -1 ? 0 # 1)
	CASE "Hide"
		nPropIndex:0 = PropIdx_WndHidden
		nPropValue:0 = ARG
	CASE "LogButton"
		nPropIndex:0 = PropIdx_WndLogButton
		nPropValue:0 = ARG
	CASEELSE
		THROW WndMgr_Attribute() : 属性名称が不正です(%ARGS%)
ENDSELECT

IF nWndId == -1
	CALL WndMgr_CheckExistWindow()
	nExistWndCnt = RESULT:0
	ARRAYSHIFT RESULT, -1, -1
	ARRAYCOPY "RESULT", "arrWndIdList"
ELSE
	nExistWndCnt = 1
	arrWndIdList:0 = nWndId
ENDIF

FOR nLoop, 0, nExistWndCnt
	; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
	CALL WndMgr_Exist( arrWndIdList:nLoop )
	IF RESULT == 0
		THROW WndMgr_Attribute() : ウィンドウ（nWndId={arrWndIdList:nLoop}）は未生成です
	ENDIF

	; 設定反映
	FOR LOCAL, 0, 5
		SIF nPropIndex:(LOCAL) == -1
			CONTINUE
		CALL WndMgr_WindowMgrMain( "PROPERTY_NUM_SET", arrWndIdList:nLoop, nPropIndex:(LOCAL), TOSTR( nPropValue:(LOCAL) ) )
	NEXT
NEXT

RETURN

;================================================================
; ウィンドウの表示位置、サイズを取得する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nPropIdx	: 取得したいプロパティIndex値（WindowDrawer.ERH参照）
;--------------------------------
;[戻り値など]
;		RESULT:0	: ウィンドウ座標Ｘ値
;		RESULT:1	: ウィンドウ座標Ｙ値
;		RESULT:2	: ウィンドウ幅
;		RESULT:3	: ウィンドウ高さ
;		RESULT:4	: ウィンドウ幅  (クライアント領域)
;		RESULT:5	: ウィンドウ高さ(クライアント領域)
;		RESULT:6	: 枠設定（0=枠無し, 1=枠あり, 2=枠あり(細枠), ）
;================================================================
@WndMgr_GetRectangle( nWndId )
#DIM  nWndId
#DIM  nPropIdx

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Move() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; 設定取得
RESULT:0 = m_arrWndPropN:nWndId:PropIdx_WndPosX
RESULT:1 = m_arrWndPropN:nWndId:PropIdx_WndPosY
RESULT:2 = m_arrWndPropN:nWndId:PropIdx_WndWidth
RESULT:3 = m_arrWndPropN:nWndId:PropIdx_WndHeight
RESULT:4 = m_arrWndPropN:nWndId:PropIdx_WndClientWidth
RESULT:5 = m_arrWndPropN:nWndId:PropIdx_WndClientHeight
RESULT:6 = m_arrWndPropN:nWndId:PropIdx_WndBorder

RETURN RESULT

;================================================================
; ウィンドウに設定されているボタン情報を取得する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;--------------------------------
;[戻り値など]
;		RESULT:0	: ボタン数
;		RESULTS:0~	: ボタンのボタン値
;================================================================
@WndMgr_GetButtonData( nWndId )
#DIM  nWndId

#DIMS arrButtonValue, 1000
#DIM  nButtonCount
#DIM  nSizeH
#DIM  nLoop
#DIM  nWndLine

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Move() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; 設定取得
CALL WndMgr_GetPropertyNum( nWndId, PropIdx_WndHeight )
nSizeH  = RESULT

VARSET arrButtonValue, ""
nButtonCount = 0

FOR nWndLine, 0, nSizeH
	CALL WndMgr_WindowMgrMain( "TEXT_GET", nWndId, nWndLine, "" )
	LOCAL = FuncTagSetText_GetButtonData( RESULTS )
	FOR nLoop, 0, LOCAL:0
		arrButtonValue:nButtonCount '= RESULTS:nLoop
		nButtonCount += 1
	NEXT
NEXT

VARSET RESULTS, ""
ARRAYCOPY "arrButtonValue", "RESULTS"
RETURN nButtonCount

;================================================================
; ウィンドウのプロパティ設定を取得する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nPropIdx	: 対象のプロパティIndex値（WindowDrawer.ERH参照）
;--------------------------------
;[戻り値など]
;	RESULT:0	: 指定したプロパティ値
;================================================================
@WndMgr_GetPropertyNum( nWndId, nPropIdx )
#DIM  nWndId
#DIM  nPropIdx

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Move() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; 設定取得
CALL WndMgr_WindowMgrMain( "PROPERTY_NUM_GET", nWndId, nPropIdx )

RETURN RESULT

;================================================================
; ウィンドウのプロパティ設定を取得する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nPropIdx	: 対象のプロパティIndex値（WindowDrawer.ERH参照）
;--------------------------------
;[戻り値など]
;	RESULT:0	: 指定したプロパティ値
;================================================================
@WndMgr_GetPropertyStr( nWndId, nPropIdx )
#DIM  nWndId
#DIM  nPropIdx

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Move() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; 設定取得
CALL WndMgr_WindowMgrMain( "PROPERTY_STR_GET", nWndId, nPropIdx )

RESULTS '= RESULTS
RETURN

;================================================================
; ウィンドウのプロパティ設定を変更する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nPropIdx	: 対象のプロパティIndex値（WindowDrawer.ERH参照）
;	ARG:0		: 設定値
;--------------------------------
;[戻り値など]
;	RESULT:0	: 指定したプロパティ値
;================================================================
@WndMgr_SetPropertyNum( nWndId, nPropIdx, ARG )
#DIM  nWndId
#DIM  nPropIdx

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Move() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; 設定取得
CALL WndMgr_WindowMgrMain( "PROPERTY_NUM_SET", nWndId, nPropIdx, TOSTR( ARG ) )

RETURN

;================================================================
; ウィンドウのプロパティ設定を変更する
;--------------------------------
;[引数]
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	nPropIdx	: 対象のプロパティIndex値（WindowDrawer.ERH参照）
;	ARGS:0		: 設定値
;--------------------------------
;[戻り値など]
;	RESULT:0	: 指定したプロパティ値
;================================================================
@WndMgr_SetPropertyStr( nWndId, nPropIdx, ARGS )
#DIM  nWndId
#DIM  nPropIdx

; 指定したウィンドウ番号のウィンドウが未生成の場合はエラーにする
CALL WndMgr_Exist( nWndId )
IF RESULT == 0
	THROW WndMgr_Move() : ウィンドウ（nWndId={nWndId}）は未生成です
ENDIF

; 設定取得
CALL WndMgr_WindowMgrMain( "PROPERTY_STR_SET", nWndId, nPropIdx, ARGS )

RETURN

;================================================================
;【内部処理用】
; ウィンドウの管理
;--------------------------------
;[引数]
;	strMode		: 処理内容
;					"EXIST"				: ウィンドウが生成されているか確認する
;					"CREATE"			: ウィンドウの生成
;					"DESTROY"			: ウィンドウの破棄
;					"MOVE"				: ウィンドウの位置を変更する
;					"RECTANGLE"			: ウィンドウの表示位置などを再設定する
;					"RESET"				: ウィンドウの属性と、テキストの初期化
;					"PROPERTY_NUM_GET"	: ウィンドウのプロパティ情報を取得する
;					"PROPERTY_NUM_SET"	: ウィンドウのプロパティ情報を設定する
;					"PROPERTY_STR_GET"	: ウィンドウのプロパティ情報を取得する
;					"PROPERTY_STR_SET"	: ウィンドウのプロパティ情報を設定する
;					"TEXT_CLEAR"		: ウィンドウに登録された文字列をすべてクリアする
;					"TEXT_SET"			: ウィンドウの指定した行位置に文字列を設定する
;					"TEXT_ADD"			: ウィンドウの指定した行位置に文字列を追加する
;					"TEXT_GET"			: ウィンドウの指定した行位置に設定されている文字列を取得する（表示用ではない文字列）
;					"PRINT_TEXT_CREATE"	: 表示用の文字列を生成する（"PRINT_TEXT_GET"で取得できるのは、ここで生成した文字列）
;					"PRINT_TEXT_GET"	: ウィンドウの指定した行位置の表示用の文字列を取得する
;					"TITLE"				: ウィンドウのタイトルを設定する          （枠あり時のみ有効）
;	nWndId		: ウィンドウＩＤ（0~=対象ウィンドウ）
;	ARG:0		: 処理内容によって変化
;	ARGS:0		: 処理内容によって変化
;--------------------------------
; 処理内容ごとの ARG:0,ARGS:0 の内容
;	strMode = "EXIST", "DESTROY"
;		ARG:0	: 未使用
;		ARGS:0	: 未使用
;
;	strMode = "CREATE", "RECTANGLE"
;		ARG:0	: 未使用
;		ARGS:0	: ウィンドウ情報をCSV形式で記述した文字列
;					（"ウィンドウ座標Ｘ値", "ウィンドウ座標Ｙ値", "ウィンドウ幅", "ウィンドウ高さ", "枠設定(0=枠無し, 1=枠あり, 2=枠あり(細枠), )" ）
;
;	strMode = "PROPERTY_NUM_GET", "PROPERTY_NUM_SET", "PROPERTY_STR_GET", "PROPERTY_STR_SET"
;		ARG:0	: 取得したいプロパティIndex値（WindowDrawer.ERH参照）
;		ARGS:0	: 設定値
;
;	strMode = "TEXT_SET", "TEXT_ADD"
;		ARG:0	: 文字列を設定する行位置
;		ARGS:0	: 設定する文字列
;
;	strMode = "TEXT_CLEAR"
;		ARG:0	: 未使用
;		ARGS:0	: 未使用
;
;	strMode = "PRINT_TEXT_GET"
;		ARG:0	: 取得する行位置
;		ARGS:0	: 未使用
;
;	strMode = "PRINT_TEXT_CREATE", "RESET"
;		ARG:0	: 未使用
;		ARGS:0	: 未使用
;--------------------------------
;[戻り値など]
;	strMode = "EXIST"の場合
;		RESULT:0	: 0=ウィンドウが生成されていない, 1=ウィンドウが生成されている
;
;	strMode = "PRINT_TEXT_GET"の場合
;		RESULTS:0	: 指定した行位置に設定されている文字列
;
;	strMode = "PROPERTY_NUM_GET"の場合
;		RESULT:0	: 指定したプロパティ値
;================================================================
@WndMgr_WindowMgrMain( strMode, nWndId, ARG, ARGS )
#LOCALSIZE 1000
#LOCALSSIZE 20
#DIMS DYNAMIC strMode
#DIM DYNAMIC  nWndId

#DIM DYNAMIC  nLoop
#DIM nWndTextLen = -1
#DIM nWndInfoLen = -1

IF nWndTextLen == -1
	VARSIZE m_arrWndText
	nWndTextLen = RESULT:1
ENDIF
IF nWndInfoLen == -1
	VARSIZE m_arrWndPropN
	nWndInfoLen = RESULT:1
ENDIF

SELECTCASE strMode
	CASE "CREATE"
		m_arrWndExsit:nWndId:0 = 1
		m_arrWndTitle:nWndId:0 '= ""
		; プロパティ値のリセット
		FOR nLoop, 0, nWndInfoLen
			m_arrWndPropN:nWndId:nLoop = 0
		NEXT
		; 登録テキストのリセット
		FOR nLoop, 0, nWndTextLen
			m_arrWndText:nWndId:nLoop '= ""
			m_arrWndTextPrint:nWndId:nLoop '= ""
		NEXT
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0
		; 表示位置などの設定
		CALL WndMgr_WindowMgrMain( "RECTANGLE", nWndId, ARG, ARGS )

	CASE "DESTROY"
		m_arrWndExsit:nWndId:0 = 0
		m_arrWndTitle:nWndId:0 '= ""
		; プロパティ値のリセット
		FOR nLoop, 0, nWndInfoLen
			m_arrWndPropN:nWndId:nLoop = 0
		NEXT
		; 登録テキストのリセット
		FOR nLoop, 0, nWndTextLen
			m_arrWndText:nWndId:nLoop '= ""
			m_arrWndTextPrint:nWndId:nLoop '= ""
		NEXT
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0

	CASE "RECTANGLE"
		; 表示位置などの設定
		VARSET LOCALS, ""
		SPLIT ARGS, ",", LOCALS
		FOR nLoop, 0, 5
			IF ISNUMERIC( LOCALS:nLoop ) == 0
				THROW WndMgr_WindowMgrMain() : 設定内容が不正です（strMode=%strMode%, ARGS=%ARGS%）
			ENDIF
		NEXT
		m_arrWndPropN:nWndId:PropIdx_WndPosX   = TOINT( LOCALS:0 )
		m_arrWndPropN:nWndId:PropIdx_WndPosY   = TOINT( LOCALS:1 )
		m_arrWndPropN:nWndId:PropIdx_WndWidth  = TOINT( LOCALS:2 )
		m_arrWndPropN:nWndId:PropIdx_WndHeight = TOINT( LOCALS:3 )
		m_arrWndPropN:nWndId:PropIdx_WndBorder = TOINT( LOCALS:4 )
		m_arrWndPropN:nWndId:PropIdx_WndClientWidth  = m_arrWndPropN:nWndId:PropIdx_WndWidth  - (m_arrWndPropN:nWndId:PropIdx_WndBorder == 0 ? 0 # 4)
		m_arrWndPropN:nWndId:PropIdx_WndClientHeight = m_arrWndPropN:nWndId:PropIdx_WndHeight - (m_arrWndPropN:nWndId:PropIdx_WndBorder == 0 ? 0 # 2)
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0

	CASE "MOVE"
		VARSET LOCALS, ""
		SPLIT ARGS, ",", LOCALS
		FOR nLoop, 0, 2
			IF ISNUMERIC( LOCALS:nLoop ) == 0
				THROW WndMgr_WindowMgrMain() : 設定内容が不正です（strMode=%strMode%, ARGS=%ARGS%）
			ENDIF
		NEXT
		m_arrWndPropN:nWndId:PropIdx_WndPosX   = TOINT( LOCALS:0 )
		m_arrWndPropN:nWndId:PropIdx_WndPosY   = TOINT( LOCALS:1 )

	CASE "RESET"
		; プロパティ値のリセット（表示位置と枠の設定を除く）
		FOR nLoop, 0, nWndInfoLen
			SELECTCASE nLoop
				CASE PropIdx_WndPosX, PropIdx_WndPosY, PropIdx_WndWidth, PropIdx_WndHeight, PropIdx_WndClientWidth, PropIdx_WndClientHeight, PropIdx_WndBorder
				CASEELSE
					m_arrWndPropN:nWndId:nLoop = 0
			ENDSELECT
		NEXT
		; 登録テキストのリセット
		FOR nLoop, 0, nWndTextLen
			m_arrWndText:nWndId:nLoop '= ""
			m_arrWndTextPrint:nWndId:nLoop '= ""
		NEXT
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0
		m_arrWndTitle:nWndId:0 '= ""

	CASE "PROPERTY_NUM_GET"
		RESULT:0 = m_arrWndPropN:nWndId:(ARG)
		RETURN RESULT:0

	CASE "PROPERTY_NUM_SET"
		m_arrWndPropN:nWndId:(ARG) = TOINT( ARGS )
		IF ARG == PropIdx_WndBorder
			m_arrWndPropN:nWndId:PropIdx_WndClientWidth  = m_arrWndPropN:nWndId:PropIdx_WndWidth  - (m_arrWndPropN:nWndId:PropIdx_WndBorder == 0 ? 0 # 4)
			m_arrWndPropN:nWndId:PropIdx_WndClientHeight = m_arrWndPropN:nWndId:PropIdx_WndHeight - (m_arrWndPropN:nWndId:PropIdx_WndBorder == 0 ? 0 # 2)
		ENDIF
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0

	CASE "PROPERTY_STR_GET"
		RESULTS:0 '= m_arrWndPropS:nWndId:(ARG)
		RETURN

	CASE "PROPERTY_STR_SET"
		m_arrWndPropS:nWndId:(ARG) '= ARGS

	CASE "TEXT_CLEAR"
		; 登録テキストのリセット
		FOR nLoop, 0, nWndTextLen
			m_arrWndText:nWndId:nLoop '= ""
			m_arrWndTextPrint:nWndId:nLoop '= ""
		NEXT
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0

	CASE "TEXT_SET"
		m_arrWndText:nWndId:(ARG) '= ARGS
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0

	CASE "TEXT_ADD"
		m_arrWndText:nWndId:(ARG) '= m_arrWndText:nWndId:(ARG) + ARGS
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0

	CASE "TEXT_GET"
		RESULTS:0 '= m_arrWndText:nWndId:(ARG)
		RETURN

	CASE "PRINT_TEXT_CREATE"
		IF m_arrWndSetTextPrint:nWndId:0 == 0
			CALL WndMgr_CreatePrintText( nWndId )		; 表示用テキストの生成
			m_arrWndSetTextPrint:nWndId:0 = 1
		ENDIF
		RETURN

	CASE "PRINT_TEXT_GET"
		; 表示用テキストが未生成の場合、生成する（※"PRINT_TEXT_CREATE"時の処理）
		IF m_arrWndSetTextPrint:nWndId:0 == 0
			CALL WndMgr_CreatePrintText( nWndId )		; 表示用テキストの生成
			m_arrWndSetTextPrint:nWndId:0 = 1
		ENDIF
		RESULTS:0 '= m_arrWndTextPrint:nWndId:(ARG)
		RETURN

	CASE "TITLE"
		m_arrWndTitle:nWndId:0 '= ARGS
		; 表示テキスト生成済みフラグ解除
		m_arrWndSetTextPrint:nWndId:0 = 0

	CASE "EXIST"
		RESULT:0 = m_arrWndExsit:nWndId:0
		RETURN RESULT:0

	CASEELSE
		DEBUGPRINTFORML ★★★ WndMgr_WindowMgrMain() : 処理内容の指定が不正です（strMode=%strMode%）

ENDSELECT

RETURN

;================================================================
;【内部処理用】
; 実際に表示する整形済みのテキストを作成する
;--------------------------------
;[引数]
;	nWndId						: ウィンドウＩＤ（0～9を指定する）
;--------------------------------
;================================================================
@WndMgr_CreatePrintText( nWndId )
#DIM  nWndId

SELECTCASE DEF_WINDOW_DRAWER_MODE
	CASE 0
		CALL WndMgr_CreatePrintText_Html( nWndId )
	CASE 1
		CALL WndMgr_CreatePrintText_Print( nWndId )
ENDSELECT

RETURN

;================================================================
;【内部処理用】
; 実際に表示する整形済みのテキストを作成する
;--------------------------------
;[引数]
;	nWndId						: ウィンドウＩＤ（0～9を指定する）
;--------------------------------
;================================================================
@WndMgr_CreatePrintText_Html( nWndId )
#DIM  nWndId

#DIMS arrWndTextBuf, 100

#DIMS arrBorderText, 8		; 左上, 上, 右上, 左下, 下, 右下, 左, 右,
#DIMS arrBorderColor, 2
#DIMS strInvlidColorText = "@C:0x333333@"

#DIMS arrPaddingSpace				; 後のウィンドウを目隠しするためのスペース埋め
#DIMS arrWndText_LineStartText, 3	; 0:先頭行, 1:最終行, 2:中間行

#DIM  nPosX
#DIM  nSizeW
#DIM  nSizeH
#DIM  nLineWidth

#DIM  nLoop
#DIMS strBuf
#DIMS CONST strBGColor = "#000000"

nPosX      = m_arrWndPropN:nWndId:PropIdx_WndPosX
nSizeW     = m_arrWndPropN:nWndId:PropIdx_WndWidth
nSizeH     = m_arrWndPropN:nWndId:PropIdx_WndHeight
nLineWidth = m_arrWndPropN:nWndId:PropIdx_WndClientWidth

SIF nSizeW <= 0 || nSizeH <= 0
	RETURN
SIF (m_arrWndPropN:nWndId:PropIdx_WndBorder > 0) && (nSizeW < 4 || nSizeH < 2)
	RETURN

; 枠の色
VARSET arrBorderColor, ""
IF (m_arrWndPropN:nWndId:PropIdx_WndBorder > 0)
	; 無効ウィンドウ / ウィンドウ枠の色 / それ以外
	IF (m_arrWndPropN:nWndId:PropIdx_WndDisabled == 1)
		arrBorderColor:0 '= strInvlidColorText
		arrBorderColor:1 '= "@/C@"
	ELSEIF (m_arrWndPropN:nWndId:PropIdx_WndBorderColorSet == 1)
		arrBorderColor:0 '= "@C:0x" + TOSTR( m_arrWndPropN:nWndId:PropIdx_WndBorderColor, "X6" ) + "@"
		arrBorderColor:1 '= "@/C@"
	ELSE
		VARSET arrBorderColor, ""
	ENDIF
ENDIF
; 枠線のテキスト
VARSET arrBorderText, ""
CALL WndMgr_GetWndBorderText( m_arrWndPropN:nWndId:PropIdx_WndBorder, arrBorderText )

; 行開始のテキスト
SELECTCASE m_arrWndPropN:nWndId:PropIdx_WndBorder
		; 枠無し
	CASE 0
		arrWndText_LineStartText:0 '= @"<font face='ＭＳ ゴシック'><nonbutton pos='{(nPosX-1) * 50}'> </nonbutton></font>"
		arrWndText_LineStartText:1 '= @"<font face='ＭＳ ゴシック'><nonbutton pos='{(nPosX-1) * 50}'> </nonbutton></font>"
		arrWndText_LineStartText:2 '= @"<font face='ＭＳ ゴシック'><nonbutton pos='{(nPosX-1) * 50}'> </nonbutton></font>"
		; 枠あり
	CASE 1, 2
		LOCALS:0 '= FuncTagSetText_ConvHtmlText( arrBorderColor:0 + arrBorderText:0 + arrBorderColor:1 )
		LOCALS:1 '= FuncTagSetText_ConvHtmlText( arrBorderColor:0 + arrBorderText:3 + arrBorderColor:1 )
		LOCALS:2 '= FuncTagSetText_ConvHtmlText( arrBorderColor:0 + arrBorderText:6 + arrBorderColor:1 )
		arrWndText_LineStartText:0 '= @"<font face='ＭＳ ゴシック'><nonbutton pos='{nPosX * 50}'>%LOCALS:0%</nonbutton></font>"
		arrWndText_LineStartText:1 '= @"<font face='ＭＳ ゴシック'><nonbutton pos='{nPosX * 50}'>%LOCALS:1%</nonbutton></font>"
		arrWndText_LineStartText:2 '= @"<font face='ＭＳ ゴシック'><nonbutton pos='{nPosX * 50}'>%LOCALS:2%</nonbutton></font>"
ENDSELECT

;--------------------------------
; テキスト部
;--------------------------------
; 登録テキストを整形
VARSET arrWndTextBuf, ""
FOR nLoop, 0, nSizeH
	arrWndTextBuf:nLoop '= m_arrWndText:nWndId:nLoop
NEXT
; HTMLテキストに変換
FOR nLoop, 0, nSizeH
	IF m_arrWndPropN:nWndId:PropIdx_WndDisabled == 1
		strBuf '= strInvlidColorText + FuncTagSetText_GetPlainText( arrWndTextBuf:nLoop ) + "@/C@"
	ELSE
		strBuf '= arrWndTextBuf:nLoop
		; ウィンドウが他のウィンドウの背後にある場合
		IF m_arrWndPropN:nWndId:PropIdx_WndBehindWindow == 1
			; 画像描画を無効にする
			WHILE 1
				LOCAL:0 = STRFINDU( strBuf, "@I:", 0 )
				SIF LOCAL:0 < 0
					BREAK
				LOCAL:1 = STRFINDU( strBuf, "@", LOCAL:0 + 1 )
				strBuf '= SUBSTRINGU( strBuf, LOCAL:0, LOCAL:1 - LOCAL:0 + 1 )
				LOCAL:0 = STRFINDU( strBuf, "@/I@", 0 )
				strBuf '= SUBSTRINGU( strBuf, LOCAL:0, 4 )
			WEND
		ENDIF
	ENDIF
	arrWndTextBuf:nLoop '= FuncTagSetText_ConvHtmlText( strBuf )
NEXT
; 枠線ありの場合の特殊な処理
SELECTCASE m_arrWndPropN:nWndId:PropIdx_WndBorder
		; 枠無し
	CASE 0
		; 太枠, 細枠
	CASE 1, 2
		; テキスト位置を1行下にずらす
		ARRAYSHIFT arrWndTextBuf, 1, ""

		; 先頭行
		LOCALS:0 '= FuncTagSetText_ConvHtmlText( arrBorderColor:0 + arrBorderText:0 + arrBorderText:1 * (nLineWidth / 2) + arrBorderText:2 + arrBorderColor:1 )
		arrWndTextBuf:0 += @"<font face='ＭＳ ゴシック'><nonbutton pos='{nPosX * 50}'>%LOCALS:0%</nonbutton></font>"
		;	先頭行の追加記述：タイトル
		IF STRLENS( m_arrWndTitle:nWndId:0 ) > 0
			LOCAL:0   = (nPosX + 2) * 50
			LOCALS:0 '= FuncTagSetText_ConvHtmlText( arrBorderColor:0 + FuncTagSetText_ConvHtmlText( m_arrWndTitle:nWndId:0 ) + arrBorderColor:1 )
			LOCAL:1   = STRLENS( FuncTagSetText_GetPlainText( m_arrWndTitle:nWndId:0 ) )
			LOCALS:1 '= @"<shape type='rect' param='0,0,{LOCAL:1 * 50},100' color='%strBGColor%' bcolor='%strBGColor%'>"
			arrWndTextBuf:0 += @"<nonbutton pos='{LOCAL:0}'>%LOCALS:1%</nonbutton><nonbutton pos='{LOCAL:0}'>%LOCALS:0%</nonbutton>"
		ENDIF

		; 最終行
		LOCALS:0 '= FuncTagSetText_ConvHtmlText( arrBorderColor:0 + arrBorderText:3 + arrBorderText:4 * (nLineWidth / 2) + arrBorderText:5 + arrBorderColor:1 )
		arrWndTextBuf:(nSizeH - 1) += @"<font face='ＭＳ ゴシック'><nonbutton pos='{nPosX * 50}'>%LOCALS:0%</nonbutton></font>"
		;	最終行の追加記述：ログ表示ボタン
		IF m_arrWndPropN:nWndId:PropIdx_WndLogButton == 1
			LOCAL = (nPosX + MAX(0, nLineWidth - 16)) * 50
			arrWndTextBuf:(nSizeH - 1) += @"<button value='l' pos='{LOCAL}'> [l] ログ表示 </button>"
		ENDIF

		; 中間行
		FOR nLoop, 1, nSizeH - 1
			LOCAL = (nPosX + nSizeW - 2) * 50
			LOCALS:0 '= FuncTagSetText_ConvHtmlText( arrBorderColor:0 + arrBorderText:7 + arrBorderColor:1 )
			arrWndTextBuf:nLoop += @"<font face='ＭＳ ゴシック'><nonbutton pos='{LOCAL}'>%LOCALS:0%</nonbutton></font>"
		NEXT

ENDSELECT

;--------------------------------
; 表示テキストに登録
;--------------------------------
; ウィンドウ背景を塗りつぶす
LOCALS:0 '= @"<button pos='{nPosX * 50}' value='%m_strWndBgBtnValue%'>"
LOCALS:1 '= @"<shape type='rect' param='0,0,{nSizeW *50},100' color='%strBGColor%' bcolor='%strBGColor%'>"
LOCALS:2 '= @"</button>"
FOR nLoop, 0, nSizeH
	m_arrWndTextPrint:nWndId:nLoop '= @"%LOCALS:0%%LOCALS:1%%LOCALS:2%"
	;m_arrWndTextPrint:nWndId:nLoop '= @"<font face='ＭＳ ゴシック'><button pos='{nPosX * 50}' value='%m_strWndBgBtnValue%'>" + (" " * nSizeW) + LOCALS:0 + @"</button></font>"
	;	m_arrWndTextPrint:nWndId:nLoop '= @"<font face='ＭＳ ゴシック'><nonbutton pos='{nPosX * 50}'>" + (" " * nSizeW) + @"</nonbutton></font>"
	;MEMO ウィンドウ背景の塗り潰しだが、上と下どちらの処理もデメリットがある
	;     ・上の処理 ： ウィンドウ領域をクリックすると、文字入力が発生してしまう（INPUTSをぬけてしまう）。
	;     ・下の処理 ： ウィンドウが重なっている場合、上のウィンドウで隠れている、下のウィンドウのボタンを押下できてしまう。
	;     上の処理を採用する。理由は、入力内容が分かり、入力破棄と再入力で回避が可能で、予期せぬ入力が発生する下の処理よりも危険が少ないため。
NEXT
; 変換したHTMLテキストを格納
FOR nLoop, 0, nSizeH
	SELECTCASE nLoop
		CASE 0
			m_arrWndTextPrint:nWndId:nLoop += arrWndText_LineStartText:0 + arrWndTextBuf:nLoop
		CASE nSizeH - 1
			m_arrWndTextPrint:nWndId:nLoop += arrWndText_LineStartText:1 + arrWndTextBuf:nLoop
		CASEELSE
			m_arrWndTextPrint:nWndId:nLoop += arrWndText_LineStartText:2 + arrWndTextBuf:nLoop
	ENDSELECT
NEXT

RETURN

;================================================================
;【内部処理用】
; 実際に表示する整形済みのテキストを作成する
;--------------------------------
;[引数]
;	nWndId						: ウィンドウＩＤ（0～9を指定する）
;--------------------------------
;================================================================
@WndMgr_CreatePrintText_Print( nWndId )
#DIM  nWndId

#DIMS arrWndTextBuf, 100

#DIMS arrBorderText, 8		; 左上, 上, 右上, 左下, 下, 右下, 左, 右,
#DIMS arrBorderColor, 2
#DIMS strInvlidColorText = "@C:0x333333@"

#DIM  nPosX
#DIM  nSizeW
#DIM  nSizeH
#DIM  nLineWidth

#DIM  nLoop
#DIMS strBuf

nPosX      = m_arrWndPropN:nWndId:PropIdx_WndPosX
nSizeW     = m_arrWndPropN:nWndId:PropIdx_WndWidth
nSizeH     = m_arrWndPropN:nWndId:PropIdx_WndHeight
nLineWidth = (m_arrWndPropN:nWndId:PropIdx_WndBorder == 0 ? m_arrWndPropN:nWndId:PropIdx_WndWidth # m_arrWndPropN:nWndId:PropIdx_WndClientWidth)

SIF nSizeW <= 0 || nSizeH <= 0
	RETURN

;--------------------------------
; 枠線部
;--------------------------------
; 枠の色
VARSET arrBorderColor, ""
IF (m_arrWndPropN:nWndId:PropIdx_WndBorder > 0)
	; 無効ウィンドウ / ウィンドウ枠の色 / それ以外
	IF (m_arrWndPropN:nWndId:PropIdx_WndDisabled == 1)
		arrBorderColor:0 '= strInvlidColorText
		arrBorderColor:1 '= "@/C@"
	ELSEIF (m_arrWndPropN:nWndId:PropIdx_WndBorderColorSet == 1)
		arrBorderColor:0 '= "@C:0x" + TOSTR( m_arrWndPropN:nWndId:PropIdx_WndBorderColor, "X6" ) + "@"
		arrBorderColor:1 '= "@/C@"
	ELSE
		VARSET arrBorderColor, ""
	ENDIF
ENDIF
; 枠線のテキスト
VARSET arrBorderText, ""
CALL WndMgr_GetWndBorderText( m_arrWndPropN:nWndId:PropIdx_WndBorder, arrBorderText )
IF (m_arrWndPropN:nWndId:PropIdx_WndBorder > 0)
	arrBorderText:0 '= arrBorderColor:0 + arrBorderText:0 + arrBorderColor:1
	arrBorderText:2 '= arrBorderColor:0 + arrBorderText:2 + arrBorderColor:1
	arrBorderText:3 '= arrBorderColor:0 + arrBorderText:3 + arrBorderColor:1
	arrBorderText:5 '= arrBorderColor:0 + arrBorderText:5 + arrBorderColor:1
	arrBorderText:6 '= arrBorderColor:0 + arrBorderText:6 + arrBorderColor:1
	arrBorderText:7 '= arrBorderColor:0 + arrBorderText:7 + arrBorderColor:1
ENDIF

;--------------------------------
; ウィンドウにセットされたテキストを整形
VARSET arrWndTextBuf, ""
FOR nLoop, 0, nSizeH
	arrWndTextBuf:nLoop '= m_arrWndText:nWndId:nLoop
NEXT
SELECTCASE m_arrWndPropN:nWndId:PropIdx_WndBorder
		; 枠無し
	CASE 0
		; 太枠, 細枠
	CASE 1, 2
		VARSET LOCALS, ""
		ARRAYSHIFT arrWndTextBuf, 1, ""
		LOCALS:0 '= FuncTagSetText_ConvHtmlText( m_arrWndTitle:nWndId:0 )
		LOCALS:1 '= arrBorderText:1 * (nLineWidth / 2)
		LOCALS:2 '= arrBorderText:4 * (nLineWidth / 2)
		IF m_arrWndPropN:nWndId:PropIdx_WndLogButton == 1
			LOCALS:3 '= " @B:l@\[l\] ログ表示@/B@ "
			LOCAL = FuncTagSetText_GetPrintLength( LOCALS:3 )
			LOCALS:2 '= FuncString_Mold( LOCALS:2, nLineWidth - LOCAL, " ", "L" )
		ENDIF
		arrWndTextBuf:0            '= arrBorderColor:0 + FuncString_Mold( LOCALS:0 + LOCALS:1, nLineWidth, " ", "L" ) + arrBorderColor:1
		arrWndTextBuf:(nSizeH - 1) '= arrBorderColor:0 + LOCALS:2 + LOCALS:3 + arrBorderColor:1
ENDSELECT

FOR nLoop, 0, nSizeH
	IF m_arrWndPropN:nWndId:PropIdx_WndDisabled == 1
		strBuf '= strInvlidColorText + FuncTagSetText_GetPlainText( arrWndTextBuf:nLoop ) + "@/C@"
	ELSE
		strBuf '= arrWndTextBuf:nLoop
	ENDIF
	arrWndTextBuf:nLoop '= TAG_PRINT_SHAPE( strBuf, nLineWidth, 1 )
NEXT

;--------------------------------
; テキスト部
SELECTCASE m_arrWndPropN:nWndId:PropIdx_WndBorder
		; 枠無し
	CASE 0
		FOR nLoop, 0, nSizeH
			m_arrWndTextPrint:nWndId:nLoop '= arrBorderText:6 + arrWndTextBuf:nLoop + arrBorderText:7
		NEXT

		; 枠あり, 細枠
	CASE 1, 2
		FOR nLoop, 0, nSizeH
			SELECTCASE nLoop
				CASE 0
					m_arrWndTextPrint:nWndId:nLoop '= arrBorderText:0 + arrWndTextBuf:nLoop + arrBorderText:2
				CASE nSizeH - 1
					m_arrWndTextPrint:nWndId:nLoop '= arrBorderText:3 + arrWndTextBuf:nLoop + arrBorderText:5
				CASEELSE
					m_arrWndTextPrint:nWndId:nLoop '= arrBorderText:6 + arrWndTextBuf:nLoop + arrBorderText:7
			ENDSELECT
		NEXT
ENDSELECT

RETURN

;================================================================
;【内部処理用】
; ウィンドウの枠線用テキストを取得する
;--------------------------------
;[引数]
;	nBorderType				: 枠線のタイプ
;	arrBorderText:Ｘ		: (REF) 枠線用テキスト格納領域（Ｘ:左上, 上, 右上, 左下, 下, 右下, 左, 右, ）
;--------------------------------
;================================================================
@WndMgr_GetWndBorderText( nBorderType, arrBorderText )
#DIM  nBorderType
#DIMS REF arrBorderText, 0

SELECTCASE nBorderType
		; 枠無し
	CASE 0
		VARSET arrBorderText, ""
		; 太枠
	CASE 1
		arrBorderText '= "┏", "━", "┓", "┗", "━", "┛", "┃", "┃"
		; 細枠
	CASE 2
		arrBorderText '= "┌", "─", "┐", "└", "─", "┘", "│", "│"
ENDSELECT

RETURN

;================================================================


code:
; 描画モード（描画に使用する処理を決定するためのフラグ）
;	0	: HTML版	メリット  ：等幅フォント以外のフォントを使用してもウィンドウの表示位置がずれない
;								画像表示が行える
;					デメリット：HTMLの書式的におかしい場合、異常終了する（<button>の入れ子やタグの閉じ忘れなど）
;								枠無しの場合、ウィンドウ表示位置の左側に半角スペースが１つ入る
;
;	1	: PRINT		メリット  ：HTML版のデメリットが発生しない
;					デメリット：MSゴシック以外のフォントを使用すると表示が崩れる
;								画像表示を行うと表示が崩れる（画像より右側への文字出力が想定通りに出力できない）
;								ウィンドウが重なる場合、下のウィンドウの描画位置が右に1文字分ずれることがあります
;
;	※ 基本的にはHTMLでの使用を推奨
#DEFINE DEF_WINDOW_DRAWER_MODE 0

; ウィンドウ数の上限
#DEFINE DEF_WINDOW_DRAWER_MAX_WND_LENGTH 100

#DIM  m_arrWndExsit,        100, 1		; ウィンドウ生成済みフラグ
#DIMS m_arrWndTitle,        100, 1		; タイトル文字列
#DIMS m_arrWndTitleLabel,   100, 1		; タイトル行に付加するラベル文字列
#DIM  m_arrWndPropN,        100, 20		; プロパティ保持領域（数値用）
#DIMS m_arrWndPropS,        100, 10		; プロパティ保持領域（文字列用）
#DIMS m_arrWndText,         100, 102	; 登録されたテキスト
#DIMS m_arrWndTextPrint,    100, 102	; 実際に表示する整形済みのテキスト。表示する度に整形すると処理が重たくなるため、保持しておく
#DIM  m_arrWndSetTextPrint, 100, 1		; 実際に表示する整形済みのテキストの作成済みフラグ

#DIMS CONST m_strWndBgBtnValue				=  "_"	; ウィンドウ背景用ボタン値

; ウィンドウプロパティのIndex値（数値用）
#DIM CONST PropIdx_WndPosX				=  0	; ウィンドウ座標Ｘ値
#DIM CONST PropIdx_WndPosY				=  1	; ウィンドウ座標Ｙ値
#DIM CONST PropIdx_WndWidth				=  2	; ウィンドウ幅
#DIM CONST PropIdx_WndHeight			=  3	; ウィンドウ高さ
#DIM CONST PropIdx_WndClientWidth		=  4	; ウィンドウ幅(クライアント領域)
#DIM CONST PropIdx_WndClientHeight		=  5	; ウィンドウ高さ(クライアント領域)
#DIM CONST PropIdx_WndBorder			=  6	; 枠設定
;	0=枠無し, 1=枠あり(太枠), 2=枠あり(細枠),
#DIM CONST PropIdx_WndBorderColorSet	=  7	; ウィンドウ枠の色を変更するフラグ
;	0=変更なし, 1=変更あり（PropIdx_WndBorderColorで枠の色を設定する）
#DIM CONST PropIdx_WndBorderColor		=  8	; ウィンドウ枠の色
#DIM CONST PropIdx_WndDisabled			=  9	; 無効化フラグ
;	0=ウィンドウ有効, 1=ウィンドウ無効（無効化時は全てのタグを無視する。またウィンドウ全体の色が無効化時用の色になる）
#DIM CONST PropIdx_WndHidden			= 10	; 非表示フラグ
;	0=ウィンドウ表示, 1=ウィンドウ非表示
#DIM CONST PropIdx_WndLogButton			= 11	; ログボタン有効
;	0=ログボタンなし, 1=ログボタン有効（ウィンドウ右下にログボタンを表示。枠あり時のみ）
#DIM CONST PropIdx_WndBehindWindow		= 12	; 他ウィンドウの背後にあることを示すフラグ
;	0=OFF, 1=ON

; ウィンドウプロパティのIndex値（文字列用）