• Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search

World: r4wp

[Rebol School] REBOL School

Giuseppe, you can experiment by creating your gui code as a block 
and then "do" it. Then view it.
a: [layout [button "hi" [print "hello"]]]
b: do a
view b
BrianH: Thanks for the info. It corrupts when I try it on objects. 
And wierd effects on blocks.. I've added "unset 'path" to my rebol.r 
file, so I won't be confused anymore.
Let us know whether you find that it's safe to unset 'path and reuse 
it for other stuff. There's no reason to think that the action! mechanism 
would call the function through its name (that's more of an R3 intrinsics 
thing), but any unpredictable behavior you find would be good to 
Gregg, a little difficult for me but I'll try to lear.
Keep asking questions Giuseppe. Dynamic GUIs is a big subject, so 
if you ask more specific questions, that makes it easier to craft 
small answers and examples.
Perhaps it helps to learn about the mechanisms: There are several 
ways to generate a dynamic UI:

The LAYOUT function works by creating an object tree, a tree of faces 
that are simply ordinary objects. When passing this to the VIEW function, 
a layout is displayed. The layout function is part of VID and is 
as such a high level function. VIEW is a low level function to interpret 
the face tree.

The face tree consists of objects that contain other objects through 
the FACE/PANE word. If the FACE/PANE contains an object, that object 
is a single face, that is displayed inside the parent face. If the 
PANE contains a block, that block may contain multiple objects that 
are simply multiple faces. As such, a typical window is a face with 
a FACE/PANE that is a block that contains other objects.

Graphically, the face is represented by a region on the screen that 
has the size and offset, possibly an effect, such as coloring, blur 
or mirroring or a text attached to it, and image or other faces that 
are only visible inside that region.

A window is also a face.

To navigate to the parent face from a face, use the FACE&/PARENT-FACE 
word. Note that FACE/PARENT-FACE is many times not set by VID, which 
is sometimes problematic.

You can manipulate the face tree by adding removing objects dynamically 
and calling the SHOW function. You can also change values in existing 
face objects in the tree, such as for resizing or moving the faces 
and then calling SHOW again. You can also build a face tree entirely 
by hand, and this is usually the starting point for different layout 
engines, such as RebGUI, that simply build face trees in their own 

The prototype face is FACE, which is a minimum requirement face for 
the View engine. The prototype face for a VID face, which contains 
a few more words, is SYSTEM/VIEW/VID/VID-FACE, which is the minimum 
requirement face for VID.

One condition for the face tree is to not use the same object in 
multiple locations. The VIEW or SHOW function will return an error 
if that is the case.

A simpler way is also to generate a new face tree every time you 
want to change the layout. Although this is slightly more computationally 
heavy, it allows you to manipulate the block that was passed to the 
LAYOUT function instead of manipulating the face tree directly. This 
technique is best used, when the face tree changes dramatically by 
each manipulation.

Another important concept is the DRAW engine which is a separate 
entity in REBOL2. It can be called to draw on an image bitmap, using 
the DRAW function or as in effect for a face object, by adding a 
parameter in the VID dialect block or by changing the FACE/EFFECT 
word. DRAW is used by calling a dialect. if you just want to use 
fields, buttons and simple user interface designs, you may not need 
to use DRAW.
Very nice Henrik.
I should add that it is possible for FACE/PANE also to be a function. 
This makes the face into an iterated face, where using a loop, you 
can "stamp" the face in various positions during a single SHOW, making 
it possible to use one face  with different texts, sizes and offsets 
to produce a grid or a table.
Henrik: With your permission I write your text to my blog. Also I'll 
study it later
A question: I create a layout wiich has two button. I whish to add 
more buttons dynamically updating the layout. How could I do this 
GiuseppeC: Go ahead.
You can do this by adding the buttons to a panel and update the contents 
of this panel.

view/new layout [p: panel 500x500 []] ; start with an empty panel. 
note that VID does not support scrolling panels out-of-the-box. For 
this you need the VID Extension Kit.

append p/pane make get-style 'button [] ; you will need to adjust 
for offset here, otherwise the new phase will be placed on top of 
the old one.

do in last p/pane 'init ; you will need to initialize the face, which 
is the FACE/INIT block that resides in the face style definition. 
once the init block has been run, the face will set itself up and 
then you can show it

show p

This is just a simple version of what can be done.

To clear it again:

clear p
show p

If you want to do more than this, I think you need to use the VID 
Extension Kit, because you will be spending a lot of time managing 
scrollbars and panels. It has styles that are meant for this purpose.
Thanks Henrik, I'll do one things at time. This is starting to be 
You might now begin to experience the VID learning curve turning 
into a wall. Suddenly you need to know a lot about its internals 
to do fairly trivial things.
I wrote another simple example as a one-liner, not useful in a real-world 
app. but gives an idea:

view f: layout/size [btn "add" [append f/pane layout/tight/offset 
[backcolor random white btn random "abcdef"] 50x50 + random 300x300 
show f]] 400x400
It actually adds new faces to the main face's pane, not the new styles. 
So, not a useful example. 
;no need to backcolor.. shorter:

