REBOL/View Graphics - Face Object
The object that defines and controls all graphics.
The entire REBOL graphics engine is built around a single, powerful element: the face object (named after interface).
REBOL's design is unique in that faces provide not only the lower level graphical objects of the system, but also the drawing canvas (raster or bitmap image), as well as the view (display port or window that projects the canvas). The look and feel of every graphical and user interface element is created and controlled by a face. Each REBOL window consists one or more faces, and a typical window is often built from hundreds of such faces.
The face object is defined by the standard object found in system/standard/face. This master face is the parent face for all other faces. Everything else is based on it, and when creating your own faces, it is important to inherit from this face object due to its relationship with the underlying REBOL implementation. Do not use your own definition of face or your programs may not work correctly.
This master face is used so often that a global variable called face also holds its value.
Note that the face object used by VID is derived from this master face. The VID face extends the object to provide additional fields required by the VID system. However, you can create useful and functional GUIs with the master face alone. You do not need the VID object definition unless you are using the VID system.
The fields below define the attributes of a face. In REBOL, these fields are called facets (named after the word "face") and they define every aspect of a face, including its state, properties, and behavior. Most of these variables are optional and should be set to NONE to save memory if they are not required.
To view the fields of the face object you can type:
>> help face
(This is handy to know while you are programming.)
|type||word!||This field is used internally, by the system, to verify that the object is structured as a face. It must be set to the word 'face.|
|offset||pair!||An xy pair that specifies the horizontal and vertical position of the upper left corner of a face. The default is 0x0. If the offset falls outside its parent face area (such as a negative offset value) the face will be clipped. If the parent face is the screen-face, then the offset is the location of the window on the screen. (See more below.)|
|size||pair!||An xy pair that specifies the width and height of the face in pixels. The defaults is 100x100. Negative values are not valid. The size includes the edge (border) if it is provided (see below). If the face is a window, then this size does not include the window borders and title bar.|
|span||pair!||Reserved. Must be set to none to be compatible.|
|pane||block! object! function!||A face or block of sub-faces that are to be displayed within the face. The pane allows you to create faces that contain other faces, to any depth. This is how all graphical interfaces are constructed in REBOL. A pane establishes a new coordinate system where each of its subfaces is positioned relative to its upper left corner. When a function is provided, the pane will be iterated based on the values produced by the function. This is useful for tables, lists, and more. We'll talk more about iterated faces below.|
|text||any-type||The text contents of a face. The text can be just a few letters or thousands of lines. Note that any printable (form-able) REBOL datatype can be specified; however, strings are optimal if a fast redraw speed is required, such as those used in iterated faces. (Non-string values must be converted to strings during the redraw operation, slowing down the redraw.) The attributes of the text (color, size, font, style) are determined by the font and para facets (see below). For large text areas, please read the line-list notes below.|
|color||tuple!||The color of a face. The default value is 128.128.128. A value of 0.0.0 is black, 255.255.255 is white, etc. Set color to none to make a face transparent. This color value is also used as the default for some types of face effects, such as gradients. (Note that semi-transparent faces are created using face effects described below, not by specifying an alpha value in this field).|
|image||image!||A background image for the face. This field must be an image! value, not a file name. Use the load function to load an image file prior to assigning it to this variable. Set this field to none for transparent or colored faces. Note that the image may be modified according to the effects block (scaling the image to the size of the face, changing its color, modifying the brightness, etc.)|
|effect||block! word!||Special effects for a face. A wide range of image processing effects are available. Multiple effects can be applied at the same time using the effect dialect. For example, you can change both the contrast and brightness of an object. See the Effects section for more information.|
|data||user-defined||This is a variable for storing state and other higher level information about the face. The type of data is determined by the programmer and the purpose of the face. For example, VID uses this variable to store the primary data of the face. Note that this field is not the only way to add "user" data to a face. The face object itself can be extended (using object inheritance) to allow additional data fields.|
|edge||object!||Specifies the border attributes of a face. This value is an object that includes the size, color, and effects for the edge (e.g. bevel, inverse bevel). If you want to modify the edge object, you should copy it first. See the Edge section below.|
|font||object!||Specifies the text font attributes of a face. This value is an object that describes the font style, size, color, alignment, shadow, and other attributes that can be provided. If you want to modify the font object, you should copy it first. See Font section.|
|para||object!||Provides the text paragraph attributes of a face. This object controls the text origin, margin, indentation, tabs, scrolling and other attributes. If you want to modify the para object, you should copy it first. See Para section.|
|feel||object!||Defines the behavior of a face. The feel object consists of a set of callback functions that are executed when specific face events occur. See the event handling section below.|
|saved-area||logic! image!||Enables faster rendering for transparent faces. When a face is transparent on a static (unchanging) backdrop, this field can be used to accelerate redrawing. It allows the face to change without requiring the backdrop (or any other faces that are behind this face) to be recomputed each time. If this variable is set to true initially by the programmer, when the system shows the face, the background image that it covers will be stored here.|
|rate||integer! time!||An integer! or time! that specifies periodic timer events for a face. This is used for animation or repetitive events (such as holding the mouse down on certain types of user interface styles). An integer! value indicates the number of events per second. A time! provides the period between events. The timer event is sent to the face feel Engage function with an event type of time.|
|show?||logic!||A flag that enables/disables showing of the face. This flag can be used to temporarily remove a face from view.|
|options||block!||Set options in a window face. This allows you to set whether a window has a title bar and borders; allows resizing; changes how over (hover) events are handled, and more.|
|parent-face||object!||The parent of the face. This is set by the system when the face is first shown and it is used to maintain the face hierarchy in memory. If necessary, you can use this field to determine a face's parent face. (Be sure to expect a none value if no parent exists, such as the top-level window face).|
|old-offset||pair!||Internal bookkeeping variable. Do not modify. Used by the system to determine dirty regions when faces are moved or resized.|
|old-size||pair!||Internal bookkeeping variable. Do not modify. Used by the system to determine dirty regions when faces are moved or resized.|
|line-list||block!||A block that holds text line information. This block is created, updated, and used by the system to optimize the updating of text. When you modify large areas of text (greater than 200 characters) you should set this variable to zero to force the system to recompute the positions of all lines. If you do not, you may see garbage characters appearing within the text.|
|changes||block!||Tell the graphics system what fields have changed. This is not normally required, but can be used to signal specific changes in a face that require special attention. For example, if you want to change a window title (caption) or activate a window, this variable must be set prior to the show function.|
|face-flags||integer!||Internal bookkeeping variable. Do not modify.|
|action||any-type||A user-defined field normally used to hold a function that will be called when a user-interface action is taken. If you are using faces directly (not in VID) you can use this field to store your own action function.|
Within applications, there are several ways to create the necessary faces. For instance, you can use VID to create the face objects. It's easy and quick to use.
Of course, as objects, you can create various prototypical faces (classes) for different types of display objects or control objects (input methods like fields, buttons, etc.) Then you can make new object instances easily for each type of face.
New faces (and/or prototypes) can always be created directly from the master face. The standard object creation method is used:
a-face: make face [ offset: 100x100 size: 200x100 color: red effect: [gradient] ]
This creates a new face object called a-face. All fields are inherited from the master face, except those new fields that are specified.
To see what the face looks like, use the view function:
The face will be shown in a window that looks like this:
This window appeared at 100x100 on the screen, and shows a horizontal red to cyan gradient (based on the face's color).
Actually, since this is a top level face, it defines a window and has a few special properties. For example, if you attempt to use text, it will appear in the window caption. More about that later.
You do not need to delete faces. Once you no longer use a face and there are no other references to it, REBOL will automatically garbage collect the face (recycle its memory).
For complex user interfaces, or those requiring a lot of images or special effects, you can help the garbage collector by setting fields to none that contain large structures (such as images). This allows the image memory to be recycled even if you still have references to the face (often from non-obvious locations or constructs in your program).
To display the fields of a face, you can use the help (?) function:
>> ? a-face A-FACE is an object of value: type word! face offset pair! 100x100 size pair! 200x100 span none! none pane none! none text string! "" color tuple! 255.0.0 image none! none effect block! length: 1 data none! none edge object! [color image effect size] font object! [name style size color offset space... para object! [origin margin indent tabs wrap? scroll] feel object! [redraw detect over engage] saved-area none! none rate none! none show? logic! true options none! none parent-face none! none old-offset pair! 100x100 old-size pair! 200x100 line-list none! none changes none! none face-flags integer! 1 action none! none
As your faces become more advanced (containing multiple layers of sub-faces) the dump-face function can be useful for debugging. But, for the face above, minimal information is displayed:
>> dump-face a-face Style: none Offset: 100x100 Size: 200x100 Text: