顯示具有 With Code 標籤的文章。 顯示所有文章
顯示具有 With Code 標籤的文章。 顯示所有文章

2008年6月14日

Event Handler

Event Handler是一種物件,具有三個word,分別是name、priority、handler,如下面的範例所示:
make object! [
name: 'view-default
priority: 50
handler: func [event] [
print ["view-event:" event/type event/offset]
switch event/type [
close [quit]
key [if event/key = escape [quit]]
]
show event/window
none ; we handled it
]
]

一般我們會在View函數中,利用下面的方式指定Event Handler:
view/options window [
handler: [
name: 'my-handler
priority: 100
handler: func [event] [
if event/type = 'down [quit]
]
]
]

注意,在上面的例子中,我們並未建立物件(make object!),而是以區塊(block!)的方式指定此Event Handler的內容。

在REBOL/View系統中,可以同時具有多個Event Handler,將它們串接起來。你可以透過handle-events與unhandle-events來分別增加與刪除Event Handler。注意,handle-events需要的參數是block!,而unhandle-events需要的參數則是物件。

每個Event Handler都具有一個name(名稱),是用來識別Event Handler之用的。想知道目前有沒有具備某名稱的Event Handler,可以透過handled-events?函數。此函數需要傳入一個名稱,它會傳出此名稱的Event Handler(如果有的話)。

利用handle-events函數加入一個Event Handler時,會根據其priority(優先權),決定其位置,優先權越高者放在越前面。例如,現在已經有兩個Event Handler,分別為優先權500的A與優先權200的B,再新增一個優先權為300的C時,最後的結果會是A、C、B,因為C的優先權介於A、B之間。

每個Event Handler都具有一個handler,這是真正處理事件的函數,所以需要事件當參數。特別注意的是,handler的傳出值如果為event,則處理完目前的Event-Handler之後,會繼續處理下一個Event Handler;handler的傳出值如果為none,則表示此事件已經處理完畢(被消耗掉了),不用再往後面的Event Handler遞送。例如,目前依序有A、C、B這三個Event Handler,其中A的handler函數傳出值為none,則C與B都不會發生作用。

2008年6月13日

MAP-INNER and MAP-OUTER are killing me

我一直搞不懂MAP-INNER與MAP-OUTER要如何使用,也沒有文件說明可以閱讀。我在動手寫程式做了一些實驗之後,終於放棄了。我於是定義了下面的函數(取得某個gob的絕對座標):
abs-offset?: func [ gob [gob!] ] [
negate second map-inner gob 0x0
]

以後我打算只使用MAP-EVENT和abs-offset?,不再碰觸令人痛苦不已的MAP-INNER與MAP-OUTER。

FORMAT與PRINTF的用法

REBOL 3.0提供format與printf函數,這兩個函數的參數完全一樣。Format函數會傳出格式化的字串,而printf則會印出格式化的字串。事實上,printf內部直接呼叫format。

>> source printf
printf: make function! [[
"Formatted print."
fmt "Format"
val "Value or block of values"
][
print format :fmt :val
]]
>>

下面是它們的使用範例:

