Header Bar

Rebol Quick Start, Part 2

See http://re-bol.com/rebol_quick_start.html for part 1

Contents:

1. Objects
1.1 What Are Objects?
1.2 "Encapsulating" Code in Objects
1.3 Inheritance
1.4 Why is this Useful?
2. A More Detailed Look at Rebol Fundamentals
2.1 Data Types
2.2 A Variety of Additional Short Series Operation Examples
2.3 Strings
2.4 File Management and Reading/Writing From/To Varied Data Sources/Protocols
2.5 More About User Defined Functions
2.6 GUI Event Management
2.7 More Various GUI Examples, Techniques, Widgets (some grids), Etc.
2.8 Embedding Files (images, sounds, binary executables, etc.) in Code
2.9 Running Command Line Applications
3. Ports
3.1 Email Ports
3.2 Console Ports
3.3 Sound and other Hardware Ports
3.4 Network Ports
4. Shared Code Files (DLLs, So, Dylib libraries, etc.)
5. Third Party Libraries
5.1 PDF
5.2 Flash (.swf) Builder
5.3 RebGUI
5.4 Cyphre Menu and Tab Panel
5.5 Henrik Listview
5.6 Ensel Menu System
5.7 r3D
5.8 MySQL
5.9 SQLite
5.10 Doc's Captcha
5.11 Irwin/Ensel Screen Capture
5.12 XML and XML-RPC
5.13 Q-Plot Graph and Chart Library
5.14 Rebzip
6. Parse
7. Binding Words Labels to Contexts
8. Multitasking (Rebol Doesn't Have Threads)
9. More about Built-In Help
10. Learning More - Online Resources
10.1 R3 Links
10.2 Rebolforum.com
10.3 Rebol.org
10.4 Forums and The AltME Community

1. Objects

NOTE: Despite Rebol's acronym ("Relative Expression Based Object Language"), object code structures are not required to write many types of useful Rebol code (they were not needed for any of the example apps in part 1 of this tutorial).

1.1 What Are Objects?

Objects are code structures which contain collections of data (variables) and actions (functions). The functionality needed to perform common types of software development work is often packaged inside object structures in libraries. For example, Rebol's GUI widget definitions can be found in the built-in 'svv object library. You can inspect the 'svv object with a question mark:

? svv

Rebol uses forward-slash "path" notation to refer to functions and variables in any object (most other languages refer to functions as "methods", and use period characters to refer to items in an object). The following code refers to the 'button object inside the 'vid-styles portion of the 'svv library:

? svv/vid-styles/button

You can use the word "do" to import libraries of object code found in local files, or at URLs:

do %rebgui.r
do http://re-bol.com/rebgui.r
? ctx-rebgui

If you try running the last line above before importing the rebgui library, you'll see that the 'ctx-rebgui object doesn't otherwise exist. After importing, you'll see that the rebgui library contains an entire replacement GUI language with some features not found in Rebol's built-in 'svv object:

REBOL [title: "Text Editor"]
do http://re-bol.com/rebgui.r
display/maximize/close "Text Editor" [
    menu #LHW data [
        "File" [
             "    Open    " [a/text: read request-file/only  show a]
             "    Save    " [write request-file/only/save a/text]
         ] 
    ] return
    a: area #LHW
] [question "Really Close?"] do-events

1.2 "Encapsulating" Code in Objects

One characteristic of objects is that they can be thought of as code containers which "encapsulate" arbitrarily labeled pieces of code. Labels are isolated in their own "namespace" inside an object, so that they can't be unintentionally duplicated or overwritten elsewhere in a program.

The 'make function is used to create Rebol objects. The code below defines 2 new objects, labeled 'money and 'place, The exact same labels "bank" and "var" in these objects refer to totally different pieces of information and actions:

REBOL []
money: make object! [
    var: 1234.56
    bank: func [] [
        print ""
        print rejoin ["Your bank account balance is:  $" var]
        print ""
    ]
]
place: make object! [
    var: "Wabash"
    bank: func [] [
        print ""
        print rejoin [
            "Your favorite place is on the bank of the:  " var]
        print ""
    ]
]

Use the forward-slash notation (as opposed to .dot notation used in other languages) to refer to functions or variable words in Rebol objects. To clarify that the same variable and function labels in each object above actually exist and operate totally within a self-contained "context" in each object, look at the result of these lines:

money/bank               ; similar to money.bank() in other languages
money/var
place/bank
place/var

1.3 Inheritance

Another important characteristic of objects is that they can be copied and changed to perform specialized work. Here's an example of a new object blueprint, meant to store user account information. It contains several variable labels set to 'none, as well as 2 function definitions labeled 'email-address and 'display:

REBOL []
account: make object! [
    first-name: last-name: address: phone: none
    email-address: func [] [
        to-email rejoin [
            first-name "_" last-name "@website.com"
        ]
    ]
    display: func [] [
        print ""
        print rejoin ["Name:     " first-name " " last-name]
        print rejoin ["Address:  " address]
        print rejoin ["Phone:    " phone]
        print rejoin ["Email:    " email-address]
        print ""
    ]
]

Note that the variable label "email-address" is initially assigned to a function, which builds a default email address by concatenating the object's first-name and last-name variables with "@website.com". You can choose to use either that "inherited" default email definition, or "override" it by assigning an actual specific email address value. If you override the default value of the 'email-address label, the 'email-address function no longer exists in that particular object - it is overwritten by the specified email value. Below are some "instances" of the above object. Each instance creates a new labeled instantiation of the 'account object definition above, filled with default and/or specified data values:

Dave: make account []

John: make account [
    first-name: "John"
    last-name: "Smith"
    phone:  "555-4321"
]

Bob: make account [
    first-name: "Bob"
    last-name: "Jones"
    address: "4321 Street Place Cityville, USA 54321"
    phone:  "555-1234"
    email-address: "bob@mysite.net"
]

You can print out all the data contained in each object, by running each object's 'display function. Pay special attention to the 'email-address value in each object:

Dave/display
John/display
Bob/display

Because of this "inheritance" characteristic of objects, they can be easily copied and redefined slightly so that only one function or variable, for example, is altered or added, but all the other parts remain the same. By inheriting all the functions and variables from a GUI button, for example, you could create another new button object which always performs an additional action, for example, not found in the original button definition. All you need to do is take the basic blueprint of the original button object, override and extend its definition by adding the new function to it:

REBOL []

tanbtn: make svv/vid-styles/btn [
    color: tan
    size: 400x50
    action: func [] [alert "I've been clicked"]
]
append svv/vid-styles 'tanbtn
append svv/vid-styles tanbtn

view layout [
    btn "Click me and nothing happens"
    btn "I'm just another button object"
    tanbtn "Click me and my default message appears"
    tanbtn "I'm just another tan button object"
]

The tan button object can be used anywhere an original 'btn object from 'svv can be used. The new color, size, and action (the alert message) exist automatically as properties of each new tan button.

An important point about this whole object creation and inheritance process is that the code which creates the 'tanbtn object could be saved in a separate file named, for example, newbtns.r:

REBOL []
tanbtn: make svv/vid-styles/btn [
    color: tan
    size: 400x50
    action: func [] [alert "I've been clicked"]
]
append svv/vid-styles 'tanbtn
append svv/vid-styles tanbtn

Then, anyone who wants to use the tan button object can simply import and use the library like this:

REBOL []
do %newbtns.r
view layout [
    btn "Click me and nothing happens"
    btn "I'm just another button object"
    tanbtn "Click me and my default message appears"
    tanbtn "I'm just another tan button object"
]

The tan button object inherits all the existing functionality of the original 'svv 'btn object (which in turn is derived from lower level GUI objects, which are in turn created using graphic draw commands, event management functions, etc.). Either the 'btn or 'tanbtn objects can be used, in the exact same way, as a basis for designing more new button objects with specialized features.

1.4 Why is this Useful?

The encapsulation and inheritance properties of objects allow developers to separate the development of portions of programs, so they can be worked on by different groups of coders. Each group only needs to work on making their objects perform according to a given specification (i.e., each object needs to contain a certain set of available functions, parameters, and variables which operate as expected). In this way, objects work like little black boxes, or generic building blocks, which just do what they're supposed to do, and which can be assembled as needed to form larger parts of programs. You could potentially create objects, for example, which perform all the work required of cells in a spreadsheet program, players in a game, ports in a network application, etc. Developers of each object can make changes and improvements to the way their object operates, without affecting the way users of the object need to interact with it in code, as long as the specifications of the object (the names of functions, parameters, and variables it contains) stay the same. The definition of the functions, parameters, and variables, such as the color, look, and computations performed by a GUI button, or the function used to compute an account property, however, can be improved, without other developers having to change any code in their part of the larger program. This allows for more modular and simplified development by both users and designers of the objects in any program.

2. A More Detailed Look at Rebol Fundamentals

2.1 Data Types

Rebol recognizes more than 40 native data types, and new ones can be defined by the user. The 'type function determines a value's data type. Here are a few examples:

a-string: "Hello World"                    type? a-string
an-integer: 3874904                        type? an-integer
a-decimal: 7348.39                         type? a-decimal    
web-site: http://musiclessonz.com          type? web-site 
email-address: user@website.com            type? email-address      
the-file: %/c/myfile.txt                   type? the-file 
money-amount: $343.56                      type? money-amount
color-tuple: 123.54.212                    type? color-tuple
a-character: #"z"                          type? a-character
a-word: 'asdf                              type? a-word                   
html-tag: <br>                             type? html-tag    
binary-info:  #{ddeedd}                    type? binary-info    
image: load http://rebol.com/view/bay.jpg  type? image
a-sound: load %/c/windows/media/tada.wav   a-sound/type

Here are some casting examples, which convert data from one type to another:

to-decimal an-integer     ; Convert values TO different types ("cast")
to-string web-site        ; now the web site URL is surrounded by quotes
form web-site             ; "form" also converts various values to string
form $29.99
alert form $29.99         ; the alert function REQUIRES a string parameter
alert $29.99              ; (this throws an error)
5 + 6                     ; you can perform math operations with integers
"5" + "6"                 ; (error) you can't perform math with strings
(to-integer "5") + (to-integer "6")    ; this eliminates the math problem
to-pair [12 43]           ; creates a coordinate pair
as-pair 12 43             ; a better way to create a coordinate pair
to-binary 123.54.212      ; convert a REBOL color value to hex color value
to-binary request-color   ; convert the color chosen by the user, to hex
to-tuple #{00CD00}        ; convert a hex color value to REBOL color value
form to-tuple #{00CD00}   ; covert the hex color value to a string
write/binary %floorplan8.pdf debase read clipboard://  ; email attachment

REBOL computes values appropriately for type:

6:30am + 00:37:19
now  
now + 0:0:59  
now - 10   
23x54 + 19x31
22x66 * 2
22x66 * 2x3
192.168.1.1 + 0.0.0.37
11.22.33.44 * 9        ; note that each IP segment value is limited to 255
0.250.0 / 2            ; an easy way to adjust color values
$29.99 * 5
x: 12  y: 33  q: 18  p: 7
(as-pair x y) + (as-pair q p)  ; very common in graphics apps using coords
remove form to-money 1 / 233
remove/part form to-time (1 / 233) 6

Random data values can be generated, appropriately according to type:

random/seed now/time   ; always use this line to get real random values
random 50              ; a random number between 0 and 50
random 50x100          ; left side is limited to 50, right limited to 100
random 222.222.222     ; each segment is limited to #s between 0 and 222
random $500
random "asdfqwerty"    ; a random mix of the given characters
random [1 2 3 4 5]     ; a randomly sorted list of values

2.2 A Variety of Additional Short Series Operation Examples

Here are a variety of series operation examples:

new-block: copy []  ; a new, empty block
some-names: ["John" "Bill" "Tom" "Mike"]   ; a list of text strings
more-names: copy some-names   ; a copy of the above list
probe more-names
same? more-names some-names   ; NOT the exact same list, but a copy
same-names: some-names   ; THESE labels now refer to the EXACT SAME list
probe same-names
same? same-names some-names ; change some-names and same-names CHANGES TOO
sortednames: sort copy some-names  ; "copy" keeps some-names from changing
sortednames: sort some-names  ; here, the some-names block has been sorted
print first sortednames  ; here are 3 different ways to pick the 1st item:
print sortednames/1 
print pick sortednames 1 
print second sortednames   ; 3 different ways to pick the 2nd item:
print sortednames/2
print pick sortednames 2
find some-names "John"
first find some-names "John"
find/last some-names "John" 
select some-names "John"   ; use series like dictionaries
reverse sortednames 
length? sortednames 
head sortednames 
next sortednames 
back sortednames 
last sortednames 
tail sortednames  
at sortednames 2
skip sortednames 1
extract sortednames 3  ; every third item
index? sortednames 
insert (at sortednames 3) "Lee" 
append sortednames "George" 
remove sortednames 
remove find sortednames "Mike" 
change sortednames "Phil" 
change third sortednames "Phil"
poke sortednames 3 "Phil" 
copy/part sortednames 2 
replace/all sortednames "Lee" "Al"
probe form sortednames
probe mold sortednames
join some-names sortednames 
intersect sortednames more-names  
difference sortednames more-names 
exclude sortednames more-names 
union sortednames more-names 
unique sortednames 
clear sortednames
empty? sortednames
probe same-names
probe more-names

index-num: length? more-names
print pick more-names index-num
print pick more-names (index-num - 1)
print pick more-names (random length? more-names)

