Monday 18 March 2013

Gob! type

Rebol 3 has a new type: gob!
GOB stands for Grafical Object, before using this guide, remember to launch load-gui

Concept

A GOB is a low-level graphical object.
GOBs are used for for constructing windows, panels, images, text, and drawings. They support two dimensional compositing with transparency (alpha channel), scalar vector graphics, image effects, and rich-text.
A GOB is a highly optimized native datatype. It has been designed to provide the primary features required for graphics, but substantially reduce the memory footprint and processing overhead required. As a result, complex displays, such as animations, simulations, or video games can be created that are composed of thousands of individual GOB elements.

Usually users do not need this information just to use the GUI. This information is provided for users who want to use the graphics system directly or to create new styles for the GUI.

GOB is a Datatype

A GOB is an optimized datatype for supporting graphics. Technically, it is not a series nor is it an object, but it will respond to action functions similar to both of those.

Making GOBs

New GOBs are created with make and a specification block.
gob1: make gob! [text: "Example" size: 400x40]
view gob1




logo-image: load %reb-logo.gif
gob2: make gob! [offset: 10x20 image: logo-image]
view gob2



You may use also the Rebol 2 Draw commands, but at the moment you can't access directly, you have to use the stylize function:


stylize [
 circle: [
 about: "A circle style"
 facets: [init-size: 100x100]
 draw: [
  pen black
  line-width 2.7
  fill-pen maroon
  circle 50x50 40
  ]
 ]
]
view [a: circle]



If inspect a/gob/draw you you'll find the DRAW commands, but don't try to modify directly it!


>> ? a/gob
A/GOB is a gob of value: make gob! [
 offset: 5x5
 size: 105x104
 alpha: 0
 draw: [translate 0x0 clip 0x0 105x104 anti-alias false pen false line-width
   1.0 variable
   pen 255.255.255 fill-pen false anti-alias true pen 0.0.0 line-width 2.7
   variable fill-pen 128.0.0 circle 50x50 40x40
   ]
]



Note that the specification block is not reduced and only valid field names are allowed (see list below.)
You can also create a GOB from another GOB, inheriting its settings:

gob4: make gob1 [text: "Another example"]


Content Types

Each GOB is of a content type that determines the format of its data and how it will be rendered on the display. Complex displays are created by combining layers of GOBs of these various types. For example, you can create a display that has colored text on top of an image on top of a draw-rendered gradient on top of a colored background.
Type Description
color An RGBA color to fill the specified area.
image An RGBA image. The size of the GOB is determined by the size of the image.
draw A block of scalar vector graphic (SVG) commands, such as line, box, and circle.
effect A block of special effect commands, such as blur or colorize, etc.
text A block of rich-text commands including special modes such as bold, italic, color, etc.
In addition a GOB may have no content type and just be used as a pane that holds a list of GOBs that will be composited together. For example a window or a panel used for an input form may be used just for "organizational" purposes.

Access Fields

A GOB datatype allows access to the following fields:
Field Datatype Description
offset pair! the x-y coordinate relative to parent
size pair! width and height of gob canvas or coordinate space
pane block! a block of child gobs (see below)
parent gob! the parent gob (in its pane)
data object! block! string! binary! integer! none! normally used to reference data related to the gob, such as the VID face object
flags block! special flags, see section below
alpha integer! alpha transparency for the gob overall
owner gob! a temporary field used for popup windows to specify the owning parent window
For example:
agob/offset: 100x100
print agob/size
bgob: agob/parent

In addition, these fields are used to access the content of a GOB, depending on its type:
Field Datatype Description
color tuple! the color of the gob
image image! an image within the gob
draw block! a DRAW dialect block
effect block! an EFFECT dialect block
text block! string! a richtext dialect block
Examples:
agob/color: blue
agob/image: load %photo.jpg

Note that you can only specify one content field per GOB. If you attempt to set a second field, it overwrites the earlier one.

Offset and Size

Spatial information about the GOB can be accessed with:
Name Description
offset The x-y offset of the GOB relative to its parent. Either value (or both) can be negative and clipping will occur.
size The width and height of GOB content area. Any graphics that extends outside this area will be clipped.
For example:
gob/offset: 100x20
print gob/offset
gob/size: 150x50

Data Reference

The primary purpose of the data field is to provide a way to reference an object, block, or other data related to your rendering, subsystem, or application.
Although the data field is under the control of the programmer and is not accessed by the GOB system itself, it is used by subsystems like the GUI. For example, in the GUI the data field might point to the face object that stores run-time information such as event handling to quickly locate the face.
Internally, the data field is pointer-sized (32 bits as of writing this page) for optimization reasons. It is not a fully-qualified value field, so can only hold the specific values mentioned above, and any series references contain no indexed offsets. If you need to store general values, use a block or object.