view f: layout/size [btn "add" [append f/pane layout/tight/offset 
[btn random "abcdef"] 50x50 + random 300x300 show f]] 400x400
how to use trim/auto? it says "auto indents relative to first line" 

>> print trim/auto ajoin [tab tab "test" newline "line 2"]
test     ;no indentation?
line 2  ;no indentation?
It removes as much whitespace from consecutive lines as it removes 
from the first:

>> print trim/auto ajoin [tab tab "test" newline tab tab tab "line 
    line 2
To be precise: It removes up to as much whitespace.
I see, thank you. So it actually does not auto indent relative to 
the first line:

>> print trim/auto ajoin [tab "  test" newline tab tab "line 2" newline 
tab "line 3"]
  line 2
line 3
If it's inserting whitespace according to the first line I'm afraid 
there isn't such functionality available out-of-the-box. And if there 
was, TRIM wouldn't probably be a good name for it, then ;-)
Anyways, I'll have a go with:
indent: funct [string [string!]] [
    whitespace: charset "^- "
    indention: line-start: content: none
    parse/all string [
        copy indention any whitespace 

        any [thru "^/" line-start: any whitespace content: (insert remove/part 
        line-start content indention) :content]
>> print indent ajoin [tab "  test" newline tab tab "line 2" newline 
tab "line 3"]
      line 2
      line 3
Or what else is it what you're wanting to do?
hah! I wrote something similar:

indent: func [s /local x] [parse/all s [x: (insert x "^-") any [thru 
newline x: (insert x "^-")]] s]
It's simple but it solves my issue.
Hello, all. I am new to REBOL4 and while having followed Lava to 
REBOL and looked through tutorials every year once a year for more 
than 10 years I have only recently began making an actual REBOL script.
I hope it is not rude to leave a question here as opposed to be here 
for the disucssion live, ala IRC. Please forgive me if so, and if 
so I will ask again when others are present. I will break down my 
script into smaller part questions as time goes on. First thing, 
I am under the impression that if I can generate a random number 
between 1 and 1 billion and assign this result to an aribtray variable 
word like so

token: random/secure 1000000000

I want to email my newly generated random number to someone. So I 
thought of this:

send [person-:-example-:-com] "Thank you. Your number is token."

One second later I realized that will just the send the actial word 
token, not the number the variabkle word token represents.

Is the above a correct way to generate a random number?

How do I insert that random number into the body of the text of an 
email to send someone? (send [person-:-example-:-com] "Thank you. Your 
number is [token]" maybe?)

 Thanks for your help in advance, apologies for any breach of rules 
 or etiquette. 
You need to seed the random generator first eg. with the datestamp 
or something, and then generate your random number.  But a better 
way is to create a UUID if you want something guaranteed to be unique.

The library has code for windows http://www.rebol.org/view-script.r?script=guid.r

Just using random, something like this should work

random/seed form now/precise

send [person-:-example-:-com] rejoin [ "Thank you. Your number is " random/secure 
1000000  "." ]
welcome to Rebol John, 

this group's etiquette is: "there are no stupid or wrong questions".

In case you ever wonder if you are asking too advanced questions 
at some point .... the fact that you are thinking of asking them 
here is an indication that you're still a candidate for this group 
even the simplest questions are good to keep our memories intact, 
and I've learned quite a few things when trying to respond to some 
seemingly simple questions (often by looking at other people's innovative 
But there are off topic questions :)
BTW, looks like the 'form is not needed above
And don't wait for people to be online. One of the great things about 
AltMe is the async nature.
Thank you all for addressing my concerns and for your answers about 
my first coding question.

Ahh.. rejoin. Reading up on it makes me better understand how some 
things are to be done in Rebol.

 Continuing to the final goal...

I have to extract an email address from a GET transfer. The methoed 
of sending the info to me is completely out of my control. An email 
address will be entered into a form on a website not controled by 
me. GET methoed will send the data to my script. The people who created 
the form on the external site advised that they label the email address 
as "trnEmailAddress".

 So now I want to see if I am correct in thinking how to extract and 
 use the email address. Will using the decode a cgi form command (I 
 know they are not commands in the tradiational sense)  work. How 
 does it work, does it create variables out of the GET (or Post when 
 using Post, but I am forced to recieve the info via GET) stream?

The GET stream in my case will include "&trnEmailAddress=person%40example%2Ecom. 
So can I do this?

decode-cgi system/options/cgi/query-string

send trnEmailAddress "Thank you. Rest of message." 

Thanks for your help.
You can easily create an object! (ie a set of words) from the CGI 
This articles explaiins how:
....Section 3 is the quick guide

....The next few pages describe all the things that can go wrong 
(probably more than you need to know right now)

....Section 7 points you to a script that handles all the edge cases 
for you.
Sunanda: Thanks again for issuing the World invitation. Everyone 
thanks for the continuing help.

I have read the cited document, but it just leaves me with more questions.

Is the following literal?

cgi-string: read-cgi
cgi-block: decode-cgi cgi-string
cgi-obj: make object! cgi-block 

 That is to say should I type exactly that? Or is cgi-string for example 
 a theoretical variable assignment that I could call anything? Are 
 they all proper commands, or is any part of that just for example 
 purposes?  I am thinking I should copy and paste it verbatium. I 
 am also thinking I mispelt verbatum.

 I am stuck with GET. Does this mean I can leave out some code that 
 makes up for  not knowing if the original data is POST vs GET? These 
 are hypothetical questions for better long term learning. I for now 
 will go with the idea that everything is as straight fowarrd as it 
 seems. I know that my GET stream will have "trnEmailAddress" in it 
 which is a field that will contains an email address.

 So will the following  generate a random number, extract the address 
 and email the same random number to that email address?

token: random/seed now/percise

cgi-string: read-cgi
cgi-block: decode-cgi cgi-string
cgi-obj: make object! cgi-block 

send trnEmailAddress rejoin [ "Thank you. Your number is" token "." 

 Graham: Thank you for the extra info on GUID, but Windows is not 
 involved here. I realize that random number generating really isn't 
 unless you have a monkey throwing darts at a numbered board. Regardless 
 extra effort to 
make a number unique is useful and your advice appreciated. 

 I do not think the corner cases will come up and the people who control 
 the original form assured me that web page issues warnings if the 
 form is not filled out correct which should help. I do realize that 
 people are idiots, systems are not fool proof, etc. What I am saying 
 is my basic needs are basic and I should be OK so I am not fretting 
 over those examples. It is great though to know the solutions are 
 out there when I need them.

Yes, the names of the words are arbitrary. -- you can chose your 
own names.

Whether the data came in via GET or POST makes no difference if you 
issue the READ-CGI just once.

If the CGI string was yadda.com?email=[me-:-test-:-com]&token=0
then the cgi-obj will look like this:
    make object! [
    email: "[me-:-test-:-com]"
    token: "0"

Note the values are strings, so you need to convert the email value 
to an email! datatype:

  send to-email cgi-obj/email rejoin [ "Thank you. Your number is" 
  cgi-obj/token "." ]
If the CGI string was yadda.com

which is what a lot of indexing bots will use, then the cgi-obj will 
look like this:
    make object! [

Hence you do need to do some data sanitisation, no matter how much 
the form people assure you the data will be right.
John you have to seed the generator first and then generate your 
And you can dispense with the cgi-string by 

cg-block: make object! decode-cgi read-cgi
cgi-block is your variable, and the rest are functions
Here is an example:

cgi-obj: construct decode-cgi read-cgi

;check the input
all [
	in cgi-obj 'email
	trnEmailAddress: to-email trim form cgi-obj/email
	not empty? trnEmailAddress
] [
	;evrything seems ok

 send trnEmailAddress reform ["Thank you. Your number is" token "."]
print "Error!"
Missing an 'if :)
oh, yes.. Thanks for correcting. IF ALL [ ...
Thanks guys. Endo: Special thanks for  going so far as type out an 
example that includes checking out that everything is OK.

 I realize that one cannot trust outside sources of info and that 
 one has to always be prepared to outsmart dumb users, but the needs 
 of this project are straightdforward and I am in unfamilar territory 
 so if it can make things easier I can go on a bit of faith for now. 
 That being said, better code that covers mistakes is better code 
 and I am appreciative of it.

 Sunanda: That is what I thought, but I had to be sure. Thanks for 
 helping with the details.

 Graham: Is that general advice or a comment on code examples I posted? 
 I thought I had done what you just said.
Hi, I have a small problem playing an mp3 file 
I have so far
player: "/Applications/Vox.app/Contents/MacOS/Vox"
thissong: "/Users/Arnold/Music/A song.mp3" 
thatsong: "/Users/Arnold/Music/A-song.mp3"       
And then 
call reform [player thissong]  
call reform [player thatsong] 

Playing thissong will start the musicplayer, but no music was found 
and playing  thatsong starts the player and is being played without 

Because most of my mp3's and directories they are in have spaces 
in their names so starting to play them from REBOL gets hard this 

I tried to-file thissong but this produces "%/......&20song.mp3" 
so it was not successful. (Allthough thatsong just played without 
a problem) :(
Any ideas please?
Another thing, I want to make an 'application' using REBOL that plays 
an mp3, an mp3 with a story for kids and I want to display the pictures 
from the book depending on maybe a timer(file) so the pictures are 
displayed acoording to the storyline. This also could be a helping 
aid for making presentations. 

I do not want to binary save my mp3 in the source of the application 
or in any other rebol-script so I just want to use the mp3 file and 
not convert it.

Furthermore I do not want an external app to be started unless it 
can be done under the hood and/or it can be controlled by my app 
because the presentation could be paused by the user. Any ideas where 
and how to start such script.
Yet another task I think REBOL could help me with. Say I could not 
find the subtitles for an ancient tv-series i stumbled upon on the 
net. But I found subtitles in English. I can translate but some words 
will reoccur often, so I imagine a rebol script showing an original 
line or words to be translated. I type some translations and when 
I translate a word, all equal words in the rest of the document will 
change, saving me quite some time.