UWSCのFUKIDASIを多色にする

追記 20120616
XPでも可能な方法を書いたので、本記事は不要。
UWSCのみでFUKIDASIをカラフルにする - じゅんじゅんのきまぐれ
でも、シンプルさではこっちが上。


公式掲示板に面白そうな(無意味な)課題があったので、やってみた。

fukidasiの一部だけの文字色変更は残念ながら出来ません
(中略)
#あるいは何かしらの(おそらく至極面倒な)手段で実現可能かもしれませんが…(略)


前に、検討したんですよね。
結局、callbackが面倒でWM_PAINTを処理できないから、無理、と判断したけど、
何故か、Win7では再描画できてしまったり、、、。



とりあえず、お題の回答

OPTION EXPLICIT

DIM fcs[] = $FF0000, $C00040, $800080, $4000C0, $0000FF
DIM msg="吹き<#CR>出しで", bc=$00FF00, al=-1
Fukidashi(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 0, 16, "MS ゴシック", bc, al)
MSGBOX("OK?")
Fukidashi(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 1, 32, "MS Pゴシック", bc, al)
MSGBOX("OK?")
Fukidashi(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 2, 8, "MS P明朝", bc, al)
MSGBOX("OK?")
Fukidashi(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 3, 10, "MS 明朝", bc, al)
MSGBOX("OK?")
Fukidashi(fcs, msg, G_MOUSE_X, G_MOUSE_Y, 4, 72, "MS ゴシック", bc, al)
MSGBOX("OK?")


// FUKIDASIにあわせる。テキスト色が配列で省略不可
PROCEDURE Fukidashi(fcs[], msg=EMPTY, x=0, y=0, dir=0, pt=10, font="MS Pゴシック", bc=$FFFF, al=0)
	// WIN32API
	// テキスト描画用
	DEF_DLL GetDC(hwnd): dword: user32
	DEF_DLL ReleaseDC(hwnd, dword): int: user32
	DEF_DLL DrawTextW(dword, wstring, int, {long, long, long, long}, uint): int: user32
	// テキストフォント変更用
	DEF_DLL SelectObject(dword, dword): dword: gdi32
	DEF_DLL DeleteObject(dword): bool: gdi32
	DEF_DLL CreateFontW(int, int, int, int, int, dword, dword, dword, dword, dword, dword, dword, dword, wstring): dword: gdi32
	DEF_DLL GetDeviceCaps(dword, int): int: gdi32
	DEF_DLL MulDiv(int, int, int): int: kernel32
	// 文字色・背景色変更
	DEF_DLL SetTextColor(dword, dword): dword: gdi32
	DEF_DLL SetBkColor(dword, dword): dword: gdi32
	DEF_DLL SetBkMode(dword, int): int: gdi32

	// とりあえずFUKIDASIを出して情報収集
	DIM fc = 0, fcnum = LENGTH(fcs)
	IF fcnum > 0 THEN fc = fcs[fcnum-1]
	FUKIDASI(msg, x, y, dir, pt, font, fc, bc, al)
	DIM wid = GETID(GET_FUKIDASI_WIN)
	DIM hwndF = IDTOHND(wid)
	DIM hdcF = GetDC(hwndF)
	DIM l = 0, t = 0, r = STATUS(wid, ST_CLWIDTH), b = STATUS(wid, ST_CLHEIGHT)
	// 微調整
	SELECT dir
	CASE 1
		t = 5; b = b + t
	CASE 2
		b = b - 10
	CASE 3
		l = 5; r = r + l
	CASE 4
		r = r - 10
	SELEND

	// フォント作成とフォント・色設定
	DIM ro = r, bo = b, nHeight = MulDiv(pt, GetDeviceCaps(hdcF, 90), 72)
	DIM hfontF = CreateFontW(0 - nHeight, 0, 0, 0, 0, FALSE, FALSE, FALSE, 0, 0, 0, 0, 0, font)
	DIM hfontO = SelectObject(hdcF, hfontF)
	DIM cFr = SetTextColor(hdcF, fc)
	DIM cBk = SetBkColor(hdcF, bc)
	DIM cBf = FALSE, cBt
	IFB al < 0 THEN
		cBf = TRUE
		cBt = SetBkMode(hdcF, 1)
	ENDIF

	// 描画位置を決定する
	DIM msgnum = LENGTH(msg)
	DIM off = DrawTextW(hdcF, msg, msgnum, l, t, r, b, $400)
	l = l + (ro - r) / 2; r = (ro + r) / 2; ro = r
	t = t + (bo - b) / 2; b = (bo + b) / 2

	// 1文字づつ描く
	DIM i, tar, lo = l, s = -1
	FOR i = 1 TO msgnum
		tar = COPY(msg, i, 1)
		IFB tar = CHR(10) THEN
			t = t + nHeight
			l = lo
			s = s - 1
			CONTINUE
		ELSEIF tar = CHR(13) THEN
			s = s - 1
			CONTINUE
		ENDIF
		IFB fcnum > i + s THEN
			SetTextColor(hdcF, fcs[i+s])
		ELSE
			BREAK
		ENDIF
		off = DrawTextW(hdcF, tar, 1, l, t, r, b, $400)
		off = DrawTextW(hdcF, tar, 1, l, t, r, b, 0)
		// 次の文字の準備
		l = r; r = ro
	NEXT

	// 後片付け
	SelectObject(hdcF, hfontO)
	DeleteObject(hfontF)
	SetTextColor(hdcF, cFr)
	SetBkColor(hdcF, cBk)
	IF cBf THEN SetBkMode(hdcF, cBt)
	ReleaseDC(hwndF, hdcF)
FEND


透明は、SetBkModeかしらん?(未評価)
一度描いただけなので、XPでは再描画が走ると、先頭色になります。
Win7では大丈夫。
VISTAはどっちかな?

追記 20120608

stuncloudさんのコメントによると、vistaも不可。
また、スクリプトを少し修正。
複数行および透明化対応。
、、、でも、本来ならWndProcをフックしてWM_PAINTを処理すべき。

追記 20120613

気になったので、DLL作ってXP/Vistaに対応した。
我ながらアホだと思う。
UWSCのFUKIDASIをカラフルにする - じゅんじゅんのきまぐれ