UWSC(PowerShell)で絵と吹き出しを表示する

公式掲示板にイラスト画像を表示して吹き出しを付けたい、というなんとも面倒なお題があがっていました。
これ簡単じゃないし、こういう質問をしちゃう人に回答すると、質問攻めに会いそうで怖いからスルーしてたんですが、ま、質問攻めをスルーするかもしれないけど、答えてみる。



スクリプト

まあ、とりあえず書いてみたぞ。
任意の画像を表示したり、吹き出しを出すなら、.net すなわち PowerShell使おう、というところ。


既知の不具合が二点あって、

  • 移動(初回表示含む)直後、メッセージが表示されない
  • 長い日本語のメッセージが切れる


bmpBalloon.uws

OPTION EXPLICIT

IFB GET_UWSC_NAME = "bmpBalloon.uws" THEN
	DIM id = BmpBalloon.Start(INPUT("表示するBitmapファイルを指定して")), cmd = EMPTY
	WHILE cmd <> "exit"
		cmd = INPUT("[exit]と入力すると終了します")
		BmpBalloon.SetMsg(id, cmd)
	WEND
	SLEEP(0.5)
ENDIF



MODULE BmpBalloon

	TEXTBLOCK _script
		Add-Type -AssemblyName System.Windows.Forms
		$formMain = New-Object System.Windows.Forms.Form

		$formMain.Text = '$$formName$$'
		$bmp = New-Object System.Drawing.Bitmap '$$bmpPath$$'
		$transColor = $bmp.GetPixel($$x$$, $$y$$)

		$formMain.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None
		$textBoxCmd = New-Object System.Windows.Forms.TextBox
		$textBoxX = New-Object System.Windows.Forms.TextBox
		$textBoxY = New-Object System.Windows.Forms.TextBox
		$textBoxDisplay = New-Object System.Windows.Forms.TextBox

		$bmp.MakeTransparent($transColor)
		$formMain.Size = New-Object System.Drawing.Size($bmp.Width, $bmp.Height)
		$formMain.BackgroundImage = $bmp
		$formMain.BackColor = $transColor
		$formMain.TransparencyKey = $transColor
		$textBoxCmd.Location = New-Object System.Drawing.Point($bmp.Width, $bmp.Height)
		$textBoxX.Location = New-Object System.Drawing.Point($bmp.Width, ($bmp.Height + 1))
		$textBoxY.Location = New-Object System.Drawing.Point($bmp.Width, ($bmp.Height + 2))
		$textBoxDisplay.Location = New-Object System.Drawing.Point($bmp.Width, ($bmp.Height + 3))

		$mainBalloon = New-Object System.Windows.Forms.ToolTip
		$mainBalloon.IsBalloon = $true
		$mainBalloon.ShowAlways = $true
		$pointDragStart = New-Object System.Drawing.Point(0, 0)

		$formMain.Add_MouseDown({
		 Param($sender, $event)
			if ($event.Button -eq [System.Windows.Forms.MouseButtons]::Left) {
				$pointDragStart = New-Object System.Drawing.Point($event.X, $event.Y)
			}
		})
		$formMain.Add_MouseMove({
		 Param($sender, $event)
			if($event.Button -eq [System.Windows.Forms.MouseButtons]::Left) {
				$formMain.Left += $event.X - $pointDragStart.X
				$formMain.Top += $event.Y - $pointDragStart.Y
			}
		})
		$funcTextChange = {
		 Param($sender, $event)
			if($textBoxCmd.Text -eq "exit") {
				$formMain.Close()
			} elseif([string]::IsNullOrEmpty($textBoxCmd.Text)) {
				$mainBalloon.Hide($formMain)
			} else {
				$x = 0; $y = 0; $display = 0
				if(![int]::TryParse($textBoxX.Text, [ref]$x)) { $x = $formMain.Width / 2 }
				if(![int]::TryParse($textBoxY.Text, [ref]$y)) { $y = $formMain.Height / 2 }
				if(![int]::TryParse($textBoxDisplay.Text, [ref]$display)) { $display = 0 }
				if($display -gt 0) {
					$mainBalloon.Show($textBoxCmd.Text, $formMain, $x, $y, $display)
				} else {
					$mainBalloon.Show($textBoxCmd.Text, $formMain, $x, $y)
				}
			}
		}
		$textBoxCmd.Add_TextChanged($funcTextChange)
		$textBoxX.Add_TextChanged($funcTextChange)
		$textBoxY.Add_TextChanged($funcTextChange)
		$textBoxDisplay.Add_TextChanged($funcTextChange)

		$formMain.Controls.Add($textBoxCmd)
		$formMain.Controls.Add($textBoxX)
		$formMain.Controls.Add($textBoxY)
		$formMain.Controls.Add($textBoxDisplay)

		$formMain.ShowDialog()
		$mainBalloon.Dispose()
		$formMain.Dispose()
	ENDTEXTBLOCK

	FUNCTION Start(bmpPath, x=0, y=0, formName=EMPTY)
		IF formName=EMPTY THEN formName = "NotifyIcon form " + GET_UWSC_NAME

		POWERSHELL(REPLACE(REPLACE(REPLACE(REPLACE(_script, "$$formName$$", formName), "$$bmpPath$$", bmpPath), "$$x$$", x), "$$y$$", y), TRUE)
		RESULT = GETID(formName, , -1)
	FEND


	PROCEDURE SetMsg(id, msg=EMPTY, display=EMPTY, x=EMPTY, y=EMPTY)
		SENDSTR(id, msg, 1, TRUE)
		IF display <> EMPTY THEN SENDSTR(id, display, 4, TRUE)
		IF x <> EMPTY THEN SENDSTR(id, x, 2, TRUE)
		IF y <> EMPTY THEN SENDSTR(id, y, 3, TRUE)
	FEND

ENDMODULE


SetMsgの引数は、サンプルだと第二引数のmsgまでしか利用していませんが、さらにdisplay,x,yがあります。
msg:表示メッセージ。長さ0もしくはEMPTYにすると吹き出しを消す。
display: 表示時間(msec)。この時間が経過すると自動的に消せる。省略および0の場合、自動的には消さない
x:画像からの吹き出し相対位置。省略時は真ん中あたり
y:画像からの吹き出し相対位置。省略時は真ん中あたり
そんなとこだね。