随笔-341  评论-2670  文章-0  trackbacks-0
    其实有了一整套的Kernel FP API之后,只需要插入几个外部函数就可以让Kernel FP绘图了。现在我们看一看这个Demo的样子。

    这是一个Kernel FP程序。程序在窗口正中绘制“Hello World!”,之后四个正方形在四个边角处旋转。下面让我们看一看这个程序的代码:

 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分别是一个点的平移和旋转。

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

    接下来,DrawSquare使用4个点构造一个中心在坐标系中心的正方形,先旋转后平移,最后使用外部函数GuiDrawPolygon绘制图形。

1 def DrawBackground = do
2   GuiSetPen (GuiSolidPen (GuiColor 255 0 01);
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首先使用外部函数GuiTextSize获得文字大小,然后计算坐标以便将文字绘制在正中。

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

    这是完整的绘图函数。首先绘制背景,然后绘制文字,最后绘制4个旋转的正方形。驱动程序执行的main函数如下:

 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

    窗口接收到消息的时候调用main函数,这个main函数可以看成消息循环的循环体。函数接收到GuiInitialize消息时进行初始化并申请一个定时器。函数接收到GuiTimer消息的时候增加角度并绘图。由于Kernel FP是一个没有状态的程序,因此使用IO void作为函数类型。IO类型是一个函数,接受“环境”参数。“环境”参数是无状态程序对事件的一个建模。可以这么理解:程序在不同的时间有不同的输出。由于热力学定律,时间不可倒退,因此一个程序在一个给定的时间下只有一次输出的机会。因此外部世界不断的递增时间并向程序请求给定时间的输出。一个时间的输出可以影响以后时间的输出,所以使用这种办法就可以在一个无状态程序中为时间建模以便处理状态。

    IO T的定义是IOEnv -> maybe (pair T IOEnv) IOError。程序在接受一个时间的时候,进行计算并返回结果。结果有两种,一种是正确一种是错误。当一次IO任务执行出错后,接下来的所有IO任务会立刻中止。当一次IO任务执行成功后,IO任务会返回一个新的时间供后续的IO任务执行。所以我们可以猜到_GetAngle和_SetAngle的类型了。这是一对与状态有关的函数,在给定时间下具有相同的行为,因此为了让他们保留类型,因此这两个函数也必须是IO类型的。getter::X与setter::X是Kernel FP虚拟机提供的状态有关的存储服务。X可以取任意值,虚拟机会在需要的时候存储状态。

1 func _GetAngle :: IO float alias "getter::program.Angle"
2 func _SetAngle :: float -> IO void alias "setter::program.Angle"

    于是当Kernel FP程序被加载到窗口中时,窗口接收到消息就用一个时间概念向main函数求值。这种复杂的相互作用隐藏在了do-end语法糖和Kernel FP API内部。外部程序仅需要在适当的时候提供IO函数就可以了。在这里给出图形界面的外部函数接口。

    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) 阅读(2712) 评论(0)  编辑 收藏 引用 所属分类: 脚本技术

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理