Friday, 13 July 2012

VID tips and tricks

I found this guide:
So I think that it is better to copy here:
Author: pat665
Date: 30-juin-2004


1. Introduction

This is a collection of "good-to-know" information about Rebol/View and VID. Some are mine, most are from the Rebol-List, books or articles about Rebol.

2. 3002-As-pair and to-pair


To-pair as a new friend: As-pair. Reading the new document about the Draw dialect, I found a new function 'as-pair.
>> help as-pair

Combine X and Y values into a pair.
AS-PAIR is a function value.

x -- (Type: number)
y -- (Type: number)

This seems to be more useful than to-pair. It is simpler to work with:
; direct value
>> as-pair 2 5
== 2x5
; variables
>> x: 3
== 3
>> as-pair x x * 2
== 3x6
>> as-pair x 2 * x
== 3x6
>> to-pair 2 5
== 5
>> to-pair [2 5]
== 2x5
>> to-pair reduce [x x * 2]
== 3x6

3. 3004-An example of using the alpha chanel from Cyphre

An example of using the alpha channel from Cyphre.
x: 0
d: 5
view center-face layout [
    origin 0x0
    image site/nyc.jpg 300x300
    at 0x0 ;same position
    image site/bay.jpg 300x300 rate 30 feel [
            engage: func [f a e][
            x: x + d
            if x > 250 [d: -5]
            if x < 5 [d: 5]
            f/effect: compose [fit alphamul (x)]
            show f

Here is a simple example how to use DRAW dialect for "painting" into alpha channel of the image. I think with the function make-alpha (bellow in the example) you can draw almost any kind of transparent shape though it is not the fastest method....IMO the possibility to use DRAW pens for alpha channel should be done at Rebol's native level...

make-alpha: func [fx img /local idx][
      append fx 'grayscale
      fx: to-block mold to-image make face [
          size: img/size
          effect: fx
          edge: none
     fx: fx/3/2
img: to-block mold img
      idx: 0
remove-each i fx [
          idx: idx + 1
            either idx > 1 [
              if idx = 3 [idx: 0]
     append img/3 fx
     return do load img
 pic: load-thru/binary
   view center-face layout [
      backdrop effect reduce ['gradient red orange]
      image make-alpha [
          gradient 1x1 0.0.0 255.255.255
         draw [
             pen 0.0.0
             fill-pen 200.200.200
            circle 100x80 50
            fill-pen 0.0.0
            box 80x80 125x125
         ] pic

Note from Cyphre Hello to myself, just little correction: You can use the make-alpha function not only with DRAW but with any other effect-block command (like the transparent gradient in the example) ..and little note: this script need at least Rebol/View version 1.2.5 and up or Rebol/Link from the version where alpha-channel support was added.

4. 3005-How to change the aspect of a box with effect?

How to change the aspect of a box with effect?
Rebol []
a: load-image
luma-fxblock: [luma 80]
grey-fxblock: [grayscale]
reduce [ 'colorize yellow]
view center-face layout [
  b1: box 100x100 a effect []
  b2: box 100x100 a effect []
  b3: box 100x100 a effect []
  b4: box 100x100 a effect []
  btn 100 "luma" [ insert b2/effect copy luma-fxblock show b2 ]
  btn 100 "greyscale" [insert b3/effect copy grey-fxblock show b3 ]
  btn 100 "colorize" [insert b4/effect copy color-fxblock show b4 ]
  btn 100 "reset" [remove b2/effect   remove b2/effect   show b2 ]
  btn 100 "reset" [remove b3/effect   show b3 ]
  btn 100 "reset" [remove b4/effect   remove b4/effect   show b4 ]

5. 3006-How to change the font of a button?

How to change the font of a button?

Rebol []
view center-face layout [
    b: button "Font Test" font [
      name: "Arial"
      size: 12
    abutton: button "rebol is cool" 150x30 [
        face/font: either ((face/font) = font-a) [:font-b][:font-a]
        show face
        do [
        font-a: make abutton/font [ size: 12 ]
          font-b: make font-a [size: 18 ]
          abutton/font: font-a
          button "Change" [b/font/name: "Times" b/font/size: 18 show b ]

6. 3007-How to change the style of a button?

How to change the style of a button?
Rebol []
view center-face layout [
    style btn1 button green
    a: btn1
    b: btn1 "ok" [unview ]  

7. 3008-How to change the windows title

How to change the windows title?
lay: layout/size [
    btn "Title 1" [set-face lay "Bye everybody !"]
    btn "Title 2" [set-face lay "Ok I stay here"]
    ] 300x100
    lay/access: make lay/access [
        set-face*: func [face value] [face/text: value face/changes: 'text ]
view/title center-face lay "Hello world"

8. 3009-How to create draw buttons?

How to create draw buttons?

8.1. Creating a draw button

Simple shaped buttons can be designed with the draw dialect.
view center-face layout [
  box 24x24 effect [draw [
      pen black
      fill-pen red
      circle 12x12 10

This code produce a red filled circle. However this is more an image than a button because there is no action.

8.2. Adding action

As for any face, action for the right clic is provided in a block, example: [ print "hey, I'm clicked!"].
Defining a draw-button style helps us to save typing.
Rebol []
draw-layout: [
    h2 "Draw buttons"
    style draw-button box 24x24 effect [
        draw [ pen black fill-pen red circle 12x12 10]
    draw-button [print "hey, I'm clicked!"]
    draw-button [print "hey, I'm clicked!"]
    draw-button [print "hey, I'm clicked!"]
    draw-button [print "hey, I'm clicked!"]
view center-face layout draw-layout

9. 3011-How to hide a face when view is called?

How to hide a face when view is called?
The purpose here is to have a face invisible when the layout is displayed the first time by view. The answer is to set face/show? to false. Use show to set the face visible again An example:
Rebol []
example: layout [
  a: button  
  button "Hide" [hide   a ]
  button "Show" [show a]
a/show?: false
view example

Rebol []
view layout [
  f: field with [ show?: false ]    
  t: text "test"    
  button "Show" [show f]

11. 3013-How to navigate through window-pane?

How to navigate through window/pane? What I am looking for is a way to navigate through window/pane to change some faces without the need of a variable. For example, with a layout composed of a,b,c,d,e I would like that a click on b will change c. In other words, knowing one face, being able to move to the next or the previous face.
var class="dt-cmt">; a simple layout
lay: layout [
  text "Hello"
  button "Test" [mytest face]
; explore lay/pane
mytest: func [f [object!] /local f2 ][
  ; here an object
  foreach face lay/pane [ print [face/style type? face] ]  
  ; here a block
  f2: first find lay/pane f
  print [f2/style type? f2]  
  view center-face lay

11.1. From Romano

var class="dt-function">view layout [
  style bt button [
      value: next find face/parent-face/pane face
      face: first either tail? value [head value][value]
    print face/offset
    bt bt bt bt bt ]

The parent-face is set only after view function has been called (= the layout function does not set it).

11.2. From Brett

In face, the Pane of a face can be one of three types:
  1. face/pane can be set to Object! - In this case the pane contains a single face. A face inside a face.
  2. face/pane can be set to Block! - In this case the pane is a collection of faces. More than one face inside a face.
  3. face/pane can be a Function! - In this case the face is iterated. "Virtual" faces that are calculated dynamically. Examples of this last one in VID is List and Text-list.
You need something to identify the face in the layout. One way is by position. If the faces are A, B, C then B would be the second face in the layout.
view lay: layout [
  text "A"
  text "B"
  text "C"
  button   "Second face" [print lay/pane/2/text]

Or instead of navigating when you need to change, you set up a reference early - assuming your layout does not change:
lay: layout [
box "A"
box "B"
box "C"
button "Change" [ if face/user-data [
    face/user-data/color: get first head reverse [blue green]
    show face/user-data
    ] ] ]  
; Make the user-data field of button refer to the "B" text face.
lay/pane/4/user-data: lay/pane/2  
view center-face lay

The third way is to search through every time looking for some identifying information. Remember though that if you have things like panels you will have a tree of faces with the top layout being the root. So you might need to search recursively. I made some functions to do this searching. Note that they cannot find the "iterated" faces.
do load-thru cc  
change-color: func [face] [
  face/color: random 255.255.255
view/new lay1: layout [
  style box box 50x50
  text "A"
  box "B"
  box "C"
  text "D"
  panel orange [box "E"]
  button "Change D" [show change-color find-face [face/text = "D"] ]
  button "Change E" [show change-color find-face [face/text = "E"] ]
view/new lay2: layout/offset [
box "D"
button "Change Boxes" [ repeat face find-faces [ all [in face 'style face/style = 'box] ] [change-color face] show lay1 show lay2   ]
  button "Close All" [unview/all]
  ] add 2x1 * lay1/offset 1x0 * lay1/size  

These are some ways to avoid using variables. A lot of the time variables are very useful and make understanding the code easier. You can variables in their own contexts to avoid cluttering up the global context or clashes between windows if you have more than one. Here is an example wishes uses this concept.
var class="dt-cmt">; Create a template spec
spec: [
  box-face: none
  lay: layout [
      box-face: box gray
      button "Change" [
          box-face/color: random 255.10.10
      show box-face
      ] ] ]  
; Create multiple layout faces in their own contexts.
context-collection: copy []
current-offset: 50x150
repeat i 5 [
  ; Create a new layout face
  ctx: context spec  
  ; Add it to our collection
  append context-collection ctx  
  ; Reposition it.
  ctx/lay/offset: current-offset  
  ; Move our offset ready for the next
  current-offset/x: current-offset/x + 20 + ctx/lay/size/x  
  ; View it
  view/new ctx/lay
; Close and Change all.
view/new layout/offset [
  space 0x0
  origin 0x0
  button "Change All" [
      repeat ctx context-collection [
          ctx/box-face/color: random 10.255.10
    show ctx/lay
    ] ]
      button "Close All" [unview/all] ] 50x50  
      ; Process events

12. 3014-How to simulate action on one button?

How to simulate action on one button? I'd like to get the same effect as if I had done a mouse click on one button, but this "action" is originated from script itself.

If you create a reference to the face (e.g. my-btn: button), then you can do this:
click-face: func [face][face/feel/engage face 'down none ]

12.1. Other solutions...

view layout [
  b: button "Test" [print "Test pressed"]
  button "Action 2" [b/action b none]

var class="dt-function">view layout [
  b: button "Test" [print "Test pressed"]
  button "In" [b/state: true show b]
  button "Out" [b/state: false show b]
  a: button "Action" [
    b/feel/engage :b 'down none
    b/feel/engage :b 'up none
    a/state: false
    show a ; Not sure why this line is needed...

The "Action" button probably gives you the effect you want, but I'm not sure if it's the best way to do it. If the final line is missing the "Action" button itself stays down for reasons I don't understand, though it's maybe because it's sharing the engage function.

13. 3015-Iterate through the faces of a layout

How to iterate through the faces of a layout?
When you create a layout such as layout puts the set words into face/var So you can iterate through the pane faces and find them out.
lay: layout [
  my-button: button
  my-field: field
foreach face lay/pane [
  print [face/var face/style face/offset face/size   ]

If you want to see the words inside a face, use:
print mold first face
Anton. Every face (like a radio) added to a window is appended to the block window/pane. The group is in the field 'related of the radio face. The variable name is in the field 'var of the radio face.

>> w: layout [
 r1: radio of 'groupe1
 r2: radio of 'groupe1
 r3: radio of 'groupe1
>> foreach x w/pane [print [x/var x/related]]
== r1 groupe1
 r2 groupe1
 r3 groupe1

>> lay: layout [
  my-button: button
 my-field: field
>> foreach face lay/pane [ print [type? face face/var face/style face/offset face/size] ]
== object my-button button 20x20 100x24
  object my-field field 20x52 200x24

14. 3016-VID styles

How to get all the VID styles?
vid-styles: copy []
pad-string: "               "
cpt: 0  
foreach [style x] system/view/vid/vid-styles [append vid-styles style]
sort vid-styles  
foreach v vid-styles [
  style: mold v
  cpt: cpt + 1
  either cpt < 6 [ prin [style copy/part pad-string (15 - length? style)] ][print style cpt: 0 ]    
  print " "

Here the standard result:
  • ANIM
  • AREA
  • BAR
  • blank-face
  • BODY
  • BOX
  • BTN
  • CODE
  • face
  • H1
  • H2
  • H3
  • H4
  • H5
  • ICON
  • INFO
  • KEY
  • LAB
  • LBL
  • LED
  • LIST
  • TEXT
  • TOG
  • TT
  • TXT
  • VH1
  • VH2
  • VH3
  • VH4
  • VLAB

15. 3017-Keyboard shortcuts

How to use keyboard shortcuts?
Just use the key
view layout [
  text "Press Enter or Esc"  
  key enter [alert "You pressed Enter"]  
  key escape [alert "you pressed Escape"]  

16. 3018-Resizing an image

The trick is to use 'layout to perform the resizing. Example:
var class="dt-set-word">img: load %my-image.png
img2: to-image layout [origin 0 image 50x50 img]
save/png %my-image2.png img2

17. 3019-Screen size

How to get the screen size?

>> system/view/screen-face/size
== 1024x768

TIP! This information comes from the center-face function source.
>> source center-face
== center-face: func [
   {Center a face on screen or relative to another face.}
   obj [object!]
   /with "Center relative to a face." face [object!]
   if none? face [face: any [obj/parent-face system/view/screen-face]]
   obj/offset: max 0x0 face/size - obj/size / 2 + either with [face/offset] [0x0]

18. 3020-How to create a bmp file from an image

How to create a bmp file from an image?
view center-face layout [
x: box snow 201x201 effect reduce [ 'gradient 0x1 164.200.255 'grid 8x8 0x0 0.0.0 ]  
button "save" [save/bmp %grid.bmp to-image x]

19. 3021-Selections with list

How to get the selected items of a list?
view layout [
text-list data ["one" "two" "three"] [print face/picked]]

To select more than one, just use the CTRL button.

20. 3022-Stylize/master

An example using stylize/master.
to-width: func [x] [75 + 8 * x - 8 ]  
stylize/master [
  ;     VID types
  lbl: lbl blue to-width 1
  field: field to-width 1
  date-field: field [
      if not empty? face/text [
        either none? attempt [to-date face/text] [
            clear face/text ] [face/text: form to-date face/text show face ]
  ;     Derived types
  lab-address: lbl "Address:"
  fld-address: field to-width 3
  lab-date:     lbl "Date:"
  fld-date:     date-field
  lab-code:     lbl "Code:"
  fld-code:     field
view center-face layout [

22. 3024-Usage of with in VID

Answers to a post of mine regarding 'with. Here is the test code:
draw-layout: [
  h2 "Draw buttons"  
  style draw-button box 24x24 with [ effect:   [draw [
      pen black
      fill-pen user-data
      circle 12x12 10
  r-btn: draw-button user-data red [print "hey, I'm red"]
  b-btn: draw-button user-data blue   [print "hey, I'm blue"]
  y-btn: draw-button user-data yellow [print "hey, I'm yellow!"]
  g-btn: draw-button user-data green   [print "hey, I'm green!"]
view center-face layout draw-layout

22.1. Answer from Brett

Could someone tell me more about this "magic" with ?... All REBOL/View faces are objects. VID and LAYOUT are used to create this object but using a simpler more powerful way to express how to create them. So LAYOUT [ button ] will create an object for the button (it will also create another for the window but lets ignore that for the moment).
When you use LAYOUT [button red] an object is created but this time with a colour of Red.
The VID language and LAYOUT translate the "red" into an action of setting the face's colour facet to red.
WITH is part of the VID language that allows you to specify the facets using a normal REBOL object specification.
So the object that is created has this specification applied to it.
For example, instead of LAYOUT [button red] you could write
layout [button with [color: red] ]

As you can see [button red] is easier, but the advantage of WITH is that you can create entirely new facets using it.
For example,

>> layout [btn: button with [my-special-facet: "Brett"]]
>> btn/my-special-facet
== "Brett"

>Why effect is now a set-word! ? Vid styles are objects too. When you use
layout [style draw-button box 24x24]
You are creating another style object, one which is based on the box style. When Romano used WITH in creating a style he was using a normal REBOL object specification to change the facets (object fields) of the style. This is why EFFECT became a set-word.
> Why is it no more needed in "user-data red"? The style that was created now has this EFFECT. Every face based on that style will have the same EFFECT by default. The EFFECT block refers to USER-DATA which is a built-in facet of every VID style. USER-DATA is a VID keyword and built-in facet.
For example

>> layout [btn: button user-data "Brett"]
>> btn/user-data
== "Brett"

As you can see just like setting the colour we can set USER-DATA just as easily.
> I was asking myself the same questions, when Anton stabbed me in the back with an even more puzzling code with a "little dialect using the words facet". ...
As it seems to me, words is a face/facet used to define a face behaviour in the form of a function.
In this function, new is the object face, while args is a block like [fill 255.0.0 [print "hey, I'm red"]].
The "next args" part is a bit of a puzzle, because it cannot be removed or the face is not displayed correctly.
Pretty close.
Yes WORDS is a facet, but it is used during LAYOUT *only* not during the display of the face. It is a way that more keywords can be added to VID so that your custom styles can have their own specific VID keywords. So what Anton has done is to create a new keyword FILL that is valid for the DRAW-BUTTON style.
When LAYOUT processes this specification [draw-button fill red ] it executes the WORDS of DRAW-BUTTON to process the FILL keyword.
Its goal seems to return whatever is left to be processed to finish the face display.
Yes whatever is left needs to be given back so that LAYOUT can process other attributes and facets after the FILL (and its data). This is an advanced technique. But as you can see it is very powerful.
Using WITH to make custom facets and WORDS to add custom VID keywords you can create altogether new VID styles that are very easy to specify. I hope this helps. Brett.

22.2. Answer from Romano

Could someone tell me more about this "magic" with ? why is it no more needed in "user-data red"?
Why effect is now a set-word! ?
All the magic is relative to object and binding of words. When you define an object starting from a previous object:
ob: make object! [a: 1] make ob [a: 2]
you assign a new value (2) to the word 'a of the object: this can happen because the word 'a in the block is bound to the word 'a in the object before executing the block.
The sequence of operations is:
  1. duplicate object ob and its context
  2. bind the block [a: 2] to the new context
  3. evaluate the block [a: 2]

Now in 3) when you change the value of 'a in the block, you really change the value of 'a in the object.
The point is that words are not variable, they have not a value, they are alphanumeric pointers to context, which are "invisible" structure created by make object! (not only).
The 'with word of Vid is a shortcut for something like this, only 'ob is the style face and the block is the 'with block. The 'effect word of Vid, instead, does not bind the block to the object context, only assign the block to the effect field.
Effect [draw [pen user-data]] is like:

new-face: make face []
new-face/effect: [draw [pen user-data]]

with [effect: [draw [pen user-data]]]
is like
new-face: make face [effect: [draw [pen user-data]]]
only in the latter case the block is bound to the face object before executing.
Ciao Romano

23. 3025-[VID] How to reset guide?

How to reset guide?
I have the following layout:
view layout [
  a: txt "test1"
  b: txt "test2"
  c: txt "test3"
  d: txt "test4"

And I want to be 'd in line with 'a. How do I get rid of the 'guide once set?
I just want to disable it until the next 'guide happens.
I never actually use guide, but this seems to give you what you want...
view layout [
  a: txt "test1"
  b: txt "test2"
  c: txt "test3"
  d: txt "test4"
  e: txt "test5"

Hope that helps.

24. 3001-Clear-fields - how to improve it?

Hi All, CLEAR-FIELDS is one of those really handy functions that annoys me. :\
It's very useful, but also problematic in that it only clears FIELD faces, not AREAs; much less CHECK, RADIO, etc. *and* it only works if a field contains a SERIES! value.
Admittedly, coming up with a completely general solution would probably add lots of code, but can it be made better without too much effort and added code?
I think so, but I'm not sure how far to go, assuming we want to submit the improved version to RT for future inclusion. Here's the standard version:
clear-fields: func ["Clear all text fields faces of a layout." panel [object!] ][
  if not all [in panel 'type panel/type = 'face] [exit]
  foreach face panel/pane [
      if all [series? face/text flag-face? face field] [clear face/text face/line-list: none ]

This one works for AREAs as well, and sets non-series values to NONE:
clear-fields: func ["Clear all text fields faces of a layout." panel [object!] ][
  if not all [in panel 'type panel/type = 'face] [exit]
  foreach face panel/pane [
      if any [flag-face? face field   flag-face? face area][
        either series? face/text [
        clear face/text face/line-list: none ][face/text: none ]

This one does the same as above, but tries to MAKE the type of value that's in the field. E.g. numeric fields would reset to 0:
clear-fields: func ["Clear all text fields faces of a layout." panel [object!] ][
  if not all [in panel 'type panel/type = 'face] [exit]
  foreach face panel/pane [
      if any [flag-face? face field   flag-face? face area][
        either series? face/text [
        clear face/text face/line-list: none ][face/text: attempt [make face/text none ] ] ] ] ]

Beyond these simple kinds of changes, should we directly add support for CHECK, RADIO, etc. or is it better to adopt a more general approach, e.g. using a dialected block as a parameter, that you use to reset the display in your app?
The latter approach makes it more effort to use, but potentially much more useful as well. Any thoughts, or other implementations would be welcome.
-- Gregg

25. 3003-Button with on-off texts

How to change a button text depending on the on/off state?
Just add ontherstring:
view layout [button   "Normal" "Pressed" ]

26. 3010-How to get to a field variable by its string name?

How to get to a field variable by its string name?
; Here we have 4 fields 'fv1, 'fv2, 'fv3, 'fv4
; The idea is to get one by its number
; building the litteral name, like "fv1"  
change-fv: func [/local i n s w f ][
  n: random 4
  ; build a word from the string "fv" + n
  w: to-word rejoin ["fv" n]  
  ; get the global variable attached/bind the w
  f: get :w  
  ; it works ! ! !
  f/text: "Changed"
  show f
fav: layout [
  style fv text 200 "text"  
  fv1: fv "A"
  fv2: fv "B"
  fv3: fv "C"
  fv4: fv "D"  
  btn-enter 60 "test" [change-fv]  
  ] ; layout  
  view center-face fav

No comments:

Post a Comment