其實(shí)有了一整套的Kernel FP API之后,只需要插入幾個(gè)外部函數(shù)就可以讓Kernel FP繪圖了。現(xiàn)在我們看一看這個(gè)Demo的樣子。
這是一個(gè)Kernel FP程序。程序在窗口正中繪制“Hello World!”,之后四個(gè)正方形在四個(gè)邊角處旋轉(zhuǎn)。下面讓我們看一看這個(gè)程序的代碼:
1 def PointAdd p1 p2 = select p1 of
2 case GuiPoint x1 y1 : select p2 of
3 case GuiPoint x2 y2 : GuiPoint (x1+x2) (y1+y2)
4 end
5 end
6
7 def PointRotate angle point = select point of
8 case GuiPoint px py : let
9 def t = angle * 3.1415926 / 180.0
10 def x = itof px
11 def y = itof py
12 def rx = x * cos t - y * sin t
13 def ry = x * sin t + y * cos t
14 in GuiPoint (ftoi rx) (ftoi ry)
15 end
PointAdd和PointRotate分別是一個(gè)點(diǎn)的平移和旋轉(zhuǎn)。
1 def DrawSquare size center angle =
2 [ GuiPoint (ineg size) (ineg size)
3 , GuiPoint (size) (ineg size)
4 , GuiPoint (size) (size)
5 , GuiPoint (ineg size) (size)
6 ] ||> PointRotate angle ||> PointAdd center |> GuiDrawPolygon
接下來(lái),DrawSquare使用4個(gè)點(diǎn)構(gòu)造一個(gè)中心在坐標(biāo)系中心的正方形,先旋轉(zhuǎn)后平移,最后使用外部函數(shù)GuiDrawPolygon繪制圖形。
1 def DrawBackground = do
2 GuiSetPen (GuiSolidPen (GuiColor 255 0 0) 1);
3 GuiSetBrush (GuiSolidBrush (GuiColor 255 255 255));
4 GuiDrawRect (GuiRect (GuiPoint 0 0) (GuiPoint 799 599));
5 end
DrawBackground繪制背景,邊框紅色,背景白色。
1 def DrawHelloWorld = do
2 TextSize = GuiTextSize "Hello World!";
3 select TextSize of
4 case GuiSize SizeX SizeY : do
5 TextX = return ((800 - SizeX)/2);
6 TextY = return ((600 - SizeY)/2);
7 GuiDrawText (GuiPoint TextX TextY) "Hello World!";
8 end
9 end;
10 end
DrawHelloWorld首先使用外部函數(shù)GuiTextSize獲得文字大小,然后計(jì)算坐標(biāo)以便將文字繪制在正中。
1 def DrawScreen = do
2 DrawBackground;
3 DrawHelloWorld;
4 angle = _GetAngle;
5 DrawSquare 20 (GuiPoint 50 50) angle;
6 DrawSquare 20 (GuiPoint 50 550) angle;
7 DrawSquare 20 (GuiPoint 750 550) angle;
8 DrawSquare 20 (GuiPoint 750 50) angle;
9 end
這是完整的繪圖函數(shù)。首先繪制背景,然后繪制文字,最后繪制4個(gè)旋轉(zhuǎn)的正方形。驅(qū)動(dòng)程序執(zhí)行的main函數(shù)如下:
1 func main :: GuiMessage -> IO void
2 def main message = do
3 select message of
4 case GuiInitialize : do
5 GuiSetCanvas (GuiSize 800 600);
6 GuiSetTitle "Canvas Program";
7 GuiSetFont (GuiFont "宋體" 96 false false false);
8 GuiSetFontColor (GuiColor 0 0 255);
9 _SetAngle 0.0;
10 DrawScreen;
11 GuiOpenTimer 0 1;
12 end
13 case GuiTimer ID : do
14 angle = _GetAngle;
15 _SetAngle (angle + 5.0);
16 DrawScreen;
17 GuiFlush;
18 end
19 else : iovoid
20 end;
21 end
窗口接收到消息的時(shí)候調(diào)用main函數(shù),這個(gè)main函數(shù)可以看成消息循環(huán)的循環(huán)體。函數(shù)接收到GuiInitialize消息時(shí)進(jìn)行初始化并申請(qǐng)一個(gè)定時(shí)器。函數(shù)接收到GuiTimer消息的時(shí)候增加角度并繪圖。由于Kernel FP是一個(gè)沒(méi)有狀態(tài)的程序,因此使用IO void作為函數(shù)類(lèi)型。IO類(lèi)型是一個(gè)函數(shù),接受“環(huán)境”參數(shù)。“環(huán)境”參數(shù)是無(wú)狀態(tài)程序?qū)κ录囊粋€(gè)建模。可以這么理解:程序在不同的時(shí)間有不同的輸出。由于熱力學(xué)定律,時(shí)間不可倒退,因此一個(gè)程序在一個(gè)給定的時(shí)間下只有一次輸出的機(jī)會(huì)。因此外部世界不斷的遞增時(shí)間并向程序請(qǐng)求給定時(shí)間的輸出。一個(gè)時(shí)間的輸出可以影響以后時(shí)間的輸出,所以使用這種辦法就可以在一個(gè)無(wú)狀態(tài)程序中為時(shí)間建模以便處理狀態(tài)。
IO T的定義是IOEnv -> maybe (pair T IOEnv) IOError。程序在接受一個(gè)時(shí)間的時(shí)候,進(jìn)行計(jì)算并返回結(jié)果。結(jié)果有兩種,一種是正確一種是錯(cuò)誤。當(dāng)一次IO任務(wù)執(zhí)行出錯(cuò)后,接下來(lái)的所有IO任務(wù)會(huì)立刻中止。當(dāng)一次IO任務(wù)執(zhí)行成功后,IO任務(wù)會(huì)返回一個(gè)新的時(shí)間供后續(xù)的IO任務(wù)執(zhí)行。所以我們可以猜到_GetAngle和_SetAngle的類(lèi)型了。這是一對(duì)與狀態(tài)有關(guān)的函數(shù),在給定時(shí)間下具有相同的行為,因此為了讓他們保留類(lèi)型,因此這兩個(gè)函數(shù)也必須是IO類(lèi)型的。getter::X與setter::X是Kernel FP虛擬機(jī)提供的狀態(tài)有關(guān)的存儲(chǔ)服務(wù)。X可以取任意值,虛擬機(jī)會(huì)在需要的時(shí)候存儲(chǔ)狀態(tài)。
1 func _GetAngle :: IO float alias "getter::program.Angle"
2 func _SetAngle :: float -> IO void alias "setter::program.Angle"
于是當(dāng)Kernel FP程序被加載到窗口中時(shí),窗口接收到消息就用一個(gè)時(shí)間概念向main函數(shù)求值。這種復(fù)雜的相互作用隱藏在了do-end語(yǔ)法糖和Kernel FP API內(nèi)部。外部程序僅需要在適當(dāng)?shù)臅r(shí)候提供IO函數(shù)就可以了。在這里給出圖形界面的外部函數(shù)接口。
CanvasModule.txt(生成的代碼文件)
1 module canvas
2 import system
3
4 data GuiMouseButton = (GuiMouseLeftButton | GuiMouseRightButton)
5
6 data GuiMessage = (((((((GuiKeyDown int) | (GuiKeyUp int)) | (GuiMouseDown GuiPoint GuiMouseButton)) | (GuiMouseUp GuiPoint GuiMouseButton)) | (GuiMouseMove GuiPoint)) | GuiInitialize) | (GuiTimer int))
7
8 data GuiColor = (GuiColor int int int)
9
10 data GuiPen = ((GuiSolidPen GuiColor int) | GuiClearPen)
11
12 data GuiBrush = ((GuiSolidBrush GuiColor) | GuiClearBrush)
13
14 data GuiFont = (GuiFont string int bool bool bool)
15
16 data GuiPoint = (GuiPoint int int)
17
18 data GuiSize = (GuiSize int int)
19
20 data GuiRect = (GuiRect GuiPoint GuiPoint)
21
22 func GuiSetPen :: (GuiPen -> (IO void)) alias "gui::SetPen"
23
24 func GuiSetBrush :: (GuiBrush -> (IO void)) alias "gui::SetBrush"
25
26 func GuiSetFont :: (GuiFont -> (IO void)) alias "gui::SetFont"
27
28 func GuiSetFontColor :: (GuiColor -> (IO void)) alias "gui::SetFontColor"
29
30 func GuiSetCanvas :: (GuiSize -> (IO void)) alias "gui::SetCanvas"
31
32 func GuiSetTitle :: (string -> (IO void)) alias "gui::SetTitle"
33
34 func GuiDrawLine :: (GuiPoint -> (GuiPoint -> (IO void))) alias "gui::DrawLine"
35
36 func GuiDrawRect :: (GuiRect -> (IO void)) alias "gui::DrawRect"
37
38 func GuiDrawEllipse :: (GuiRect -> (IO void)) alias "gui::DrawEllipse"
39
40 func GuiDrawArc :: (GuiRect -> (GuiPoint -> (GuiPoint -> (IO void)))) alias "gui::DrawArc"
41
42 func GuiDrawChord :: (GuiRect -> (GuiPoint -> (GuiPoint -> (IO void)))) alias "gui::DrawChord"
43
44 func GuiDrawPie :: (GuiRect -> (GuiPoint -> (GuiPoint -> (IO void)))) alias "gui::DrawPie"
45
46 func GuiDrawPolyline :: ((list GuiPoint) -> (IO void)) alias "gui::DrawPolyline"
47
48 func GuiDrawPolygon :: ((list GuiPoint) -> (IO void)) alias "gui::DrawPolygon"
49
50 func GuiDrawText :: (GuiPoint -> (string -> (IO void))) alias "gui::DrawText"
51
52 func GuiFlush :: (IO void) alias "gui::Flush"
53
54 func GuiTextSize :: (string -> (IO GuiSize)) alias "gui::TextSize"
55
56 func GuiOpenTimer :: (int -> (int -> (IO void))) alias "gui::OpenTimer"
57
58 func GuiCloseTimer :: (int -> (IO void)) alias "gui::CloseTimer"
59
posted on 2008-12-29 10:41
陳梓瀚(vczh) 閱讀(2723)
評(píng)論(0) 編輯 收藏 引用 所屬分類(lèi):
腳本技術(shù)