index-num: ((index? (find more-names "Tom")) - 1)
print pick more-names index-num ; 4 ways to pick items at a variable index
print more-names/:index-num
print compose [more-names/(index-num)]
print reduce [more-names/(index-num)]

"READ" reads data byte-for-byte from file, "LOAD" performs a CONVERSION. "WRITE" writes series byte-for-byte to file, "SAVE" performs CONVERSION:

save %names.txt more-names         ; series data saved to a text file
loaded-names: load %names.txt      ; use "load" to read it into a variable
write %names2.txt mold more-names  ; series saved but WITH SQUARE BRACKETS
loaded-names2: load %names2.txt    ; "load" also correctly loads that file
read-names: to-block read %names.txt  ; "read" requires "to-block" convert
read-names2: to-block read %names2.txt  ; block within a block
probe read-names2                       ; [["John" "Phil" "Tom" "Mike"]]
first read-names2                       ; ["John" "Phil" "Tom" "Mike"]

Working with compressed blocks of data:

write/binary %compressed.dat compress mold more-names  ; compress and save
probe load decompress read/binary %compressed.dat  ; read and decompress
save %compressed.dat compress mold more-names  ; another way to save
probe load decompress load %compressed.dat  ; and load compressed series

Incrementing a counter (produces similar functionality to 'repeat and 'for):

count: 0
foreach item items [
    count: count + 1
    print rejoin ["^/Item #" count ": " item]
]

A nested block:

big-block: [
    [may june july] 
    [ 
        [1 2 3] 
        [
            [yes no]
            [monday tuesday friday]
        ]
    ]
]

Indentation makes the block easier to read, but is not required:

big-block: [[may june july][[1 2 3][[yes no][monday tuesday friday]]]]

probe first big-block          ; 3 ways to get the first item in the block
probe big-block/1
probe pick big-block 1
probe second big-block        ; 3 ways to get the second item in the block
probe big-block/2
probe pick big-block 2 
probe first second big-block     ; 1st block in the 2nd block in big-block
probe big-block/2/1
probe second second big-block    ; 2nd block in the 2nd block in big-block
probe big-block/2/2
probe first second second big-block
probe big-block/2/2/1
probe second second second big-block
probe big-block/2/2/2
probe big-block/2/2/2/1
probe big-block/2/2/2/2
probe big-block/2/2/2/3

A block of contact info:

users: [
    "John Smith" "123 Tomline Lane Forest Hills, NJ" "555-1234"
    "Paul Thompson" "234 Georgetown Pl. Peanut Grove, AL" "555-2345"
    "Jim Persee" "345 Pickles Pike Orange Grove, FL" "555-3456"
    "George Jones" "456 Topforge Court Mountain Creek, CO" ""
    "Tim Paulson" "" "555-5678"
]

Sort a copy of the block by the first column (groups of every 3 consecutive items), Without the 'copy, the original list is permanently changed:

probe sort/skip copy users 3

To sort by any other column, first convert the block to a nested block of blocks (rows of column data):

new-users: copy []
foreach [name address phone] users [
    append/only new-users reduce [name address phone]
] ; append/only inserts blocks as blocks, instead of as individual items
editor new-users

Sort ascending by 2nd field (by address):

field: 2  sort/compare new-users func [a b] [(at a field) < (at b field)]
editor new-users

Sort descending:

field: 2  sort/compare new-users func [a b] [(at a field) > (at b field)]
editor new-users

"Flatten" the block back to it's orginal state (no nested blocks of blocks):

users: copy []
foreach block new-users [append users reduce block]
editor users

Extract columns:

probe extract users 3           ; the name column (every 3rd item)
probe extract/index users 3 2   ; address column (skip 3, starting on 2)
probe extract/index users 3 3   ; phone column (skip 3, starting on 3)

Convert entire block to a string:

probe form users

Get groups of 3 consecutive items:

foreach [name address phone] users [ 
    print rejoin [
        "^/Name:     " name 
        "^/Address:  " address 
        "^/Phone:    " phone 
    ]
]

Print phone numbers for all names that contain the letter "a":

foreach name (extract users 3) [
    if find name "a" [
        print pick users ((index? find users name) + 2)
    ]
]

Append to end of list:

append users ["Joe Thomas" "" "555-321-7654"]

Append variable values ('repend is 'reduce + 'append)

name: "Alex Sharp"  address: "937 Boll Rd"  phone: "555-294-2834"
repend users [name address phone]

Insert at a specific index:

insert (at users 4) [
    "Tom Adams" "321 Way Lane Villageville, AZ" "555-987-6543"
]

Remove single and multiple items:

remove (at users 4)  ; remove 1 item
remove/part (at users 4) 2  ; remove 2 items
change (at users 1) "Jonathan Smith"
remove (at users 1) insert (at users 1) "Jonathan Smith"
foreach item users [
    replace item "John Smith" "Jonathan Smith"
]

Retrieve single and multiple items:

copy/part users 3
copy/part (at users 4) 3
copy at tail users -3
copy/part (at users 7) 3
copy/part (find users "Jim Persee") -3
copy/part (skip (find users "Jim Persee") -6) 3
alert form (copy/part users 3)

chosen: request-list "Choose a person: " (extract users 3)
alert form reduce [copy/part find users chosen 3]
alert reform [copy/part find users chosen 3]
chosen: request-list "Choose an address: " (extract/index users 3 2)
alert reform [copy/part at (find users chosen) -1 3]

Move item positions:

x: ["one" "two" "three" "four" "five" "six"]
move/to (find x "five") 2
print x               ; item position changed

x: ["asdf" "qwer" "zxcv" "uiop" "hjkl" "vbnm"]
y: head clear skip tail x -2
probe y               ; last 2 items removed

Nested blocks:

data: [
    1 2 3 [4 5 6]
    7 8 9 [0 9 8 7 6 5 4 3 2 1]
    3 4 5 [6 3 1 7 8 0] 
]
counter: 1
foreach [col1 col2 col3 col4] data [
    print rejoin [
        "Row: " counter newline
        "Column1: " col1 newline
        "Column2: " col2 newline
        "Column3: " col3 newline
        "Column4 (sorted): " (sort col4) newline newline
    ]
    counter: counter + 1
]

Directories are just lists of files - all series operations work:

foreach file read %. [
    if (suffix? file) = %.tester [
        rename file to-file (replace to-string file ".tester" ".test")
    ]
]
list-dir

foreach line reverse copy system/console/history [print line]

Here's a useful unique string generator demonstrating the 'replace function

replace/all replace/all replace/all replace/all form now/precise trim {
    /} "" ":" "x" "-" "q" "." ""

2.3 Strings

Strings of text work just like blocks of data items - they're just a list of characters. Use all the same functions used to manipulate items in a block, to manipulate the list of characters in a string of text:

the-string: "abcdefghijklmnopqrstuvwxyz"

; 3 different ways to get just the 7th character:

pick the-string 7
the-string/7 
seventh the-string

; get the left 7 characters of the string:

copy/part the-string 7

; get the right 7 characters of the string:

copy at tail the-string -7

; get 7 characters from the middle of the string,
; starting with the 12th character:

copy/part (at the-string 12) 7

; get 7 characters from the middle of the string,
; starting 7 characters back from the letter "m":

copy/part (find the-string "m") -7

; get 7 characters from the middle of the string,
; starting 12 characters back from the letter "t":

copy/part (skip (find the-string "t") -12) 7

; Change "cde" to "123"

replace the-string "cde" "123"

; Several ways to change the 7th character to "7"

change (at the-string 7) "7"
poke the-string 7 #"7"  ; the pound symbol refers to a single character
poke the-string 7 (to-char "7")  ; another way to use single characters
print the-string

; Remove 15 characters, starting at the 3rd position:

remove/part (at the-string 3) 15
print the-string

; Insert 15 characters, starting at the 3rd position:

insert (at the-string 3) "cdefghijklmnopq"
print the-string

; Insert 3 instances of "-+" at the beginning of the string:

insert/dup head the-string "-+ " 3
print the-string

; Replace every instance of "-+ " with " ":

replace/all the-string "-+ "  " "
print the-string

; Get every third character from the string:

extract the-string 3

2.4 File Management and Reading/Writing From/To Varied Data Sources/Protocols

Here are some function examples which demonstrate file management operations:

rename %temp.txt %temp2.txt       ; change file name
write %temp.txt read %temp2.txt   ; copy file
write/append %temp2.txt ""   ; create file (or if it exists, do nothing)
delete %temp2.txt
change-dir %../
what-dir 
list-dir
make-dir %./temp
print read %./
osfile: to-local-file filename   ; REBOL uses its own multiplatform syntax
to-rebol-file osfile  ; Convert from native OS file notation back to REBOL
the-url: http://website.com/subfolder
split-path the-url   ; "split-path" breaks any file or URL into 2 parts

Here are some examples of reading and writing data to and from various data sources and protocols:

print read http://rebol.com  ; "read" retrieves the data from many sources
editor http://rebol.com   ; the built in editor can also read many sources
print read %./   ; the % symbol is used for local files and folders
editor %./
write %temp.txt "test"   ; write takes TWO parameters (file name and data)
editor %temp.txt
editor request-file/only   ; "only" refinement limits choice to 1 file
write clipboard:// (read http://rebol.com)  ; 2nd parameter in parentheses
editor clipboard://
print read dns://msn.com   ; REBOL can read many built in protocols
print read nntp://public.teranews.com 
write/binary %/c/bay.jpg (read/binary http://rebol.com/view/bay.jpg)
write/binary %tada.wav (read/binary %/c/windows/media/tada.wav)
write/binary %temp.dat (compress read http://rebol.com)  ; COMPRESS DATA
print decompress read/binary %temp.dat                   ; DECOMPRESS DATA
print read ftp://user:pass@website.com/name.txt       ; user/pass required
write ftp://user:pass@website.com/name.txt "text"     ; user/pass required
editor ftp://user:pass@website.com/name.txt  ; can save changes to server!
editor pop://user:pass@website.com    ; read all emails in this account
send user@website.com "Hello"   ; send email
send user@website.com (read %file.txt)   ; email the text from this file
send/attach user@website.com "My photos" [%pic1.jpg %pic2.jpg pic3.jpg]

2.5 More About User Defined Functions

Any string or block of data can be treated like a function, using 'do:

some-actions: [
    alert "Here is one action." 
    print "Here's a second action."
    write %/c/anotheraction.txt "Here's a third action."
]
do some-actions

Copy, paste and run any code using 'do:

write clipboard:// {alert "This code was run from the clipboard"}
do read clipboard://

write %some-code.r {
    REBOL [] ; executable code saved to a file must begin with this header
    print rejoin [newpage "The code in %some-code.r just ran." newline]
}
do %some-code.r

write ftp://user:pass@site.com/public_html/some-code.r {
    REBOL []
    print "The code in http://site.com/some-code.r just ran."
}
do http://site.com/some-code.r

You can 'do any rejoined text:

the-word: to-word request-list "choose a word:" (first system/words)
do rejoin ["help " the-word]

'Does is a 'func shortcut, when no parameter list is required:

cls: does [prin "^(1B)[J"]          ; same as "prin newpage"
cls

By default, variables in functions are GLOBAL:

x: 10
change-x-globally: func [y z] [x: y + z]
change-x-globally 10 20
print x

You can change that default behavior with the /local option:

x: 10
change-x-locally: func [y z /local x] [x: y + z]
change-x-locally 10 20
print x

Here's how to include refinement options in your functions:

compute: func [x y /multiply /divide /subtract] [
    if multiply [return x * y]
    if divide   [return x / y]
    if subtract [return x - y]
    return x + y
]
compute/multiply 10 20
compute/divide 10 20
compute/subtract 10 20
compute 10 20

Here's how to include function documentation (used by 'help), and require data types for parameters:

concatenate-string-or-num: func [
    "This function will only concatenate strings or integers."
    val1 [string! integer!] "First string or integer"
    val2 [string! integer!] "Second string or integer"
] [
    join val1 val2
]
help concatenate-string-or-num
concatenate-string-or-num "Hello " "there."  ; this works correctly
concatenate-string-or-num 10 20              ; this works correctly
concatenate-string-or-num 10.1 20.3          ; this creates an error

Using 'do for metaprogramming:

do [
    print "^/This example builds a line of code, and then executes it.^/"
    function: ask "Enter a function, such as 'print' or 'editor':  "
    parameter: ask "Enter a parameter, such as some random text:  "
    print rejoin [function { "} parameter {"}]
    do rejoin [function { "} parameter {"}]
    do compose [(to-word function) (parameter)]
    print "That's a very simple way to accomplish metaprogramming tasks."
]

Save functions to library files. Import the libraries with 'do:

write %imported-func.r {
    REBOL [title: "play-sound"]
    play-sound: func [sound-file] [
        wait 0
        insert sound-port: open sound:// load sound-file
        wait sound-port
        close sound-port
    ]
}
do %imported-func.r
play-sound %/C/WINDOWS/Media/chimes.wav

Get the code of any function, as a text string:

editor mold :read-cgi

Redefine a built-in (mezzanine) function:

request: do replace/all mold :request "bold" ""
request/ok/type "An alert without bold text" 'alert

2.6 GUI Event Management

"Feel" and "Engage" together detect events:

view layout [
    text "Mouse me." feel [
        engage: func [face action event] [
            if action = 'up [print "You just released the mouse."]
        ]
    ]
]

The variables 'f, 'a, and 'e are shortcuts used to refer to face, action, and event. For example, e/offset gets the coordinate position of a mouse click:

print "Click anywhere in the window, then click the text."
view center-face layout [
    size 400x200
    box 400x200 feel [
        engage: func [f a e] [
            print rejoin ["Mouse " a " at " e/offset]
        ]
    ]
    origin 
    text "Click me" [print "Text clicked"] [print "Text right-clicked"]
    box blue [print "Box clicked"]
]

Here's some generic click and drag code:

movestyle: [
    engage: func [f a e] [
        if a = 'down [initial-position: e/offset]
        if find [over away] a [
            f/offset: f/offset + e/offset - initial-position
            show f
        ]
    ]
]
view layout [
    size 600x400
    text "This is some text" feel movestyle
]

This drag code ensures that the dragged item is layered as the top face in the z-order of the layout:

movestyle: [
    engage: func [f a e] [
        if a = 'down [
            initial-position: e/offset
            remove find f/parent-face/pane f
            append f/parent-face/pane f
        ]
        if find [over away] a [
            f/offset: f/offset + (e/offset - initial-position)
        ]
        show f
    ]
]
view layout/size [
    style moveable-object box 20x20 feel movestyle
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    text "This text and all the boxes are movable" feel movestyle
] 600x440