Panes

The pane field provides the tree structure (the hierarchy) for a GOB display. Each pane begins a new relative-coordinate system with sub-GOBs located within it.
Each GOB can include a content and a pane. In such cases, the content is layered behind any GOBs of the pane. The GOBs of the pane are also clipped according to the size of the parent GOB.
The order of layering for GOBs in a pane is last-on-top. That is, they are rendered in the order they appear in the pane, with each successive GOB on top of the others.
Reuse restriction: When a GOB can only be in one pane at a time. If you attempt to insert a GOB into more than one pane, it will be removed form it prior pane. This is a necessary requirement of the linked list used to manage panes and state internal variables required for rendering.

Adding GOBS to Panes

To add one or more GOBs to a pane, use the append or insert functions.
For example, given these gobs:
gob1: make gob! [size: 200x200 color: white]
gob2: make gob! [offset: 20x20 size: 40x30 color: red]
gob3: make gob! [offset: 120x80 size: 50x40 color: blue]

this line will add gob2 to the gob1 pane:
append gob1 gob2
view gob1


Or, you can add several GOBs at the same time:
append gob1 [gob2 gob3]
view gob1


Note that the block of words is not reduced, but words will be looked up.

Other Useful Actions

You can use other series-like functions, such as getting the length:
length? gob1
Or clearing the pane, or specific parts of the pane:
clear gob1
clear at gob1 2

You can also remove from the pane:
remove find gob1 gob2

As well as use indexing refinements:
gob1/1: gob4
gob1/2/image: new-image

All Valid Actions

Here's a full list of all the action functions that operate on the GOB datatype:
Action Description
append Inserts a value at tail of series and returns the series at head. (Modifies)
at Returns the series at the specified index.
back Returns the series at its previous position.
clear Removes all values. For series, removes from current index to tail and returns tail. (Modifies)
find Finds a value in a series and returns the series at the start of it.
head Returns the series at its head.
head? Returns TRUE if a series is at its head.
index? Returns the index number of the current position in the series.
insert Inserts into a series and returns the series after the insert. (Modifies)
length? Returns the length of the series from the current position.
next Returns the series at its next position.
past? Returns TRUE if a series index is past its tail.
pick Returns the value at the specified position in a series.
poke Returns value after changing its data at the given index. (Modifies)
remove Removes value(s) from a series and returns after the remove. (Modifies)
reverse Reverses a series and similar types. (Modifies)
skip Returns the series forward or backward from the current position.
tail Returns the series at the position after the last value.
tail? Returns TRUE if empty, or for series, if index is at or beyond its tail.
take Copies and removes from series. (Typically, removes last GOB.)

Coordinate Mapping

Each GOB pane provides it's own coordinate system. That is, all of it's sub-gobs are located relative to the origin of their parent.
Often you will need to take a position at the top level and map it to a position within a sub-gob, or within even deeper sub-gobs. There are two functions to help perform this mapping:
Function Description
map-gob-offset Translates a gob and offset to the deepest gob and offset in it, returned as a block: the gob and offset. Also supports the reverse operation: given a GOB and offset, provide the GOB and offset within its top-most GOB.
map-event Within an event datatype that has a GOB and offset position, modify the event by mapping to its terminal (lowest) GOB and offset.

GOBs as Windows

The screen and its windows are controlled with GOBs. New windows are opened by adding a window GOB to the screen GOB pane. Windows are closed by removing the window GOB from the pane.

The Screen GOB

The screen-gob is a field in system/view object. The size field of the GOB is the size of the screen:
print system/view/screen-gob/size
1440x900

Each GOB within the screen-gob/pane is a window.

Creating a Window

Note: See R3 View - Windowing System for more information about windows.
Normally, windows are created by the view function. Internally, it creates a new GOB for the window. The offset provides the position of the window, and the size provides its width and height. If text is provided, it will become the window caption. (Window GOBs do not allow color, image, draw, or effect content types, only text for the caption.)
For example, if you create a GOB:
win: make gob! [text: "Test Window" offset: 100x100 size: 300x200]

You can use that for a window by calling view this way:
view/as-is win ; use the argument as the window itself

Or, you could open the window on screen with this:
append system/view/screen-gob win
show win

However, this method should be avoided. You should use the view function, which handles many other features.