>> format [ 20 #"/" -10 ] [ %my-rebol-file.r 31023 ]
== "my-rebol-file.r / 31023"

>> printf [ 20 #"/" -10 ] [ %my-rebol-file.r 31023 ]
my-rebol-file.r / 31023
>>

printf與format都需要兩個參數,第一個是格式規則,第二個是代換內容的區塊(block)。格式規則區塊內可以出現四種元素:
  • 正整數:指定內容長度,如果內容超過指定長度,則自動放寬。如果內容不滿指定長度,則「補上空白」,且內容「向左對齊」。
  • 負整數:指定內容長度,如果內容超過指定長度,則自動放寬。如果內容不滿指定長度,則「補上空白」,且內容「向右對齊」。
  • 字元:直接放置一個字元
  • 字串:直接放置此字串

使用format時,還可以透過/pad,指定補上某字元(或字串),而不是補上空白。例如:



>> format/pad [ 20 #"/" -10 ] [ %my-rebol-file.r 31023 ] #"."
== "my-rebol-file.r...../.....31023"

Bugfix: ls與format

我已經修正完畢LS函數和FORMAT函數的Bug,下面列出的是FORMAT的定義。至於LS的定義修改方式很簡單,把LENGTH?用LENGTH+?取代即可。當FORMAT遇到中文時,終於不會出問題了!

LENGTH+?不會計算出字串的字元長度,而是會計算出「相當於多少個half-width字元」的長度。記得把前一篇文章的Full-Wide-Width-charset定義也加進來,因為LENGTH+?會用到這個定義。

我會找一天把修正後的結果透過DevBase遞交給REBOL公司。

length+?: func [str [string!] /local ans ] [
ans: 0
foreach ch str [
either find Full-Wide-Width-charset ch [
ans: ans + 2
] [
ans: ans + 1
]
]
]

format: make function! [[
"Format a string according to the format dialect."
rules {A block in the format dialect. E.g. [10 -10 #"-" 4]}
values
/pad p
/local out val
][
p: any [p #" "]
unless block? :rules [rules: reduce [:rules]]
unless block? :values [values: reduce [:values]]
out: make string! ""
foreach rule rules [
if word? :rule [rule: get rule]
switch type?/word :rule [
integer! [
val: first+ values
val: form :val
pad: (abs rule) - length+? val
if negative? pad [ pad: 0 ]
either positive? rule [
append out :val
append/dup out p pad
] [
append/dup out p pad
append out :val
]
]
string! [append out rule]
char! [append out rule]
]
]
if not tail? values [append out values]
head out
]]

Format函數與寬字元

REBOL 3.0有提供一個函數名為format,用來進行輸出文字的格式化。許多函數都會用到format,例如what、ls。

format一遇到中文就會失靈,輸出格式亂掉,這是因為中文字是寬字元(Wide Character)。為了要修正format的此錯誤,我剛剛把Unicode Standard Annex #11 (East Asian Width) 所附的檔案整理過,找出其中屬於Full-Width與Wide的字元。接下來,就等我(或任何人)有空去修正format函數的定義了。
full-wide-width-charset: charset [
#"^(1100)" - #"^(1159)"
#"^(115F)"
#"^(2329)" - #"^(232A)"
#"^(2E80)" - #"^(2E99)"
#"^(2E9B)" - #"^(2EF3)"
#"^(2F00)" - #"^(2FD5)"
#"^(2FF0)" - #"^(2FFB)"
#"^(3000)" - #"^(303E)"
#"^(3041)" - #"^(3096)"
#"^(3099)" - #"^(30FF)"
#"^(3105)" - #"^(312D)"
#"^(3131)" - #"^(318E)"
#"^(3190)" - #"^(31B7)"
#"^(31C0)" - #"^(31E3)"
#"^(31F0)" - #"^(321E)"
#"^(3220)" - #"^(3243)"
#"^(3250)" - #"^(32FE)"
#"^(3300)" - #"^(33FF)"
#"^(3400)" - #"^(4DB5)"
#"^(4E00)" - #"^(9FC3)"
#"^(A000)" - #"^(A48C)"
#"^(A490)" - #"^(A4C6)"
#"^(AC00)" - #"^(D7A3)"
#"^(F900)" - #"^(FA2D)"
#"^(FA30)" - #"^(FA6A)"
#"^(FA70)" - #"^(FAD9)"
#"^(FE10)" - #"^(FE19)"
#"^(FE30)" - #"^(FE52)"
#"^(FE54)" - #"^(FE66)"
#"^(FE68)"
#"^(FF01)" - #"^(FF60)"
#"^(FFE0)" - #"^(FFE6)"
]

2008年6月12日

對Object!進行Append與Length?

REBOL 3.0現在允許擴充(extend)物件(object!),如下所示:
>> obj: context [ a: 1 ]
== make object! [
a: 1
]
>> append obj [ b 2 c 4]
== make object! [
a: 1
b: 2
c: 4
]

上面的例子中,[ b 2 c 4] 也可以寫成 [ b: 2 c: 4],效果一樣。

如果Block內的word和Object內的word相同時,會造成修改的效果。例如:
>> append obj [c 3]
== make object! [
a: 1
b: 2
c: 3
]

上面的例子,由於obj本來就有c,所以append之後,c的值會被改變。

特別注意,這些處理series的函數中,只有append可以用在物件上,remove、insert並不適用於物件。我猜想可能是因為remove、insert會讓context內部binding對應的方式亂掉。

Block不會先被reduce,如果有reduce的必要,必須自己來。這個時候,通常會使用compose或reduce/no-set,例如:
>> append obj reduce/no-set [ d: 365 + now ]
== make object! [
a: 1
b: 2
c: 3
d: 12-Jun-2009/22:56:29+8:00
]

想知道某物件有多少Word,可以利用Length?,例如:

>> length? obj
== 4

效果相當於「length? words-of obj」。

2008年6月9日

OOP in REBOL 3.0: An Example

REBOL[]


Inherit: func [super [object!] sub [object!]] [
append sub reduce/no-set [parent: super]
]


Invoke: func [ obj member /local ans] [
either ans: select obj member [
ans
] [
attempt [Invoke obj/parent member]
]
]


Super-Class: context [
Member-A: does [ print "Member-A of Super" ]
Member-B: does [ print "Member-B of Super" ]
]


Sub-Class: context [
Inherit Super-Class Self


Member-B: does [ print "Member-B of Sub" ]
Member-C: does [ print "Member-C of Sub" ]
]


Invoke sub-class 'Member-A
Invoke sub-class 'Member-B
Invoke sub-class 'Member-C

2008年4月12日

用Draw方言繪製發光文字


REBOL Draw底層使用AGG 2.4當繪圖引擎,繪圖能力很強。這裡是一個範例展示:

REBOL[]

my-font: make system/standard/font [
name: "Times New Roman" size: 64
]

draw-block: [ ]

for i 0 9 1 [
j: to-integer (255 / 10.0 * (i + 1))
append draw-block compose/deep [
pen (to-tuple reduce [ j j 255 ] )
line-width (10 - i)
line-join round
fill-pen none
text 10x0 vectorial [
font my-font bold "REBOL"
]
]
]

append draw-block compose [
fill-pen black
text 10x0 vectorial [
font my-font bold "REBOL"
]
Fill-pen Red
text 142x0 vectorial [
font my-font bold "O"
]
]

win: make gob! [
size: 360x130
color: black
]

append win g: make gob! compose [
size: ( win/size )
offset: 0x0
]

g/draw: draw-block

view win

2008年3月6日

用REBOL 3.0列出Unicode字元表

REBOL 3.0 支援Unicode,而且是連console都支援Unicode,你可以在console中輸入或輸出任何Unicode字元,只要你有適當的字型,就不會有問題。

下面是一個簡短的範例,將0x0000-0xFFFF的全部Unicode列出,程式很簡單,所以我就不說明了:

for i 0 4095 1 [ 
prin rejoin [ newline to-hex/size i 3 "0 " ]
for j 0 15 1 [
prin [ to-char to-hex/size i * 16 + j 4 " " ]
]
wait .01
]