This example follows all mouse movements:

view center-face layout [
    size 600x440
    at 270x209 b: btn "Click Me!" feel [
        detect: func [f e] [
            if e/type = 'move [
                if (within? e/offset b/offset 59x22) [
                    b/offset: b/offset + ((random 50x50) - (random 50x50))
                    if not within? b/offset -59x-22 659x462 [
                        b/offset: 270x209
                    ]
                    show b
                ]
            ]
            e
        ]
    ]
]

To trap other events, use 'insert-event-func. This example traps and responds to close events:

insert-event-func [
    either event/type = 'close [
        really: request "Really close the program?"
        if really = true [unview]
    ] [event]  ; always return other events
]
view center-face layout [size 600x400]

This example traps resize events:

insert-event-func [
    either event/type = 'resize [
        fs: t1/parent-face/size
        t1/offset: fs / 2x2
        t2/offset: t1/offset - 50x25
        t3/offset: t1/offset - 25x50
        show gui  none
    ] [event]
]
svv/vid-face/color: white
view/options gui: layout [
    across
    t1: text "50x50"
    t2: text "- 50x25"
    t3: text "- 25x50"
] [resize]

2.7 More Various GUI Examples, Techniques, Widgets (some grids), Etc.

Some more built in widget styles:

print "GUI Output:^/"
view layout [
    h1 "Some More GUI Widgets:"
    box red 500x2
    drop-down 200 data system/locale/months [
        a/text: join "Month:  " value show a
    ]
    a: field
    slider 200x18 [bar1/data: value show bar1]
    bar1: progress
    scroller 200x16 [bar2/data: value show bar2]
    bar2: progress
    across 
    toggle "Click here" "Click again" [print value]
    rotary "Click" "Again" "And Again" [print value]
    choice "Choose" "Item 1" "Item 2" "Item 3" [print value]
    return
    x: radio y: radio z: radio
    btn "Get Radio States" [print [x/data y/data z/data]]
    return
    led
    arrow
    below
    code "Code text"
    tt "Typewriter text"
    text "Little Text" font-size 8
    title "Centered title" 500
]

You can fit images on most widgets:

view layout [
    area 400x400 load http://rebol.com/view/bay.jpg effect [
        Fit Flip Emboss 
    ]
]

And there are many more effects:

effects:  [
  invert contrast 40 colorize 0.0.200 gradcol 1x1 0.0.255 255.0.0 tint 100
  luma -80 multiply 80.0.200 grayscale emboss flip 0x1 flip 1x0 rotate 90
  reflect 1x1 blur sharpen aspect tile tile-view
]

Gradients (color fades) can be applied as an effect:

view layout [area effect [gradient red blue]]

view layout [
    size 500x400
    backdrop effect [gradient 1x1 tan brown]
    box effect [gradient 123.23.56 254.0.12]
    box effect [gradient blue gold/2]
]

Switching between separate panes on a single window layout:

gui: layout [
    across
    btn "Fields"      [window/pane: pane1 show window]
    btn "Text List"   [window/pane: pane2 show window]
    return
    window: box 400x200
]
pane1: layout/tight [field 400 field 400 area 400]
pane2: layout/tight [text-list 400x200 data system/locale/days]
window/pane: pane1
view center-face gui

Changing the global face color property:

svv/vid-face/color: white
alert "New global background color is now white."

Responding to keys:

view center-face layout [
    size 600x440 
    h3 "Press the left or right arrow key"
    key keycode [left]  [alert "You pressed the LEFT arrow key"]
    key keycode [right] [alert "You pressed the RIGHT arrow key"]
    btn #"a" "Click Me or Press the 'a' Key" [alert "clicked or pressed"]
]

Here's a useful scipt to show all key codes:

insert-event-func func [f e] [if e/type = 'key [print mold e/key] e]
view layout [text "Type keys to see their character/keycode"]

How to refer to the main layout window:

view gui: layout [
    btn1: btn "Button 1"
    btn2: btn "Remove all widgets from window" [
        foreach item system/view/screen-face/pane/1/pane [
            remove find system/view/screen-face/pane/1/pane item
        ]
        show gui
    ]
]

Graphic collision detection using the 'within function:

view center-face layout [
    size 400x400
    btn1: btn red
    at 175x175 btn2: btn green
    box 0x0 rate 0 feel [engage: func [f a e] [if a = 'time [
        btn1/offset: btn1/offset + 5x5
        show btn1
        if within? btn1/offset btn2/offset 1x1 [alert "Collision" unview]
    ]]]
]

A simpler collision example using the 'overlap function:

gui: view/new center-face layout [
    size 400x400
    btn1: btn red
    at 175x175 btn2: btn green
]
forever [
    wait .02
    btn1/offset: btn1/offset + 5x5  show gui 
    if overlap? btn1 btn2 [alert "Collision"]
    if btn1/offset/1 > 300 [alert "done" quit]
]

Use "to-image" to create a screen shot of any layout:

picture: to-image layout [
    page-to-read: field "http://rebol.com"
    btn "Display HTML"
]
save/png %layout.png picture     ; save the image to a file
browse %layout.png

A simple info screen:

flash "Waiting..."  wait 3  unview
inform layout [btn "Click Me" [flash "Waiting..." wait 3 unview]]

Here are all the main GUI words that you should get to know:

VID-STYLES--GUI-WIDGETS: [
    face blank-face IMAGE BACKDROP BACKTILE BOX BAR SENSOR KEY BASE-TEXT
    VTEXT TEXT BODY TXT BANNER VH1 VH2 VH3 VH4 LABEL VLAB LBL LAB TITLE
    H1 H2 H3 H4 H5 TT CODE BUTTON CHECK CHECK-MARK RADIO CHECK-LINE
    RADIO-LINE LED ARROW TOGGLE ROTARY CHOICE DROP-DOWN ICON FIELD INFO
    AREA SLIDER SCROLLER PROGRESS PANEL LIST TEXT-LIST ANIM BTN BTN-ENTER
    BTN-CANCEL BTN-HELP LOGO-BAR TOG
]
LAYOUT-WORDS: [
    return at space pad across below origin guide tab tabs indent style
    styles size backcolor backeffect do
]
STYLE-FACETS--ATTRIBUTES: [
    edge font para doc feel effect effects keycode rate colors texts help
    user-data with bold italic underline left center right top middle
    bottom plain of font-size font-name font-color wrap no-wrap as-is
    shadow frame bevel ibevel
]
SPECIAL-STYLE-FACETS: [
    ARROW: [up right down left]  ROTARY: data  CHOICE: data  DROP-DOWN: 
    [data rows]  FIELD: hide  INFO: hide  AREA: hide  LIST: [supply map
    data]  TEXT-LIST: data  ANIM: [frames rate]
]

The especially powerful 'list widget can create data grids, not just from text fields, but from ANY types of widgets:

y: read %.   c: 0   x: copy []
foreach i y [append/only x reduce [(c: c + 1) i (size? to-file i)]]
slider-pos: 0
view center-face layout [
    across space 0
    the-list: list 400x400 [
        across  space 0x0
        text 50 purple
        text 250 bold [editor read to-file face/text]
        text 100 red italic
        return box green 400x1
    ] supply [
        count: count + slider-pos
        if none? q: pick x count [face/text: none exit]
        face/text: pick q index
    ]
    scroller 16x400 [
        slider-pos: (length? x) * value
        show the-list
    ]
]

A more powerful grid example implemented using the 'list widget:

REBOL [title: "Table/Grid/Listview Example"]

headers: ["Numbers" "Text" "Dates"]

x: [
    [1   "1"   1-1-2012]
    [11  "11"  1-2-2012]
    [2   "2"   1-3-2012]
]

do decompress #{
789CC518C98EDB36F4AEAF78500FB11228B2074D0AA8B3A01F904BAF860EB245
D9CAD0A2225133720CFF7B1F77D24BE324456A60C626F9F69D1C5B4A86015E4A
3A922778B3199B7445D9FA1996F6670E8763118D21E004CB298735EBF6B02CCE
4EC9AEE3FB74E8CA3581A5B7C8615E447B8D3741B46674DCB5430E94B41BBE7D
822D292BD20F91FA36FC25F8E118F5A423258706341E2C23C04FD975A4ADC0C7
819E7C664D0BCB781B237C9C713271888BA83821CD9946F0B7A355734AEFCDB0
1F38D945949595DA22550EF5D8AE615995BC4CEB8612C87AF26524032FB4644D
0D7AC783CACD9E5C65ACA5FB4C625B8842A9C5B9309D26253ED672FA5B08E3B0
2CD8B065AF401BB9161A0FE50BF945320B56C2A6E1194C2885B45C4D4BFECBCD
56A3BDAE98CAC5303870D663C82C606682B29E929388331FC12908D265119C0B
529F610E33839EC22241D2211517C28E1E740DFEAB279835F00E3E271060845C
14B2B40826554FAA11D3CE91B2B09E8E3692FE3D68FE37775D720A29D75BE851
CAE9C47EDA78B5D51D819CD24E43119B4E8B7A72BAB29EA7CA4546DBBA21B432
0A92866F490F128CF55814726819F7D69E4062335BB35D57F618F79A5A092BA4
35C3DA5582A49CC02388E54A2F9594C50FD0B9BF484719CEF8B4889E0956E075
CF28350AAA555AEED8D85A4F0E69C7B01ACB2F0CBB00C6B85A1D3EBAF4C0EC58
6A44BB5584D0F798030666AE2B05CD842F0CB32CA01788AF7F0C14F5E8C9D07C
25E9A66F6C25EB48BF262D2F37C468213A970043DAB268672F0D79CD501942DA
B4C6369475654BB2452680E04F9194F3692E516983012BB6B345EE2FE02D383E
279077B9E598DD2131AFDF4948AE85E9D18A15AAE951F5B4F6BB4D92681369CC
126D54363D2C3EFA6C25CCD84AE564EEA314A0561D6F18561B212FD2142A032D
F76CE4E0357865CBC259B56E30D92B46861FB1A3C4F0DC03336B14A1A7AF750A
EF1709B22DAB2AA54D4B0CD3B014600B9E647F6E50890DE698A927A29567BCE1
58552A529723C5C6FE5755A9E163C082228BC46F79EC178F9D4F89BDF4E9DA45
B4E0040F22447BC2C7BE5501DA92D754910C6BFB597B083C278ABBAE478E80C2
8F639D15ED4030B7A5CB44EE4E5280C48777992B9CB363588AFF2343FD8D7439
0345348FE1E76C8407BC1F09DC3FDA0E6007AFBF150B88552B535A42FC141721
0D254A60095FFD33E52512A355FA5D7A7F123CEA9EEDBE2B38844B6E60A3C90B
BB7AC4D138B399A1206C970086CECC882E7792DBEDF929B4A625736E5161B20C
855126358089D5C66F0C3BAC5463D7511C08825E475E48FB84718B851F9BA1C8
75EC8F0C1BDFEBB6E1A2D2FA7B77BFCFDFCBBF0F1F9404122FD7E8EF5489370A
B6ACC52BC297DC28E2F31026CD4DB600991A6EEDA2DD8256BB20D4DD1C99CF3D
01E4A1EA2F6BDBBC3C1692F717116E44CCA6036D2A34F65E8C2DDA0CED062BBD
9D06B0DF12BF3B3762E701DE8C1DF635373D288238318AFB831E46826B442DF9
BB99643DAAF29CDF88E90B6070E1F1012ED5A230287CA94BCAD38ABD62540DBC
94C2E31493034E69753D104F3C214D8AF1A0653C0463573F7CC5D140F8B96E7A
8CD4966C4A8E898CB54F51C442EFD14F02648C3BE90ED36BC335621AEA01165A
7966D44E2CEEA5DD5B2860642E12ADF3299DF0EC766A9764F24FF0F7454ADBAB
525D3BB926D329BC91E8F2FE35796485D04E399DC44E288939C1E21EED2FBCAC
530112C4101C9CA78E36826FC691FC8E10AE2F86B748CC4B0187C11A6CDB6075
E11F5EB590A8854173DD9FB640F3A95828F5C905448C59A46A785064B04EF7AE
C4B093023363508A81D1543E6C0AB5AC69A26BE8CD5C6F190F19664AB59B4B58
7869D53532E873A691AAC3E0B6182AF9EDA1514EDD29CCA70FF3C88E856E86C6
A39919783FCEFD693A89BE3511FFD0A86DEE25105CF0641F066B66D1B5223DD8
B9195A154429B5151F4ABC350D628693CF5FE666211DAF59C36AE49CB5560B25
2476315861F83FAB1E0B2BECDCD1B71EBD9C2C6650B03E39887FDB23621E72C3
F888C301354F5B4396E319D48450701DF028E604317059979EB1928C0C79FBB6
2173F1DC44B9D156E916F7312CFE9850D72014A5B91FECD483D32366E2536C1F
19F797225CE5A1BE8EA9FB9A0B07FF2E2D6DBF2694828C5E0D2015B74969A1CF
FDF7B34E101F44D4AE90721C3D35507DF3702AE799C15E211C6139A5AA53F45A
7199BB71DC05971DF4C3801AF6C08E7DFAA299EBBBBE78E5A0DA7C3A2FFC7BF9
5B252884CED06E385EE3FA4CF6E26FCD2AA43A765884DC7304A40BF35A118089
F12404BC0CD761894BCF68DECDAF039F5356D0C7C87BF1B6CFC2764FBD093BD5
CC83F03FD2FC2B1641170000
}
view center-face gui: layout gui-block