Window Flags

Window GOBs accept these special flags:
Flag Description
dropable allow drag and drop of files
hidden window is hidden
modal modal event handling (for requestors)
no-border do not draw window borders (or title)
no-title do not show window title
on-top keep window on top
popup a popup window (has owning parent window)
resize allow the window to be resized
transparent let the window be transparent
These flags can be set like this:
win/flags: [resize dropable]

or during the MAKE with:
win: make gob! [size: 100x200 flags: [resize]]

You can obtain the flags block with:
probe win/flags

Event Handling

Window events such as mouse moves and button clicks are mapped by the native system to an offset within a specific window gob. The higher level event system is responsible for locating the specific sub-gob target of the click, if that action is desired.
Typically, a GOB that requires interactivity, such as processing of button events will be part of a higher level face object, and the processing of the specific events will be done by functions of that face.
For more information see R3 View - Event Handling and R3 View - Windowing System sections.

Rendering Graphics

Graphics is rendered with the show function. This same function is used for both initial rendering as well as updates (refresh). The target GOB to render is specified as the argument.
The line:
show gob1

Render gob1 as well as all sub-gobs in its pane, if it has one. If the GOB is already being displayed, it's display would be refreshed.
This same function is true for window GOBs:
show win

renders all of the graphics in the window and redisplays it.
The show function also allows a block of GOBs:
show [gob1 gob2 gob3]

As you can see, if the gobs are words, their values will be used.
Here are a few important notes about rendering:
  • Rendering order is first to last
    For GOB panes, each GOB is rendered in the order it appears in the pane, with each successive GOB on top of the others, with the last GOB on top.
  • Background refresh
    When a GOB offset is moved relative to its parent GOB, or when it changes size, any background behind the GOB is re-rendered. (Internally a GOB stores its old-offset and old-size information for use in this process.)
  • Optimized show
    If a gob appears more than once within a show block (and the panes of gobs in that block) the second case of the GOB will be ignored (an optimization).
  • Delayed show
    If you are changing several GOBs during a single event, it is more efficient to keep a list of changes then render all the changes together with a single call to show. In the R3 GUI, this is done by defining a show-later that queues the requests to a block, then calls show-now to refresh the display.

Transparency

GOBs support two levels of transparency.
  1. Images or colors may specify transparency. For example, an image with transparent rounded edges.
  2. The transparency of a GOB can be controlled with /alpha. This setting affects the entire GOB (and all subGOBs within it). The range is 0 to 255.
An example of setting the transparency of a GOB:

gob1: make gob! [size: 200x100 text: "Example of transapency"]
gob2: make gob! [size: 180x50]
gob2/image: load %logo.gif
gob2/alpha: 200
append gob1 gob2
view gob1



Note on speed optimization: if an image or color is found not to be transparent, and the /alpha field fully opaque, the compositing system will optimize the action (using a non-transparent blit). The speed difference is significantly faster, but should only matter in special cases, such as when moving or updating large areas of a window (e.g. playing a large animation or video, where alpha is not so important.)

Examples

The example below creates a window with a background image and an image on top of that background. Note, that setting gobb/image to back-img automatically sets gobb/size to the image's size - or, to state it differently, for image GOBs the size is always equal to that of the image.
Rebol []
;-- Background image
gobb: make gob! [offset: 0x0]
gobb/image: load %rebol-3d.png
;-- Top image:
gobi: make gob! [offset: 10x10]
gobi/image: load %icon.png
;-- The window:
win: make gob! [] ;[text: "Test Window"]
win/size: gobb/size
append win gobb
append win gobi
view win

4 comments:

  1. Excellent tutorial. Very useful. Thanks!

    ReplyDelete
  2. Thank you, unfortunately at the moment DRAW is buggy, see https://github.com/angerangel/r3bazaar/issues/3

    ReplyDelete
  3. Added to http://rebol.informe.com/wiki/view/GOB! wiki, so anybody can contribute and add examples.

    ReplyDelete
  4. I'd like to correct you, you do not have to use STYLIZE to use draw, you can display DRAW GOBs (almost) directly:

    >> gob: make gob! [draw: []]
    == make gob! [offset: 0x0 size: 100x100 alpha: 0 draw: []]

    >> to-draw [pen black fill-pen red circle 50x50 40] gob/draw
    == [pen 0.0.0 fill-pen 255.0.0 circle 50x50 40x40]

    >> view gob

    You need to use the TO-DRAW function, it translates DRAW dialect keywords to command! type. This way it can run much faster.

    ReplyDelete