Other options such as coloring rows, and specifying column data types, using the compressed grid code above, are demonstrated in the following example. This is a critically useful tool for data entry, visualization, and demonstration:

REBOL [title: "Table/Grid/Listview Example With Expanded Features"]

headers: ["Numbers" "TEXT (Note Sort)" "Dates"] ; REQUIRED COLUMN LABELS

; ALL THESE ADDITIONAL SETUP PARAMETERS ARE *** OPTIONAL ***:

x: [[1 "1" 1-1-2012][11"11"1-2-2012][2"2"1-3-2012]]  ; some default data

colors: [blue black red]    ; specify column colors like this
empty-space: 235            ; size of blank GUI area to appear below grid
svv/vid-face/color: white   ; default GUI face color

; Here's how to include GUI layout code to appear above the grid: 

gui-block: {
    h3 "RIGHT-CLICK/DRAG HEADERS TO RESIZE COLUMNS.  RESIZE WINDOW..."
    text "Click headers to sort (note that sort is DATA-TYPE SPECIFIC)."
    text "Notice Arrow Keys, PgUp/PgDn Keys, Scroll Bar, and highliting"
    text "Click any cell to edit data. Buttons load and save data to HD."
}

; The following line automatically fits grid to resized GUI window:

insert-event-func [either event/type = 'resize [resize-fit none] [event]]

do decompress #{
    789CC518C98EDB36F4AEAF78500FB11228B2074D0AA8B3A01F904BAF860EB245
    D9CAD0A2225133720CFF7B1F77D24BE324456A60C626F9F69D1C5B4A86015E4A
    3A922778B3199B7445D9FA1996F6670E8763118D21E004CB298735EBF6B02CCE
    4EC9AEE3FB74E8CA3581A5B7C8615E447B8D3741B46674DCB5430E94B41BBE7D
    822D292BD20F91FA36FC25F8E118F5A423258706341E2C23C04FD975A4ADC0C7
    819E7C664D0BCB781B237C9C713271888BA83821CD9946F0B7A355734AEFCDB0
    1F38D945949595DA22550EF5D8AE615995BC4CEB8612C87AF26524032FB4644D
    0D7AC783CACD9E5C65ACA5FB4C625B8842A9C5B9309D26253ED672FA5B08E3B0
    2CD8B065AF401BB9161A0FE50BF945320B56C2A6E1194C2885B45C4D4BFECBCD
    56A3BDAE98CAC5303870D663C82C606682B29E929388331FC12908D265119C0B
    529F610E33839EC22241D2211517C28E1E740DFEAB279835F00E3E271060845C
    14B2B40826554FAA11D3CE91B2B09E8E3692FE3D68FE37775D720A29D75BE851
    CAE9C47EDA78B5D51D819CD24E43119B4E8B7A72BAB29EA7CA4546DBBA21B432
    0A92866F490F128CF55814726819F7D69E4062335BB35D57F618F79A5A092BA4
    35C3DA5582A49CC02388E54A2F9594C50FD0B9BF484719CEF8B4889E0956E075
    CF28350AAA555AEED8D85A4F0E69C7B01ACB2F0CBB00C6B85A1D3EBAF4C0EC58
    6A44BB5584D0F798030666AE2B05CD842F0CB32CA01788AF7F0C14F5E8C9D07C
    25E9A66F6C25EB48BF262D2F37C468213A970043DAB268672F0D79CD501942DA
    B4C6369475654BB2452680E04F9194F3692E516983012BB6B345EE2FE02D383E
    279077B9E598DD2131AFDF4948AE85E9D18A15AAE951F5B4F6BB4D92681369CC
    126D54363D2C3EFA6C25CCD84AE564EEA314A0561D6F18561B212FD2142A032D
    F76CE4E0357865CBC259B56E30D92B46861FB1A3C4F0DC03336B14A1A7AF750A
    EF1709B22DAB2AA54D4B0CD3B014600B9E647F6E50890DE698A927A29567BCE1
    58552A529723C5C6FE5755A9E163C082228BC46F79EC178F9D4F89BDF4E9DA45
    B4E0040F22447BC2C7BE5501DA92D754910C6BFB597B083C278ABBAE478E80C2
    8F639D15ED4030B7A5CB44EE4E5280C48777992B9CB363588AFF2343FD8D7439
    0345348FE1E76C8407BC1F09DC3FDA0E6007AFBF150B88552B535A42FC141721
    0D254A60095FFD33E52512A355FA5D7A7F123CEA9EEDBE2B38844B6E60A3C90B
    BB7AC4D138B399A1206C970086CECC882E7792DBEDF929B4A625736E5161B20C
    855126358089D5C66F0C3BAC5463D7511C08825E475E48FB84718B851F9BA1C8
    75EC8F0C1BDFEBB6E1A2D2FA7B77BFCFDFCBBF0F1F9404122FD7E8EF5489370A
    B6ACC52BC297DC28E2F31026CD4DB600991A6EEDA2DD8256BB20D4DD1C99CF3D
    01E4A1EA2F6BDBBC3C1692F717116E44CCA6036D2A34F65E8C2DDA0CED062BBD
    9D06B0DF12BF3B3762E701DE8C1DF635373D288238318AFB831E46826B442DF9
    BB99643DAAF29CDF88E90B6070E1F1012ED5A230287CA94BCAD38ABD62540DBC
    94C2E31493034E69753D104F3C214D8AF1A0653C0463573F7CC5D140F8B96E7A
    8CD4966C4A8E898CB54F51C442EFD14F02648C3BE90ED36BC335621AEA01165A
    7966D44E2CEEA5DD5B2860642E12ADF3299DF0EC766A9764F24FF0F7454ADBAB
    525D3BB926D329BC91E8F2FE35796485D04E399DC44E288939C1E21EED2FBCAC
    530112C4101C9CA78E36826FC691FC8E10AE2F86B748CC4B0187C11A6CDB6075
    E11F5EB590A8854173DD9FB640F3A95828F5C905448C59A46A785064B04EF7AE
    C4B093023363508A81D1543E6C0AB5AC69A26BE8CD5C6F190F19664AB59B4B58
    7869D53532E873A691AAC3E0B6182AF9EDA1514EDD29CCA70FF3C88E856E86C6
    A39919783FCEFD693A89BE3511FFD0A86DEE25105CF0641F066B66D1B5223DD8
    B9195A154429B5151F4ABC350D628693CF5FE666211DAF59C36AE49CB5560B25
    2476315861F83FAB1E0B2BECDCD1B71EBD9C2C6650B03E39887FDB23621E72C3
    F888C301354F5B4396E319D48450701DF028E604317059979EB1928C0C79FBB6
    2173F1DC44B9D156E916F7312CFE9850D72014A5B91FECD483D32366E2536C1F
    19F797225CE5A1BE8EA9FB9A0B07FF2E2D6DBF2694828C5E0D2015B74969A1CF
    FDF7B34E101F44D4AE90721C3D35507DF3702AE799C15E211C6139A5AA53F45A
    7199BB71DC05971DF4C3801AF6C08E7DFAA299EBBBBE78E5A0DA7C3A2FFC7BF9
    5B252884CED06E385EE3FA4CF6E26FCD2AA43A765884DC7304A40BF35A118089
    F12404BC0CD761894BCF68DECDAF039F5356D0C7C87BF1B6CFC2764FBD093BD5
    CC83F03FD2FC2B1641170000
}

; APPEND ANY WIDGETS AND/OR GUI CODE TO APPEAR BELOW THE GRID, HERE:

append gui-block [

    ; REPLACE 'BTN' WITH 'KEY' TO HIDE BTNS AND STILL USE KEY SHORTCUTS.
    ; CHANGE/REMOVE BUTTONS AND/OR KEYBOARD SHORTCUTS AS NEEDED:

    text "" return
    btn "Insert (Ins)" keycode [insert] [add-line] 
    btn "Remove (Del)" #"^~" [remove-line]  
    btn "Move (CTRL+M)" #"^M" [move-line]
    btn "Grow (+)" #"+" [resize-grid 1.333]
    btn "Shrink (-)" #"-" [resize-grid .75]
    btn "Fit (CTRL+R)" #"^R" [resize-fit]
    return
    btn "Load Blocked (CTRL+O)" #"^O" [load-blocked/request %blocked.txt]
    btn "Save Blocked (CTRL+S)" #"^S" [save-blocked/request %blocked.txt]
    btn "Load Flat (CTRL+U)" #"^U" [load-flat/request %flat.txt]
    btn "Save Flat (CTRL+F)" #"^F" [save-flat/request %flat.txt]

; LOAD A DEFAULT DATA *FILE HERE (instead of specifying it in code above):
; Note that the "load-flat" and "save-flat" functions load "flat" blocks,
; which are simply long sequences of data values.  The "load-blocked" and
; "save-blocked" functions load block which have rows enclosed inside
; deliniated blocks.  All of those functions provide an optional
; "/request" refinement that allows the user to select a file:

    ;  do [load-blocked %blocked.txt] 

]
view/options center-face gui: layout gui-block [resize]

2.8 Embedding Files (images, sounds, binary executables, etc.) in Code

Use this script to embed files:

system/options/binary-base: 64
editor picture: compress to-string read/binary to-file request-file/only

Here's how you can use the data above:

view layout [image load (to-binary decompress picture)]

Here's an example of some image data created using the script above:

logo-pic: load to-binary decompress #{
789C018A0375FC89504E470D0A1A0A0000000D49484452000000640000001808
020000008360CFB90000001374455874536F667477617265005245424F4C2F56
6965778FD916780000033249444154789CD599217402310C86F7CE6227B1481C
1637874362B1382C1687C4A15168240A89C5A2B058ECDEBE47DFFA429276DCEE
10FDCD582F97267FD33F2D7CF47ABDCF32D1ED76E7F3F9ED76FB4EE0743A8D46
A3B6A683A80FFE540562381C1E8FC7144D12DBEDB6951C3B9D4E91648DC7E34C
41B925465D349C14A2CA230BA65EA729E27C3E37CCB43CB228905A3525B1DBED
9A4CED93851C7C193088A0667C0D0603FB5640BFDFB7F648C0D0836B1C41C22E
11D7EBF57038F074BFDF534429BE2693891B4626CE1C59BC7CB95CDC99EEF7FB
66B349F922D65A4B4A8DE0D0B547B9DD85212B6B4CB4D3E994B055FEE8943566
30134626BBDA64052C974BD757A637B1DA2E599959A05EE61F4032D62C55EFBC
6EED01878954188DC80AE714C07126D24F91BBBE6265A129B3D96C2A4085BB64
459FEBF51A1B2692E5A9FA17A428B562EBE595A1F29650AD5C6B9525FD4621E0
A95D73491606F9046C94101A06178B4518E19122023655DA184B03ECA15BE98E
6D9D302E536E8D2C96A5FF0061458FEE9EAA045958720EDCFC82CF145A9E2C7C
52BC6CF0503B8C2B2200DAACD24698A4B710361E6421930E05A85E9484BE51B3
0885AE9727CB22A5591981B73D1AC6A58D2ABD5892DF46C5993DCFF25BC8828E
14538AACEB3390A43C59D890213B5D2AA3D2AC3C59ABD54ACE2E85C29E36DE42
162B8C0AC47F0942B512972CCCF0D91170ED6594ECC130288549ED44744DE52C
771381C571D5AFEDB14B2E79CB022F13C834A056049EFCE35C2A7449877A2B00
2D872635082FEA2D267D8BC047AD910D3875CE9247078A826259FC8234F264E1
9FAD4AAC52015465D973193B3755B611B417FB562A0C66C77EF7001F5463FD83
2CF20F83B2B8E0C22DAE760FA556B32AAF87B86A18C18259CFAA3567C250C7C3
1AE72CD95350531BD93FAE3B6CEADB33188174FCBBD77B7B7A0841DAB6C3EBEE
F13DE8696B6455E222ADCE23F162ECF644064709A47AA8FD3632BFAD78EA5E92
D947500C3BB04CAD419F3D5B05580DC127118E3D2866CAFB8AC6CAFCEB68F895
56796455CF47AAD741F5B957D4D751245980BD569729B723D742A964558FFB4D
EAB6A440BF6ACE54157EB028F7A730B695BDF749D05EA9C1B612C4CF0F396EDC
8E943F5C020000000049454E44AE426082CAEBA2D78A030000
}  
view layout [image logo-pic]

2.9 Running Command Line Applications

You can run executable functions using the 'call function. See "help call" to see the many available refinements of 'call:

call/show "notepad.exe c:\config.sys"   ; run OS shell command

3. Ports

Rebol "ports" are created with the 'open function:

help open

Ports enable fine grained access to data sources such as files, email, network connections, etc. This line:

write/append %temp.txt "1234"

Is the same as:

temp: open %temp.txt
append temp "1234"
close temp

See all the properties of a port object using "probe":

temp: open %temp.txt
probe temp
close temp
temp: open %temp.txt
print temp/date
print temp/path
print temp/size
close temp

Just one of the properties enabled by opening a file port includes setting read, write, and execute permissions for the file:

my-file: open %temp.txt
set-modes my-file [
    world-read: true
    world-write: true
    world-execute: true
]
close my-file

Be sure to examine all the other properties of a port to see how data is handled under the hood:

write %temp.txt ""
print read %temp.txt
temp: open %temp.txt
append temp "1234"
print temp/state/inBuffer
print read %temp.txt
update temp
print read %temp.txt
temp: head temp
insert temp "abcd"
print temp/state/inBuffer
print read %temp.txt
close temp
print read %temp.txt
append temp "1q2w3e4r"  ; (error)

Fine grained access, for example, to read very large files can be managed with the port structure:

x: open/direct/lines %input.txt
while [not empty? data: copy/part x 10] [
   probe data
   ask "continue..."
]
close file

3.1 Email Ports

Ports allow you to deal with data sources in ways which aren't possible using other functions. For example, this example requires download of ALL mail in the account, just to read the second message:

print second read pop://user:pass/site.com

The port version actually only downloads a single message from the account port. Notice that ports respond to series functions:

my-email: open pop://user:pass/site.com
print second my-email

3.2 Console Ports

Access to the console can also be manipulated with a port structure:

print ""
q: open/binary/no-wait console://
forever [if wait q [print join "You typed:  " to-integer copy q]]

q: open/binary/no-wait console:// 
while [120 <> x: to-integer copy wait q] [print join "You typed:  " x]
print "Goodbye!" wait 2

3.3 Sound and other Hardware Ports

The port structure is used to access not only data structures, but also hardware and other features. The sound system is set up as a port in Rebol. Play sounds by opening a sound port and inserting the data:

the-sound: load %/c/windows/media/tada.wav
insert s: open sound:// the-sound wait s close s
insert s: open sound:// load %/c/windows/media/tada.wav wait s close s
insert s: open sound:// load request-file/only wait s close s

That data can be a .wav file, or it can be generated by code:

REBOL [title: "Sine Wave Example, by Carl Sassenrath"]
tone: #{}
for phase 1 360 6 [
    val: 128 + to-integer 127 * sine phase
    append tone to-char val
]
q: make sound [rate: 44100  channels: 1  bits: 8  volume: 0.5  data: #{}]
loop 1000 [append q/data tone]
insert s: open sound:// q wait s close s

This example opens a serial port:

port: open serial://port1/9600/8/none/1

3.4 Network Ports

This section demonstrates how to send text and binary data across network ports:

A basic server (run this script first):

REBOL [title: "Server"]
port: first wait open/lines tcp://:55555
print join "Received: " first wait port

A basic client (run this script second, in a separate instance of REBOL):

REBOL [title: "Client"]
port: open/lines tcp://localhost:55555
insert port ask "Send:  "

This app combines a server and a client:

REBOL [title: "Network Text Messenger"]
view layout [ across
    q: btn "Serve" [
        focus g 
        p: first wait open/lines tcp://:8 
        z: 1
    ]
    text"OR"
    k: btn "Connect" [
        focus g 
        p: open/lines rejoin[tcp:// i/text ":8"]
        z: 1
    ]
    i: field form read join dns:// read dns://  
    return
    r: area rate 4 feel [
        engage: func [f a e] [
            if a = 'time and value? 'z [
                if error? try [x: first wait p] [quit]
                r/text: rejoin [x "^/" r/text] 
                show r
            ]
        ]
    ]
    return
    g: field "Type message here [ENTER]" [
        insert p value
        focus face
    ]
]

This app demonstrates how to send binary files across a network port:

REBOL [title: "Network Binary File Transfer"]
; server/receiver - run first:
if error? try [port: first wait open/binary/no-wait tcp://:8] [quit]
mark: find file: copy wait port #""
length: to-integer to-string copy/part file mark
while [length > length? remove/part file next mark] [append file port]
view layout [image load file]
; client/sender - run after server (change IP address if using on 2 pcs):
save/png %image.png to-image layout [box blue "I traveled through ports!"]
port: open/binary/no-wait tcp://127.0.0.1:8  ; adjust this IP address
insert file: read/binary %image.png join l: length? file #""
insert port file

Here's a VOIP intercom:

REBOL [title: "VOIP Intercom"] do [write %ireceive.r {REBOL []
if error? try [port: first wait open/binary/no-wait tcp://:8] [quit]
wait 0  speakers: open sound://
forever [
    if error? try [mark: find wav: copy wait port #""] [quit]
    i: to-integer to-string copy/part wav mark
    while [i > length? remove/part wav next mark] [append wav port]
    insert speakers load to-binary decompress wav
]} launch %ireceive.r
lib: load/library %winmm.dll
mci: make routine! [c [string!] return: [logic!]] lib "mciExecute"
if (ip: ask "Connect to IP (none = localhost):  ") = "" [ip: "localhost"]
if error? try [port: open/binary/no-wait rejoin [tcp:// ip ":8"]] [quit]
mci "open new type waveaudio alias wav"
forever [
    mci "record wav"  wait 2  mci "save wav r"  mci "delete wav from 0"
    insert wav: compress to-string read/binary %r join l: length? wav #""
    if l > 4000 [insert port wav]  ; squelch (don't send) if too quiet
]]

This app demonstrates how to send and receive data via UDP:

REBOL [Title: "UDP Group Chat"]
net-in: open udp://:9905  ; This is UDP, so NO known IP addresses required
net-out: open/lines udp://255.255.255.255:9905
set-modes net-out [broadcast: on]
name: request-text/title "Your name:"
gui: view/new layout [
    a1: area wrap rejoin [name ", you are logged in."] 
    f1: field 
    k1: at 0x0 key #"^M" [
        if f1/text = "" [return]
        insert net-out rejoin [name ":  " f1/text]
    ]
]
forever [
    focus f1
    received: wait [net-in]
    if not viewed? gui [quit]
    insert (at a1/text 1) copy received  show a1
]

4. Shared Code Files (DLLs, So, Dylib libraries, etc.)

To load shared libraries, used the 'load/library function. Give the loaded library a label. This example loads the Windows kernel32.dll library, and labels it 'lib:

lib: load/library %kernel32.dll

Define a Rebol function using the signature of any exported function in the shared library, with "make routine!". Give the exported function a label, define the return value types, and all the required parameter types. The new Rebol function below is labeled 'play-sound. It wraps the "Beep" function from the kernel32.dll library loaded above (labeled 'lib here). It returns an integer value, and requires 2 integer parameters:

play-sound: make routine! [
    return: [integer!] 
    pitch [integer!] 
    duration [integer!]
] lib "Beep"

Here's an example of the 'play-sound function in use. It uses a 'for loop to play every frequecy from 37 to 3987, in steps of 50 hertz, for 50 milliseconds each. Close the library with the 'free function when you're done:

for hertz 37 3987 50 [
    print rejoin ["The pitch is now " hertz " hertz."]
    play-sound hertz 50
]
free lib

Here's a Windows API example which plays an AVI file:

REBOL [title: "AVI example"]
lib: load/library %winmm.dll
mciExecute: make routine! [c [string!] return: [logic!]] lib "mciExecute"
if not exists? %test.avi [
    flash "Downloading test video..."
    write/binary %test.avi read/binary http://re-bol.com/test.avi
    unview
]
video: to-local-file %test.avi
mciExecute rejoin ["OPEN " video " TYPE AVIVIDEO ALIAS thevideo"]
mciExecute "PLAY thevideo WAIT"
mciExecute "CLOSE thevideo"
free lib
quit

A Windows API sound recorder example:

REBOL [title: "Sound Recorder"]
lib: load/library %winmm.dll
mciExecute: make routine! [ 
    command [string!]
    return: [logic!] 
] lib "mciExecute"
file: to-local-file to-file request-file/save/title/file "Save as:" {
    } %rebol-recording.wav
mciExecute "open new type waveaudio alias buffer1 buffer 6"
mciExecute "record buffer1"
ask "RECORDING STARTED (press [ENTER] when done)...^/"
mciExecute "stop buffer1"
mciExecute join "save buffer1 " file
free lib
print "Recording complete.  Here's how it sounds:^/"
insert snd: open sound:// load to-rebol-file file wait snd close snd
print "DONE.^/"

AutoIT DLL example which moves the mouse around the screen:

REBOL [title: "AutoIT DLL example"]
if not exists? %AutoItDLL.dll [
    write/binary %AutoItDLL.dll
    read/binary http://musiclessonz.com/rebol_tutorial/AutoItDLL.dll
]
lib: load/library %AutoItDLL.dll
move-mouse: make routine! [
    return: [integer!] x [integer!] y [integer!] z [integer!]
] lib "AUTOIT_MouseMove"
print "Press the [Enter] key, and your mouse will move to the top"
ask "corner of your screen, and then down diagonally to 200x200:  " 
for position 0 200 5 [
    move-mouse position position 10 
]
free lib
print "^/Done.^/"
halt

Use the Windows API to capture a webcam image:

REBOL [title: "Webcam"]
avicap32.dll: load/library %avicap32.dll
user32.dll: load/library %user32.dll
find-window-by-class: make routine! [
    ClassName [string!] WindowName [integer!] return: [integer!]
] user32.dll "FindWindowA"
sendmessage: make routine! [
    hWnd [integer!] val1 [integer!] val2 [integer!] val3 [integer!]
    return: [integer!]
] user32.dll "SendMessageA"
sendmessage-file: make routine! [
    hWnd [integer!] val1 [integer!] val2 [integer!] val3 [string!]
    return: [integer!]
] user32.dll  "SendMessageA"
cap: make routine! [
    cap [string!] child-val1 [integer!] val2 [integer!] val3 [integer!]
    width [integer!] height [integer!] handle [integer!] 
    val4 [integer!] return: [integer!]
] avicap32.dll "capCreateCaptureWindowA"
view/new center-face layout/tight [
    image 320x240
    across
    btn "Take Snapshot" [
        sendmessage cap-result 1085 0 0
        sendmessage-file cap-result 1049 0 "scrshot.bmp"
        browse %scrshot.bmp
    ]
    btn "Exit" [
        sendmessage cap-result 1205 0 0
        sendmessage cap-result 1035 0 0
        free user32.dll   quit
    ]
]
hwnd: find-window-by-class "REBOLWind" 0
cap-result: cap "cap" 1342177280 0 0 320 240 hwnd 0
sendmessage cap-result 1034 0 0
sendmessage cap-result 1077 1 0
sendmessage cap-result 1075 1 0
sendmessage cap-result 1074 1 0
sendmessage cap-result 1076 1 0
do-events

Use the Windows API to change Rebol's default window title:

tt: "Your Title"
user32.dll: load/library %user32.dll
gf: make routine![return:[int]]user32.dll"GetFocus"
sc: make routine![hw[int]a[string!]return:[int]]user32.dll"SetWindowTextA"
so: :show show: func[face][so[face]hw: gf sc hw tt]
view layout [text 400x400 "No 'REBOL -' in the title bar!"]

Using the usps4cb DLL:

REBOL [title: "USPS Intelligent Mail Encoder"]
unless exists? %usps4cb.dll [
    write/binary %usps4cb.dll read/binary http://re-bol.com/usps4cb.dll
]
GEN-CODESTRING: make routine! [
    t [string!]  r[string!]  c [string!]  return: [integer!]
]  load/library request-file/only/file %usps4cb.dll "USPS4CB"
t: request-text/title/default "Tracking #:" "00700901032403000000"
r: request-text/title/default "Routing #:" "55431308099"
GEN-CODESTRING t r (make string! 65)
alert first second first :GEN-CODESTRING

An MP3 player using libwmp3.dll:

REBOL [Title: "MP3 Jukebox"]
if not exists? %libwmp3.dll [
    write/binary %libwmp3.dll
    read/binary http://musiclessonz.com/rebol_tutorial/libwmp3.dll
]
lib: load/library %libwmp3.dll
Mp3_Initialize: make routine! [
    return: [integer!]
] lib "Mp3_Initialize"
Mp3_OpenFile: make routine! [
    return: [integer!] 
    class [integer!] 
    filename [string!]
    nWaveBufferLengthMs [integer!]
    nSeekFromStart [integer!] 
    nFileSize [integer!]
] lib "Mp3_OpenFile"
Mp3_Play: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Play"
Mp3_Stop: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Stop"
Mp3_Destroy: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Destroy"
Mp3_GetStatus: make routine! [
    return: [integer!] 
    initialized [integer!] 
    status [struct! []]
] lib "Mp3_GetStatus"
status: make struct! [
    fPlay [integer!] 
    fPause [integer!] 
    fStop [integer!] 
    fEcho [integer!] 
    nSfxMode [integer!] 
    fExternalEQ [integer!] 
    fInternalEQ [integer!] 
    fVocalCut [integer!] 
    fChannelMix [integer!] 
    fFadeIn [integer!] 
    fFadeOut [integer!] 
    fInternalVolume [integer!] 
    fLoop [integer!] 
    fReverse [integer!] 
] none
Mp3_Time: make struct! [
    ms [integer!] 
    sec [integer!]
    bytes [integer!] 
    frames [integer!] 
    hms_hour [integer!] 
    hms_minute [integer!] 
    hms_second [integer!] 
    hms_millisecond [integer!] 
] none
TIME_FORMAT_SEC: 2
SONG_BEGIN: 1
SONG_CURRENT_FORWARD: 4
Mp3_Seek: make routine! [
    return: [integer!] 
    initialized [integer!]
    fFormat [integer!]
    pTime [struct! []]
    nMoveMethod [integer!]
] lib "Mp3_Seek"
Mp3_PlayLoop: make routine! [
    return: [integer!] 
    initialized [integer!]
    fFormatStartTime [integer!]
    pStartTime [struct! []]
    fFormatEndTime [integer!] 
    pEndTime [struct! []]
    nNumOfRepeat [integer!] 
] lib "Mp3_PlayLoop"
Mp3_GetSongLength: make routine! [
    return: [integer!]
    initialized [integer!]
    pLength [struct! []]
] lib "Mp3_GetSongLength"
Mp3_GetPosition: make routine! [
    return: [integer!] 
    initialized [integer!]
    pTime [struct! []]
] lib "Mp3_GetPosition"
Mp3_SetVolume: make routine! [
    return: [integer!] 
    initialized [integer!]
    nLeftVolume [integer!]
    nRightVolume [integer!]
] lib "Mp3_SetVolume"
Mp3_GetVolume: [
    initialized [integer!]
    pnLeftVolume [integer!]
    pnRightVolume [integer!]
    return: [integer!]
] lib "Mp3_GetVolume"
Mp3_VocalCut: make routine! [
    return: [integer!] 
    initialized [integer!]
    fEnable [integer!]
] lib "Mp3_VocalCut"
Mp3_ReverseMode: make routine! [
    return: [integer!] 
    initialized [integer!]
    fEnable [integer!]
] lib "Mp3_ReverseMode"
Mp3_Close: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Close"
waves: []
foreach file read %. [
    if (%.mp3 = suffix? file) [append waves file]
]
append waves "(CHANGE FOLDER...)"
initialized: Mp3_Initialize
view center-face layout [
    vh2 "Click a File to Play:"
    file-list: text-list data waves [
        if value = "(CHANGE FOLDER...)" [
            new-dir: request-dir
            if new-dir = none [break]
            change-dir new-dir
            waves: copy []
            foreach file read %. [
                if (%.mp3 = suffix? file) [append waves file]
            ]
            append waves "(CHANGE FOLDER...)"
            file-list/data: waves
            show file-list
            break
        ]
        Mp3_GetStatus initialized status
        if (status/fPlay = 0) [
            file: rejoin [to-local-file what-dir "\" value]
            Mp3_OpenFile initialized file 1000 0 0
            Mp3_Play initialized
        ]
    ]
    across
    tabs 40
    text "Seek:   " 
    tab slider 140x15 [
        plength: make struct! Mp3_Time compose [0 0 0 0 0 0 0 0]
        Mp3_GetSongLength initialized plength
        location: to-integer (value * plength/sec)
        ptime: make struct! Mp3_Time compose [0 (location) 0 0 0 0 0 0]
        Mp3_Seek initialized TIME_FORMAT_SEC ptime SONG_BEGIN
        Mp3_Play initialized
    ]
    return
    text "Volume: " 
    tab slider 140x15 [
        volume: to-integer value * 100
        Mp3_SetVolume initialized volume volume
    ]
    return
    btn "Reverse" [
        Mp3_GetStatus initialized status
        either (status/fReverse > 0) [
            Mp3_ReverseMode initialized 0
        ] [
            Mp3_ReverseMode initialized 1
        ]
    ]
    btn "Vocal-Cut" [
        Mp3_GetStatus initialized status
        either (status/fVocalCut > 0) [
            Mp3_VocalCut initialized 0
        ] [
            Mp3_VocalCut initialized 1
        ]
    ]
    return
    tabs 50
    text "Loop Start:" 
    tab start-slider: slider 120x15 []
    return
    text "Loop End:  " 
    tab end-slider: slider 120x15 []
    return
    btn "Play Loop" [
        plength: make struct! Mp3_Time compose [0 0 0 0 0 0 0 0]
        Mp3_GetSongLength initialized plength
        s-loc: to-integer (start-slider/data * plength/sec)
        pStartTime: make struct! Mp3_Time compose [0 (s-loc) 0 0 0 0 0 0]
        end-loc: to-integer (end-slider/data * plength/sec)
        pEndTime: make struct! Mp3_Time compose [0 (end-loc) 0 0 0 0 0 0]
        ; TIME_FORMAT_SEC: 2
        Mp3_PlayLoop initialized 2 pStartTime 2 pEndTime 1000  ; 1000x
    ]
    btn 58 "Stop" [
        Mp3_GetStatus initialized status
        if (status/fPlay > 0) [Mp3_Stop initialized]
    ]
]
Mp3_Destroy initialized
free lib

5. Third Party Libraries

This section contains examples which demonstrate how to use a variety of third party Rebol libraries. SQLite and MySQL databases, a little 3D module based on Draw graphics, dialects to create PDF and Flash (.swf) output, XML-RPC, additional GUI layout tools, and other functionality are demonstrated:

5.1 PDF

PDF Maker by Gabriele Santilli:

REBOL [title: "PDF example"]
do http://www.colellachiara.com/soft/Misc/pdf-maker.r
write/binary %example.pdf layout-pdf [[textbox ["Hello PDF world!"]]]
call %example.pdf

REBOL [title: "PDF example 2"]
do http://www.colellachiara.com/soft/Misc/pdf-maker.r
write/binary %example.pdf layout-pdf compose/deep [
    [
        page size 215.9 279.4  ; American Letter Size
        textbox ["Here is page 1.  It just contains this text."]
    ] 
    [
        textbox 55 55 90 100 [
            {Here's page 2.  This text box contains a starting
             XxY position and an XxY size.  Coordinates are in
             millimeters and extend from the BOTTOM LEFT of the
             page (this box extends from starting point 55x55
             and is 90 mm wide, 100 mm tall).
             All the following page sizes are the default ISO A4,
             or 211297 mm.  That is SLIGHTLY SMALLER than the
             standard American Letter page size.}
        ]
    ]
    [
        textbox 0 200 200 50 [
            center font Helvetica 10.5
            {This is page 3.  The text inside this box is centered
             and formatted using Helvetica font, with a character
             size of 10.5 mm.}
        ]
    ]
    [
        apply rotation 20 translation 35 150 [
            textbox 4 4 200 20 [
                {This is page 4.  The textbox is rotated 20 degrees
                 and translated (moved over) 35x150 mm.  Graphics
                 and images can also be rotated and translated.}
            ]
        ]
    ]
    [
        textbox 5 200 200 40 [
            {Here's page 5.  It contains this textbox and several
             images.  The first image is placed at starting point
             50x150 and is 10mm wide by 2.4mm tall.  The second
             image is 2x bigger and rotated 90 degrees.  The last
             image is placed at starting point 100x150 and is
             streched to 10x its size.  Notice that this ENTIRE
             layout block has been evaluated with compose/deep to
             evaluate the images in the following parentheses.}
        ]
        image 50 150 10 2.4 (system/view/vid/image-stock/logo)
        image 50 100 20 4.8 rotated 90 
            (system/view/vid/image-stock/logo)
        image 100 150 100 24 (system/view/vid/image-stock/logo)
    ]
    [
        textbox [
            {This page contains this textbox and several generated
             graphics:  a line, a colored and filled box with a
             colored edge, and a circle.}
        ]
        line width 3  20 20 100 50   ; starting and ending XxY positions
        solid box edge width 0.2 edge 44.235.77 150.0.136 100 67 26 16
        circle 75 50 40   ; starting point 75x50, radius 40mm
    ]
]
call %example.pdf
; see http://www.colellachiara.com/soft/Misc/pdf-maker-doc.pdf

5.2 Flash (.swf) Builder

By Oldes:

REBOL [title: "REBOL/Flash example"]
do http://box.lebeda.ws/~hmm/rswf/rswf_latest.r
make-swf/save/html http://tinyurl.com/yhex2cf 
browse %starfield1.html
; see http://box.lebeda.ws/~hmm/rswf/ 
; and http://re-bol.com/rebol.html#section-9.17

5.3 RebGUI

A GUI dialect by Ashley Truter, with features not in native VID:

REBOL [title: "RebGUI Example"]
do http://re-bol.com/rebgui.r
display/close "Tab Panel" [
    main-screen: tab-panel data [
        "Spreadsheet" [
            x: sheet data [
                A1 32 A2 12 A3 "=a1 + a2" A4 "=1.06 * to decimal! a3"
            ]
            a: area
            reverse
            button -1 " Show Data " [x/save-data set-text a x/data]
            button -1 " Quit! " [if true = question "Quit?" [quit]]
        ]
        "Pie Chart" [
            pie-chart data ["VID" yellow 19 "RebGUI" red 81]
                tip "Pie Chart!"
        ]
        "Menu" [
            menu #LHW data [
                "File" [
                     "Open" [x/text: read to-file request-file show x]
                     "Save" [write to-file request-file/save x/text]
                 ]
                 "About" [
                     "Info" [alert "RebGUI is great!"]
                 ]
            ] 
            return
            x: area #LHW "[CTRL-Z: Undo CTRL-Y: Redo CTRL-S: Spell Check]"
        ]
        "VID style"  [
            style -1 data [text bold "Back to Spreadsheet" [
                main-screen/select-tab 1
            ]]
        ]
        action [wait .2 face/color: 230.230.230]  "Text" [
            text "Tabs are a great way to maximize screen real estate."
        ]
        action [wait .2 set-focus z]  "Fields" [
            y: field
            z: field "Edit me"
        ]
    ]
] [question "Really Close?"]
do-events

A little app example:

REBOL [title: "RebGUI Table Grid Example"]
do load-thru http://re-bol.com/rebgui.r
alert {Default username/password is "user1/pass1"}
unless exists? %snappmx.txt [
    save %snappmx.txt [
        "user1" "pass1" "Bill Jones" "bill@site.com" "Bill LLC" 
        "user2" "pass2" "John Smith" "john@mail.com" "John LLC"
    ]
]
database: load %snappmx.txt
login: request-password
found: false
foreach [userid password name email company] database [
    either (login/1 = userid) and (login/2 = password) [found: true] []
]
if found = false [alert "Incorrect Login." quit]
add-record: does [
    display/dialog "User Info" [
        text 20 "User:" f1: field return
        text 20 "Pass:" f2: field return
        text 20 "Name:" f3: field return
        text 20 "Email:" f4: field return
        text 20 "Company:" f5: field reverse
        button -1 #XY " Clear " [clear-fields]
        button -1 #XY " Add " [add-fields]
    ]
]
edit-record: does [
    display/dialog "User Info" [
        text 20 "User:" f1: field (form pick t/selected 1) return
        text 20 "Pass:" f2: field (form pick t/selected 2) return
        text 20 "Name:" f3: field (form pick t/selected 3) return
        text 20 "Email:" f4: field (form pick t/selected 4) return
        text 20 "Company:" f5: field (form pick t/selected 5) reverse
        button -1 #XY " Delete " [
            t/remove-row t/picked
            save %snappmx.txt t/data
            hide-popup
        ]
        button -1 #XY " Save " [
            t/remove-row t/picked
            add-fields
            save %snappmx.txt t/data
            hide-popup
        ]
    ]
]
add-fields: does [
    t/add-row reduce [
        copy f1/text copy f2/text copy f3/text copy f4/text copy f5/text
    ]
    save %snappmx.txt copy t/data
]
clear-fields: does [
    foreach item [f1 f2 f3 f4 f5] [do rejoin [{set-text } item {""}]]
]
table-size: system/view/screen-face/size/1 / ctx-rebgui/sizes/cell
display/maximize "Users" [
    t: table table-size #LWH options [
        "" left .0  "" left .0   ; don't show the first 2 fields
        "Name" center .33  "Email" center .34  "Company" center .34
    ] data database [edit-record]
    reverse
    button -1 #XY " Add " [add-record]
]
do-events

5.4 Cyphre Menu and Tab Panel

REBOL [title: "Cyphre Menu and Tab Panel Example"]
do load-thru http://re-bol.com/cyphre_menu_and_tab_panel.r
insert-event-func [ 
    either event/type = 'resize [
        mn/size/1: system/view/screen-face/pane/1/size/1 
        my-tabs/size: system/view/screen-face/pane/1/size - 15x30
        show [mn my-tabs]  none
    ] [event]
]
view/options center-face layout  [
    across space 0x0 origin 0x0
    mn: menu with [ 
        size: 470x20 
        data: compose/deep [
            " File " [
                "Open" # "Ctrl+O" [request-file]
                "Save" # "Ctrl+S" [request-file/save]
                bar
                "Exit" [quit]
            ]
            " Options " [
                "Preferences" sub [
                    "Colors" [alert form request-color]
                    "Settings" [request-text/title "Enter new setting:"]
                ]
                "About" [alert "Menu Widget by Cyphre"]
            ]
        ]
    ]
    below
    at 10x25 my-tabs: tab-panel data [
        "Fields"   [
            h1 "Tab Panel by Cyphre" field field area area btn "Ok"
         ]
        "Data List"  [
            t1: text-list 400x430 data system/locale/months [alert value]
        ]
    ]
] [resize]

5.5 Henrik Listview

REBOL [title: "Listview Example"]
evt-close: func [face event] [
    either event/type = 'close [
        inform layout [
            across
            Button "Save Changes" [
                backup-file: to-file rejoin ["backup_" now/date]
                write backup-file read %database.db
                save %database.db theview/data quit
            ]
            Button "Lose Changes" [quit]
            Button "CANCEL" [hide-popup]
        ] none ] [ 
        event
    ]
]
insert-event-func :evt-close
if not exists? %list-view.r [write %list-view.r read
    http://www.hmkdesign.dk/rebol/list-view/list-view.r
]
do %list-view.r
if not exists? %database.db [write %database.db {[][]}]
database: load %database.db
view center-face gui: layout [
    h3 {To enter data, double-click any row, and type directly 
        into the listview.  Click column headers to sort:}
    theview: list-view 775x200 with [
        data-columns: [
            Student Teacher Day Time Phone Parent Age Payments
            Reschedule Notes
        ]
        data: copy database
        tri-state-sort: false
        editable?: true
    ]
    across
    button "add row" [theview/insert-row]
    button "remove row" [
        if (to-string request-list "Are you sure?" 
                [yes no]) = "yes" [
            theview/remove-row
        ]
    ]
    button "filter data" [
        filter-text: request-text/title trim {
            Filter Text (leave blank to refresh all data):}
        if filter-text <> none [
            theview/filter-string: filter-text
            theview/update
        ]
    ]
    button "save db" [
        backup-file: to-file rejoin ["backup_" now/date]
        write backup-file read %database.db
        save %database.db theview/data
    ]
]

5.6 Ensel Menu System

REBOL [title: "Another Menu Module Example"]
if not exists? %menu-system.r [write %menu-system.r (
        read http://www.rebol.org/library/scripts/menu-system.r)]
do %menu-system.r
menu-data: [
    file: item "File" menu [item "Open" item "Save" item "Quit"]
    edit: item "Edit" menu [ 
        item "Item 1"
        item "Item 2" <ctrl-q>
        ---
        item "Submenu..." menu [
            item "Submenu Item 1" 
            item "Submenu Item 2"
            item "Submenu Item 3" menu [
                item "Sub-Submenu Item 1"
                item "Sub-Submenu Item 2"
            ]
        ]
        ---
        item "Item 3"       
    ]
    icons: item "Icons" menu [
        item "Icon Item 1" icons [help.gif stop.gif]
        item "Icon Item 2" icons [info.gif exclamation.gif]
    ]
]
basic-style: [item style action [
    switch item/body/text [
        case "Open" [
            the-file: request-file
            alert rejoin ["You opened: " the-file]
        ] 
        case "Save" [
            the-file: request-file/save
            alert rejoin ["You saved to: " the-file]
        ]
        case "Quit" [
            if (request/confirm "Really Quit?") = true [quit]
        ]   
        case "Item 1" [alert "Item 1 selected"]
        case "Item 2" [alert "Item 2 selected"]
        case "Item 3" [alert "Item 3 selected"]
        case "Submenu Item 1" [alert "Submenu Item 1 selected"]
        case "Submenu Item 2" [alert "Submenu Item 2 selected"]
        case "Submenu Item 3" [alert "Submenu Item 3 selected"]
        case "Sub-Submenu Item 1" [alert "Sub-Submenu Item 1 selected"]
        case "Sub-Submenu Item 2" [alert "Sub-Submenu Item 2 selected"]
        case "Icon Item 1" [alert "Icon Item 1 selected"]
        case "Icon Item 2" [alert "Icon Item 2 selected"]
    ]
]]
evt-close: func [face event] [either event/type = 'close [quit] [event]]
insert-event-func :evt-close
view center-face layout [
    size 400x500
    at 2x2 menu-bar menu menu-data menu-style basic-style
]

5.7 r3D

A 3D dialect based on native Rebol draw functions, by Andrew Hoadley:

REBOL [title: "r3D Example"]
do http://re-bol.com/r3d.r
Transx:   Transy:   Transz:   300.0
Lookatx:  Lookaty:  Lookatz:  100.0 
do update: does [ 
    world: copy [] 
    append world reduce [
        reduce [cube-model (r3d-scale 100.0 150.0 125.0) red]
    ]
    camera: r3d-position-object   
        reduce [Transx Transy Transz]
        reduce [Lookatx Lookaty Lookatz]
        [0.0 0.0 1.0] 
    RenderTriangles: render world camera r3d-perspective 250.0 400x360
    probe RenderTriangles    ; This line can be removed
] 
view layout [
    scrn: box 400x360 black effect [draw RenderTriangles]  ; basic draw
    across return
    slider 60x16 [Transx: (value * 600 - 300.0) update show scrn]
    slider 60x16 [Transy: (value * 600 - 300.0) update show scrn]
    slider 60x16 [Transz: (value * 600) update show scrn]
    slider 60x16 [Lookatx: (value * 400 - 200.0) update show scrn]
    slider 60x16 [Lookaty: (value * 400 - 200.0) update show scrn]
    slider 60x16 [Lookatz: (value * 200 ) update show scrn]
]

5.8 MySQL

By Nenad Radosevic ("Doc Kimbel"):

REBOL [title: "MYSQL Example"]
; First, start MySQL and create a database named "Contacts"
unless exists? %mysql-protocol.r [
    write %mysql-protocol.r read http://re-bol.com/mysql-protocol.r
]
do %mysql-protocol.r
db: open mysql://root:root@localhost/Contacts
insert db {create table Contacts (
    name            varchar(100),
    address         text,
    phone           varchar(12),
    birthday        date 
)} 
insert db {INSERT into Contacts VALUES 
    ('John Doe', '1 Street Lane', '555-9876', '1967-10-10'),
    ('John Smith', '123 Toleen Lane', '555-1234', '1972-02-01'),
    ('Paul Thompson', '234 Georgetown Pl.', '555-2345', '1972-02-01'),
    ('Jim Persee', '345 Portman Pike', '555-3456', '1929-07-02'),
    ('George Jones', '456 Topforge Court', '', '1989-12-23'),
    ('Tim Paulson', '', '555-5678', '2001-05-16')
}
insert db "DELETE from Contacts WHERE birthday = '1967-10-10'"
insert db "SELECT * from Contacts"
results: copy db
probe results
close db
halt
; see http://softinnov.org/rebol/mysql-usage.html

REBOL [title: "MySQL GUI Example"]
do %mysql-protocol.r
results: read/custom mysql://root:root@localhost/Contacts [
    "SELECT * from Contacts"
]
view layout [
    text-list 100x400 data results [
        string: rejoin [
            "NAME:      " value/1 newline
            "ADDRESS:   " value/2 newline
            "PHONE:     " value/3 newline
            "BIRTHDAY:  " value/4
        ]
        view/new layout [
            area string
        ] 
    ] 
]

5.9 SQLite

By Ashley Truter:

REBOL [title: "SQLITE Example"]
unless exists? %sqlite3.dll [
    write/binary %sqlite3.dll read/binary http://re-bol.com/sqlite3.dll
]
unless exists? %sqlite.r [
    write %sqlite.r read http://re-bol.com/sqlite.r
]
do %sqlite.r
db: connect/create %contacts.db
SQL "create table contacts (name, address, phone, birthday)"
SQL {insert into contacts values 
    ('"John Doe"', '"1 Street Lane"', '"555-9876"', '"1967-10-10"')
}
data: [
    "John Smith" "123 Toleen Lane" "555-1234" "1972-02-01"
    "Paul Thompson" "234 Georgetown Pl." "555-2345" "1972-02-01"
    "Jim Persee" "345 Portman Pike" "555-3456" "1929-07-02"
    "George Jones" "456 Topforge Court" "" "1989-12-23"
    "Tim Paulson" "" "555-5678" "2001-05-16"
]
SQL "begin"
foreach [name address phone bd] data [
    SQL reduce [
        "insert into contacts values (?, ?, ?, ?)" name address phone bd
    ]
]
SQL "commit"
SQL ["DELETE from Contacts WHERE birthday = ?" "1967-10-10"]
results: SQL "select * from contacts"
probe results
disconnect db
halt
; see http://www.dobeash.com/sqlite.html

REBOL [title: "SQLITE GUI Example"]
do %sqlite.r
connect %contacts.db
results: SQL "select * from contacts"
view layout [
    text-list 100x400 data results [
        string: rejoin [
            "NAME:      " value/1 newline
            "ADDRESS:   " value/2 newline
            "PHONE:     " value/3 newline
            "BIRTHDAY:  " value/4
        ]
        view/new layout [
            area string
        ] 
    ] 
]
disconnect

5.10 Doc's Captcha

REBOL [title: "Captcha Example"]
write/binary %Caliban.caf read/binary http://re-bol.com/Caliban.caf
do http://re-bol.com/captcha.r
captcha/set-fonts-path %./
captcha/level: 4
write/binary %captcha.png captcha/generate
write %captcha.txt captcha/text
view center-face layout [
    image (load %captcha.png)
    text "Enter the captcha text:"
    f1: field [
        either f1/text = (read %captcha.txt) [
            alert "Correct"
        ] [
            alert "Incorrect"
        ]
    ] 
]

5.11 Irwin/Ensel Screen Capture

REBOL [title: "Windows Screen Capture Example"]
do http://www.rebol.org/download-a-script.r?script-name=capture-screen.r
the-image: ftp://user:pass@site.com/path/current.png
view center-face gui: layout [
    button 150 "Upload Screen Shot" [
        unview gui
        wait .2
        save/png the-image capture-screen
        view center-face gui
    ]
]

5.12 XML and XML-RPC

See http://earl.strain.at/space/rebXR+Users+Guide

REBOL [title: "XML-RPC Example"]
xmlrpc-exec http://betty.userland.com/RPC2 [examples.getStateName 41]
defh: func [orig-call] [do orig-call]
xmlrpc-serve/default [] 'defh

5.13 Q-Plot Graph and Chart Library

By Matt Licholai:

REBOL [title: "Minimal Bar Graph Example"]
if not exists? %q-plot.r [write %q-plot.r read http://re-bol.com/q-plot.r]
do %q-plot.r
view quick-plot [
    600x400
    bars [5 3 8 2 10 3 4 9 5 7]
]

REBOL [title: "Exploded Pie Chart"]
if not exists? %q-plot.r [write %q-plot.r read http://re-bol.com/q-plot.r]
do %q-plot.r
view center-face quick-plot [
    400x400
    pie [10 3 6 1 8] labels [A B C D E] explode [3 5]
    title "Exploded Sections C and E" style vh2
]

REBOL [title: "Simple Line Graph Example"]
if not exists? %q-plot.r [write %q-plot.r read http://re-bol.com/q-plot.r]
do %q-plot.r
view quick-plot [
    400x400
    line [1 2 4 8 16 32 64 128 256]
]

5.14 Rebzip

Rebzip by Vincent Ecuyer:

REBOL [title: "Rebzip Example"]
do to-string to-binary decompress 64#{
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
j9hfoGv6L0cgfyluTAAA
}
make-dir %./tempfiles/
repeat i 10 [write join %./tempfiles/ i random "asdfghjklqwertyuiop"]
zipfile: request-file/file/save/only %zippedfiles.zip
zip/deep zipfile %tempfiles/

There are numerous other useful libraries available at rebol.org, and at various Rebol community web sites (many by the authors above).

6. Parse

Rebol's 'parse function has two modes of operation. First, it can be used to split strings:

my-text: {"apple","orange","pear"}
parsed-block: parse my-text none

some-text: {    First Name
           Last Name
           Street Address
           City, State, Zip}
parsed-block: parse/all some-text "^/"
foreach item parsed-block [trim item]
probe parsed-block

Beyond that, 'parse is one of the most unique and powerful aspects of Rebol. It is largely responsible for Rebol's ability to create language dialects (DSLs). Parse can accept either a block, or a string of data, and a set of rules which enable it to perform the types of pattern matching typically handled by Regular Expressions (regex).

This example takes a string of text, searches thru "<%" and to "%>" strings - any instance - and replaces everything between with the string " text2 ":

code: "text1 <% replace this %> <% replace this %> text3"
parse/all code [
    any [thru "<%" copy new to "%>" (replace code new " text2 ")] to end
]
print code

This example matches opening and closing HTML title tags, copies the data in between, to the label 'my-ip, then searches the 'my-ip result for the string "Your IP Address is: " and copies everything to the end, to a variable labeled 'stripped-ip:

parse read http://guitarz.org/ip.cgi [
    thru <title> copy my-ip to </title>
]
parse my-ip [
    thru "Your IP Address is: " copy stripped-ip to end
]
alert to-string rejoin [
    "External: " trim/all stripped-ip "  "
    "Internal: " read join dns:// read dns://
]

This example extracts all the image links read from an HTML document, copies the link URLs to a block labeled 'x, downloads the images to a new folder, and then presents a GUI slideshow of each image. Notice that one line of readable 'parse code extracts all the image links:

html: read http://musiclessonz.com/ScreenShots.html
x: copy []
parse html [any [thru {src="} copy link to {"} (append x link)] to end]
make-dir %./downloaded-images
change-dir %./downloaded-images
foreach i x [attempt [
    print rejoin ["downloading:  " i] 
    write/binary (to-file last split-path to-url i) (read/binary to-url i)
]]
foreach i read %. [view center-face layout [image (load i)]]

This example searches for all the http:// URL links in a string of text, and wraps them in HTML < a href > tags:

bb:  "some text http://guitarz.org http://yahoo.com"
bb_temp: copy bb
append bb_temp " "
append bb " "
parse bb [any [thru "http://" copy link to " " (
    replace bb_temp (rejoin [{http://} link]) (rejoin [
    {<a href="} {http://} link {" target=_blank>http://} 
    link {</a>}]))] to end
]
bb: copy bb_temp
print bb

This example allows you to interactively make changes to some GUI layout code:

code: {
    view layout [
        btn "some text"
        btn "some more text"
    ] 
}
strings: copy []
parse code [
    any [thru {"} copy a-string to {"} (append strings a-string)] to end
]
foreach str strings [
    if true = request rejoin [{Change "} str {"?}] [
        replace/all code str request-text/title rejoin [
            {Change "} str {" to:}
        ]
    ]
]
editor code

This removes all comments from every line of code in a Rebol script:

code: read to-file request-file
parse/all code [any [
    to #";" begin: thru newline ending: (
        remove/part begin ((index? ending) - (index? begin))) :begin
    ]
]
editor code  ; all comments removed

This example creates a cleaned up Rebol data block from a CSV document read from a file:

filename: %filename.csv
data: copy []
lines: read/lines filename
foreach line lines [
    append/only data parse/all line ","
]
info: copy ""
foreach line data [
    either find "Header" line/1 [
        info: line/1
    ][
        append line info
    ]
]
remove-each line data [find "Header" line/1/1]
remove-each line data [
    (line/3 = "TITLE") or (line/3 = "DESCRIPTION")
]

Parse is an extremely powerful replacement for regex. It's readable and totally unique to Rebol. If you want to do text processing, validations, or dialect creation in Rebol, learning to construct parse rules is key.

7. Binding Words Labels to Contexts

In REBOL, words maintain a reference to the context in which they are created:

REBOL []
y: copy []
f1: func [/local x] [x: 1 append y 'x]
f2: func [/local x] [x: 2 append y 'x]
f1 
f2
probe y                        ; [x x]
probe reduce y                 ; [1 2]  !!!

The 'y block above contains two words labeled 'x, both contained in the same block, but each 'x word refers to different values. This is true because each of the 'x variable labels was assigned a value within a different context (in this case, local scope within a function).

This special capability of Rebol can cause a problem when using the same variables defined in two different contexts:

x: [1 2 3]
f: [print y]
foreach y x [do f]

** Script Error: y has no value
** Near: print y

You can use the 'bind function to refer to a specific instance of a word, by associating it with another word from the desired context:

x: [1 2 3]
f: [print y]
foreach y x [do bind f 'y]

You'll see 'bind used when applying 'parse rules, and in certain metaprogramming situations:

gui-size: system/view/screen-face/size - 0x50
gui: {size gui-size}
gui: to-block gui
view layout gui

** Script Error: gui-size word has no context
** Where: do-facets
** Near: gui-size

Binding the word 'gui to the global 'system context fixes the issue above:

gui-size: system/view/screen-face/size - 0x50
gui: {size gui-size}
gui: to-block gui
bind gui 'system
view layout gui

8. Multitasking (Rebol Doesn't Have Threads)

This section demonstrates some basics of multitasking in REBOL. This example demonstrates how to obtain keyboard input without blocking looping program flow:"

p: open/binary/no-wait console://
q: open/binary/no-wait [scheme: 'console]
count: 0
forever [
    count: count + 1
    if not none? wait/all [q :00:00.01] [
        wait q
        qq: to string! copy q
        probe qq
        print ["^/loop count incremented to" count "while waiting^/"]
    ]
]

In "Catch" game example earlier, you saw one method of multitasking a GUI. Use 'view/new to build the GUI, but don't start the event loop (normally using 'do-events). Instead, start a 'forever loop, perform any calculations, evaluations, and manually update the layout display with 'show. Typically, you'll want to include a small delay in each repeate, using the 'wait function:

REBOL [title: "Catch Game"]
random/seed now   
start: now/time
speed: 2
view/new center-face g: layout [
    size 600x440 
    at 280x20   a: image logo.gif
    at 280x420  b: btn 50x20 blue
    key keycode [left]  [b/offset: b/offset - 10x0]
    key keycode [right] [b/offset: b/offset + 10x0]
]
forever [
    a/offset: a/offset + (as-pair 0 round speed)
    if overlap? a b [
        a/offset: as-pair (random 500) 20
        speed: speed + .1
    ]
    if a/offset/y > 440 [break]
    wait .01
    show g
]

Another way to multitask in a GUI is:

  1. Assign a rate of 0 to a GUI widget.
  2. Assign a "feel" detection to that widget, and put the actions you want performed simultaneously inside the block that gets evaluated every time a 'time event occurs.
  3. Stop and start the evaluation of concurrently active portions of code by assigning a rate of "none" or 0, respectively, to the associated GUI widget(s).

Here's a GUI demo of the above technique:

REBOL [title: "GUI Multitasking"]
webcam-url: http://209.165.153.2/axis-cgi/jpg/image.cgi
view layout [
    btn "Start Video" [
        webcam/rate: 0 
        webcam/image: load webcam-url 
        show webcam
    ]
    btn "Stop Video" [webcam/rate: none show webcam]
    return 
    webcam: image load webcam-url 320x240 rate 0 feel [
        engage: func [f a e][
            if a = 'time [
                f/image: load webcam-url show f
            ] 
        ] 
    ]
    clock: field to-string now/time/precise rate 0 feel [
        engage: func [f a e][
            if a = 'time [
                f/text: to-string now/time/precise show f
            ] 
        ] 
    ]
    h3 "Notice the delay in the timer as each image loads"
]

This examples achieves true multitasking by simply writing the code for one process into a separate file and running it in a separate REBOL interpreter process using the "launch" function:

REBOL [title: "Launching Separate Processes"]
write %async.r {
    REBOL []
    view layout [
        origin 10x10
        clock: field to-string now/time/precise rate 0 feel [
            engage: func [face action event][
                if action = 'time [
                    face/text: to-string now/time/precise show face
                ] 
            ] 
        ]
    ]
}
launch %async.r
webcam-url: http://209.165.153.2/axis-cgi/jpg/image.cgi
view center-face layout [
    btn "Start Video" [
        webcam/rate: 0 
        webcam/image: load webcam-url 
        show webcam
    ]
    btn "Stop Video" [webcam/rate: none show webcam]
    return 
    webcam: image load webcam-url 320x240 rate 0 feel [
        engage: func [face action event][
            if action = 'time [
                face/image: load webcam-url show face
            ]
        ]
    ]
]

9. More about Built-In Help

The "help" function displays required syntax for any REBOL function:

help print

"?" is a synonym for "help":

? print

The "what" function lists all built-in words:

what

Together, those two words provide a built-in reference guide for the entire core REBOL language. Here's a script that saves all the above documentation to a file. Give it a few seconds to run:

echo %words.txt what echo off   ; "echo" saves console activity to a file
echo %help.txt
foreach line read/lines %words.txt [
    word: first to-block line
    print "___________________________________________________________^/"
    print rejoin ["word:  " uppercase to-string word]  print "" 
    do compose [help (to-word word)]
]
echo off
editor at read %help.txt 4

You can use help to search for defined words and values, when you can't remember the exact spelling of the word. Just type a portion of the word (hitting the tab key will also show a list of words for automatic word completion):

? to-         ; shows a list of all built-in type conversions
? reques      ; shows a list of built-in requester functions
? "load"      ; shows all words containing the characters "load"
? "?"         ; shows all words containing the character "?"

Here are some more examples of ways to search for useful info using help:

? datatype!   ; shows a list of built-in data types
? function!   ; shows a list of built-in functions
? native!     ; shows a list of native (compiled C code) functions
? char!       ; shows a list of built-in control characters
? tuple!      ; shows a list of built-in colors (RGB tuples)
? .gif        ; shows a list of built-in .gif images

You can view the source code for built-in "mezzanine" (non-native) functions with the "source" function. There is a huge volume of REBOL code accessible right in the interpreter, and all of the mezzanine functions were created by the language's designer, Carl Sassenrath. Studying mezzanine source is a great way to learn more about advanced REBOL code patterns:

source help
source request-text
source view
source layout
source ctx-viewtop  ; try this:  view layout [image load ctx-viewtop/13]

The "word browser" script is a useful tool for finding, cross referencing, and learning about all the critical functions in REBOL:

write %wordbrowser.r read http://re-bol.com/wordbrowser.r
do %wordbrowser.r

9 The REBOL System Object, and Help with GUI Widgets

"Help system" displays the contents of the REBOL system object, which contains many important settings and values. You can explore each level of the system object using path notation, like this:

? system/console/history        ; the current console session history
? system/options
? system/locale/months
? system/network/host-address

You can find info about all of REBOL's GUI components in "system/view/VID":

? system/view/VID

The system/view/VID block is so important, REBOL has a built-in short cut to refer to it:

? svv

You'll find a list of REBOL's GUI widgets in "svv/vid-styles". Use REBOL's "editor" function to view large system sections like this:

editor svv/vid-styles

Here's a script that neatly displays all the words in the above "svv/vid-styles" block:

foreach i svv/vid-styles [if (type? i) = word! [print i]]

Here's a more concise way to display the above widgets, using the "extract" function:

probe extract svv/vid-styles 2

This script lets you browse the object structure of each widget:

view layout [
    text-list data (extract svv/vid-styles 2) [
        a/text: select svv/vid-styles value
        show a focus a
    ]
    a: area 500x250 
]

REBOL's GUI layout words are available in "svv/vid-words":

? svv/vid-words

The following script displays all the images in the svv/image-stock block:

b: copy [] 
foreach i svv/image-stock [if (type? i) = image! [append b i]]
v: copy [] foreach i b [append v reduce ['image i]]
view layout v

The changeable attributes ("facets") available to all GUI widgets are listed in "svv/facet-words":

editor svv/facet-words

Here's a script that neatly displays all the above facet words:

b: copy [] 
foreach i svv/facet-words [if (not function? :i) [append b to-string i]]
view layout [text-list data b]

Some GUI widgets have additional facet words available. The following script displays all such functions, and their extra attributes:

foreach i (extract svv/vid-styles 2) [
    x: select svv/vid-styles i
    ; additional facets are held in a "words" block:
    if x/words [
        prin join i ": "
        foreach q x/words [
            if not (function? :q) [prin join q " "]
        ]
        print ""
    ]
]

To examine the function(s) that handle any of the additional facets for the widgets above, type the path to the widget's "words" block, i.e.:

svv/vid-styles/TEXT-LIST/words

For more information on system/view/VID, see http://www.mail-archive.com/rebol-bounce@rebol.com/msg01898.html and http://www.rebol.org/ml-display-message.r?m=rmlHJNC.

It's important to note that you can SET any system value. Just use a colon, like when assigning variable values:

system/user/email: user@website.com

Familiarity with the system object yields many useful tools.

10. Learning More - Online Resources

Rebol is a powerful general purpose development tool. You can use it to create complex software of all types for desktop, mobile, server, and web environments, with greater simplicity, and dramatically improved productivity, compared to other tools. Because Rebol code is typically orders of magnitude shorter, more concise, and more readable than code written in popular tools such as Java, C, Visual Basic, and even scripting tools such as Python, Ruby, and Lua, developing with it means being able to create much more software over your lifetime, and it makes maintaining, upgrading and improving that software much more manageable than it is with other development tools. Rebol's portability, small size, and unique features enable capabilities which are simply not possible using other development platforms.

To learn more about Rebol, see:

http://business-programming.com: a full 850 book that documents everything you need to know to create many types of applications with Rebol (R2). More than 100 complete working programs are included in this text, every topic is fully explained, and links to many other supporting online docs and resources are provided. The examples provide useful solutions and code patterns which demonstrate how to solve many common programming problems with Rebol. An older version of this text is found at http://re-bol.com

http://re-bol.com/examples.txt: example code from the book above, without any extra prose. Much of that code is included in the present text, but there are quite a few additional full applications in the examples.txt link.

10.1 R3 Links

http://learnrebol.com: learn about the newest version of Rebol (Saphir R3 and R3-GUI), which is open source and available for Android mobile platforms, as well as desktop and server environments.

The links below are critically important R3 and R3-GUI reference docs:

http://www.rebol.com/rebol3/index.html http://www.rebol.com/r3/docs/gui/gui.html http://development.saphirion.com/rebol/r3gui/ (backed up at http://re-bol.com/saphirion-r3guidocs.zip) https://github.com/saphirion/documentation

It's important to understand that R3 is an open source project, most actively developed now by the group at saphirion.com and Atronix. R3 docs found on rebol.com are generally helpful and correct, but are not necessarily up to date with improvements made by Saphirion, especially for non-core features such as GUI, protocols, ports to new OS platforms, etc.

10.2 Rebolforum.com

Beyond the list of supporting documents and web sites links in the business-programming.com tutorial, a collection of currently important links is maintained at http://rebolforum.com/index.cgi?f=printtopic&permalink=Nick19-Jan-2014/18:29:47-8:00&archiveflag=new.

10.3 Rebol.org

Rebol.org maintains a searchable history of several hundred thousand posts from both the mailing list and AltME, along with a rich script archive. You can typically find answers to just about any question, already in the archives.

10.4 Forums and The AltME Community

To ask a question directly of other REBOL developers, you can post forum messages:

http://rebolforum.com

http://chat.stackoverflow.com/rooms/291/rebol-and-red

But the Rebol community is most active using this program:

AltME

Download it and set up a user account for the "Rebol4" world. Just follow the instructions at http://www.rebol.org/aga-join.r. Joining AltME and getting to know the community is the best way to ask questions and to find Rebol related support.