# Oberon/ETH Oberon/Tutorial/GadgetsUse

These tutorial pages were written by André Fischer (afi) with editorial assistance of Hannes Marais, were hosted at the ETHZ and remain under the ETH license. Related content is found in the system via Book.Tool. Extended content is also available on paper. Some tutorial pages are in the WayBack archive.

## Objective

Learn how a gadget is inserted in the display space, how to name it and, more generally, understand the concept of gadget attributes. Review the rich gadget collection supplied with the system. Understand and exercise the composition of gadgets for building new applications with a graphical user interface or for adapting an existing interface to your preference.
Estimated time: 60 minutes.

## How to instantiate a gadget
### Inserting a visual gadget - Gadgets.Insert

Gadgets.Insert ViewNewProc ~ creates a new instance of a visual gadget of the specified type and inserts it in the display space at the caret position. Say, the module M contains a procedure P whose task it is to dynamically allocate a new instance of a certain object type. "M.P" is then called the object's New procedure or generator. Executing the New procedure M.P causes a new instance of that object type to be created and initialized to a default state so that it is ready to accept messages (i.e. it is totally functional). As the object does not know what to do with itself after creation, another command is needed to display the new object (that is, if it is a visual gadget). The Oberon module "Gadgets" provides a standard interface for creating and inserting objects.

### Linking a model gadget to a gadget - Gadgets.Link

Gadgets.Link ModelNewProcedure ~ creates a new instance of a model gadget of the specified type and links it to the selected visual gadgets. If a model gadget is already linked to the selected gadgets, it is removed first.

### Inserting a visual + model gadget pair

Gadgets.Insert ViewNewProc ModelNewProc ~ has the same effect as the command sequence
    Gadgets.Insert ViewNewProc ~
    Gadgets.Link ModelNewProcedure ~
ViewNewProc identifies the New procedure of the visual gadget to create. The ModelNewProc identifies the model gadget to be linked to the newly created gadget. For example, the following creates a Model-View pair of a button and a boolean:
    Gadgets.Insert BasicGadgets.NewButton BasicGadgets.NewBoolean ~
This new gadget pair is inserted at the caret position. Note that many gadgets function both with and without a model. Typically, a button need not have a model gadget.

## The gadget attributes

The interesting property of gadgets is that they can be modified and used wherever they are located. Oberon System 3 creates new user interfaces (GUI) or modifies existing ones in typical drag-and-drop fashion. UI construction is reduced to document editing.
To this effect, each gadget type has its own set of attributes, used to configure a particular gadget instance, but all gadgets have two attributes in common, namely the Gen (Generator) and the Name attributes. Each attribute consists of an attribute name and an attribute value pair, that define a part of the gadget's appearance and behaviour. An attribute is typically used to specify the caption of a button, the color of a gadget or the command that a gadget must execute when solicited by a middle mouse key click.
In addition, a gadget may be extended with user-defined attributes.
Columbus can be used to inspect and change the current attribute values for the purpose of customization. You will have plenty of opportunities to practice that later in this tutorial. Attributes can also be interrogated and set using commands or under program control.

### The Gen attribute

The Gen attribute contains the name of the Generator or New procedure which created, or if you prefer allocated, this gadget instance. It is a read-only value, that is, it cannot be customized. However, a visual gadget of a given type can be converted into a gadget of another type with the command Gadgets.Change. This possibility is rarely used.

### The Name attribute

The Name is one of the most important attributes of a gadget and each gadget has such an attribute. When a gadget is instantiated the attribute contains the empty string. It is used to reference the gadget, either from other gadgets, or from application programs. A gadget or an application program referencing another gadget's name can search for and find (or not find) that other gadget in a specified environment or context. Gadgets often use names to refer to each other's attributes. Practically, a gadget refers to another gadget's attribute with the following syntax:
       ObjectName.AttributeName
where ObjectName is the gadget's name (attribute) and AttributeName is the attribute name to access. Have you observed the difference between "name attribute" and "attribute name"?
The name belongs to the gadget, i.e. it is stored inside the gadget itself which means that a copy of a named gadget has the same name.

### Name scope

Name scoping is used when a named gadget belongs to a private library. The scope in which the system searches for gadgets is determined by the hierarchy of container elements. The current name scope is determined when a gadget executes a command or receives a message, and is exactly the container in which the gadget is located. The ancestor is sent a special Find message to search for the specified object. The find message propagates in a breadth-first fashion from the ancestor to all descendants until the named object is found. If needed, a gadget may enlarge the search space by starting the find operation at a higher point in the container hierarchy, at the risk of hitting on a ambiguous name.

### The Cmd attribute

The Cmd attribute may contain a string specifying what action should be taken when the user clicks on the gadget with the middle mouse key. This action is coded as a procedure in the Oberon language, i.e. the string must represent an Oberon command, with or without parameters. The procedure can search for objects in the user interface and change their state accordingly. For example, the command attribute "Edit.Open Test.Text" specified in a button will open a text viewer displaying the file "Test.Text" when you click on it. Using a very simple script facility, parameters may be edited before they are passed to the procedure: embedding special macro characters in the command string allows attributes to be accessed, selections to be processed, strings to be edited, etc. These macros are used to combine different gadgets together, and have enough power to build graphical interfaces for some classes of Oberon applications.
If this string is empty or it cannot be interpreted as a command, no action is taken.
Very few gadgets do not have this attribute, e.g. the calendar, the clock, etc.

### The ConsumeCmd attribute

The ConsumeCmd attribute may contain a string specifying what action should be taken when a gadget is consumed by the gadget. The string's specifications are identical to those of a Cmd attribute string above. In addition a macro character may be used to control consume operations processing the consumee(s). Currently, only the icon gadget is equiped with this attribute.

### The Color attribute

Some gadgets have a Color attribute. The Gadget system uses a palette of 16 or 256 colors depending on the hardware installed. Each color is identified by an integer 0 .. 15 or 0 .. 255 respectively. The ColorPicker is very convenient to set the color attribute of a gadget: to this effect, a default value for its Cmd attribute is already defined.

### The GridSnap attribute

Container gadgets such as the Panel, are equiped with a grid snap attribute that allows easy positioning of their descendants. The snap function, which has no equivalent in hand drafting, forces displayable gadgets to align to a raster of (invisible) vertical and horizontal lines when moved or copied. The integer value assigned to the attribute specifies the raster lines distance in pixels. The default snap distance is 4 pixels.

### The Locked attribute

Often you would like to restrict the editability of the gadgets you create. Editing may mean changing the position or size (see Resizing and moving) of the gadgets in a panel or another container. This editability is determined by two things. First, the gadget may be programmed in such a way that it cannot be moved or resized. This is an inherent restriction determined by the programmer. Second, the Locked attribute is a boolean which determines the gadget's editability.
You will observe in the presentation of the visual gadgets collection that all the container gadgets (iconizer, note-book, organizer, panel, panel document, text gadget) have this attribute. Note that the attribute controls all and only the direct descendants of a container. That is, you cannot selectively lock only some descendants and you have to lock nested containers yourself. Since the editability of a contained gadget is controlled by its context (ancestor), when it is moved to another context its editing behaviour changes.
After having created a UI, you may explicitly freeze it using Columbus, and users can unlock a UI at any time to make adjustments.

## The visual gadget collection

Oberon System 3 comes to you with a comprehensive collection of gadgets, each of which is described in detail hereafter. In the future, new applications delivered with the system may add their own gadgets.
Each gadget description contains the following sections:
* Generator: Procedure used to create a new instance of that type.
* Alias: Short form for the New procedure, if one is defined.
* Function: An explanation of the gadget's meaning and usage.
A detailed description of the gadget attributes and of commands related with the gadgets is contained in Chapter 4 of the "The Oberon Companion" which is included in the distribution. This material is best digested in the form of printed document and is too voluminous to fit in a HTML document.
To support the detailed explanations which follow, we suggest that you prepare and reserve a small free area of your desktop for inserting new gadgets in that area (simply clicking on the command) and that you use Columbus to study the various attributes at the same time as you read this tutorial. These gadgets are immediately operational, can be modified and combined at discretion and you can even hone them until they become workable objects, eventually. Otherwise, they are throw-away products.
Alternatively, you could insert an almost complete collection of visual gadgets at once with a single click on BasicGadgets.Panel. In that case you will also need Columbus. You will then observe that all these gadgets are fitted with a 'custom' attribute "Tutorial" otherwise not documented. It serves the purpose of directing the help icon to the gadget's description in this tutorial. Consequently, you are given the choice of reading this tutorial sequentially (the gadgets are presented in alphabetical order) or at random.
The disadvantage of this alternative is that it uses an optically large panel and that your display space will be crowded. You would do well to use the 'Document List' button on your desktop! Do not 'Store' that panel, only 'Close' it.

### Button

Generator: Gadgets.Insert BasicGadgets.NewButton ~ Alias: Button
Function: A button can be pushed in and out with a middle mouse key click. You have already exercised with a button in another tutorial. It may have a string or a visual gadget as caption that identifies the button's function. It may be linked to a boolean or to an integer model gadget. A button has the ability to execute a command when clicked on. An attribute indicates if the button should pop out after clicking on it. Buttons function as radio-buttons when linked to an integer value. To build a set of radio-buttons, several buttons are linked to the same integer gadget. Each gadget remembers a certain number, and when the integer gadget has that value, that button will be pushed in. A command is provided to assign unique numbers to button gadgets.

### Calendar

Generator: Gadgets.Insert Clocks.NewCalendar ~ Alias: Calendar
Function: A calendar showing the current week day and date.

### Caption

Generator: Gadgets.Insert TextFields.NewCaption ~ Alias: None
Function: A caption is a text, often used for titles or comments in panels and other container gadgets. A caption may consist of multiple lines of text. Only limited editing capabilities are provided for captions. The focus point is set with a left mouse key click. The gadget is then framed in a thin rectangle but no caret is visible. When focused, characters typed are appended to the caption. Use the backspace key to correct or modify a caption. A selected text may also be appended by copying. When a caption is selected the font and the text color can be changed with one of the EditTools commands.
Useful hint: A caption may be typed directly in a panel at the caret position. It is not necessary to insert the caption first with Gadgets.Insert Caption ~

### CheckBox

Generator: Gadgets.Insert BasicGadgets.NewCheckBox ~ Alias: CheckBox
Function: A check box functions like a button except that it shows a little check mark when set to TRUE. It may be linked to a boolean or to an integer model gadget. It functions like a radio-button when connected to an integer gadget. In that case, the check mark is rectangular.

### Circle

Generator: Gadgets.Insert BasicFigures.NewCircle ~ Alias: Circle
Function: A circle of variable radius. Selecting a circle causes two control points to appear, one at the center and the other on the circumference. Either control point may be dragged on the middle mouse key to change the position and the radius of the circle.

### Clock

Generator: Gadgets.Insert Clocks.NewClock ~ Alias: Clock
Function: An analog clock with hour and minute hands showing the current time.

### ColorPicker

Generator: Gadgets.Insert ColorTools.NewColorPicker ~ Alias: ColorPicker
Function: A ColorPicker shows the current color palette of the system. The color are listed from top to bottom, left to right, from color index 0 to the number of colors available. Pressing the middle mouse key on the ColorPicker pops up a menu from which a color can be selected. The color is then applied to the last selection, either a text, gadget or gadget group. Note that not all gadgets can be colored.

### DigitalClock

Generator: Gadgets.Insert Clocks.NewDigiClock ~ Alias: DigitalClock
Function: A digital clock showing the current time in hours and minutes.

### Finder

Generator: Gadgets.Insert Finder.NewDocList ~ Alias: Finder
Function: A finder is used to quickly find a document among the many documents piled in a container. Finders are typically placed in the desktop, although they function in other containers too. Moving the mouse cursor to the finder and pressing the middle mouse key pops up a list of document names from which one can be selected. When the mouse key is released, the selected document is brought to the front of the container. A finder is captioned "Document List".

### Icon

Generator: Gadgets.Insert Icons.NewIcon ~ Alias: Icon
Function: An icon provides a caption for its content, a single child. When created, an icon contains nothing. At this stage it will consume a gadget as its content. Once an icon has consumed a gadget, it will not accept any other gadget for consumption. Selecting such an icon and issuing the command Icons.Break reverses the operation.

### Iconizer

Generator: Gadgets.Insert Icons.NewIconizer ~ Alias: Iconizer
Function: An iconizer is used to build various types of menus. It can be treated as a flip-card, with a gadget on each side of the card. Flipping the card switches from one gadget to the other. Initially, the iconizer contains no gadget, but can be flipped between its two faces Open and Close. A flip button is located in the top left corner of the iconizer. Clicking on this button flips the iconizer. When building a menu, one side of the card represents the menu, and the other represents the menu items. When one state is empty, a gadget may be dropped into the iconizer to become the view of that side of the card. By setting attributes, the iconizers can be changed into different types of pop-up menus.

### Line

Generator: Gadgets.Insert BasicFigures.NewLine ~ Alias: Line
Function: Display a line.

### List

Generator: Gadgets.Insert Lists.NewList ~ Alias: List
Function: see List

### NamePlate

Generator: Gadgets.Insert NamePlates.NewNamePlate ~ Alias: NamePlate
Function: A NamePlate shows the name of the document in the document menubar and the name of the desktop when located inside of one. The name is the string value found in the DocumentName attribute of the TextDoc gadget, LogDoc gadget, or PanelDoc gadget in the case of a desktop. Most editing operations work in the same way as those in a main editable text - the name may be changed, a stretch of text may be selected, deleted or copied. One restriction is that, in order to set the caret (clicking the left mouse key), the mouse focus must point at the very bottom of the NamePlate. The NamePlate then enters a local editing mode in which carriage returns (RETURN) are not accepted. The other restriction is that the font, the color and the vertical offset cannot be changed.

### Navigator

Generator: Gadgets.Insert Navigators.NewNavigator ~ Alias: Navigator
Function: Your desktop, as provided by the Gadgets System, has four times the size of your display screen. It is organized in four quadrants, only one of which is visible at a given moment. The navigator is a miniature representation of these 4 quadrants showing profiles of the objects dropped on the desktop and in which the quadrant appearing on the display is marked in black. You can drag objects from the current quadrant to any of the other 3 adjacent quadrants or bring objects to the current quadrant by positioning them on the border between quadrants. Clicking on one the quadrants transports you to that quadrant which becomes visible.

### NoteBook

Generator: Gadgets.Insert NoteBooks.New ~ Alias: NoteBook
Function: A note-book organizes gadgets as pages of a note-book. All pages are of the same size which means that, if not locked, resizing a page causes all other pages to be resized accordingly. The title, i.e. the name attribute of the current page is displayed at the top of the note-book. Two arrow-shaped buttons allow you to turn the pages forward or backward. The title bar consumes a new page which is then added to the end of the note-book. A page can be removed by dropping it at a different location or with a right plus left keys interclick.

### Organizer

Generator: Gadgets.Insert Organizers.NewPanel ~ Alias: Organizer
Function: An Organizer is a panel extended with a simple constraint solver to reorder the children automatically when the organizer is changed in size. Organizers are distinguished from panels by a diagonal line in the top left corner of the organizer. The constraint system is based on virtual wires: four wires are strung between the four sides of a descendant and an edge of the panel. The horizontal sides of the child gadget are attached to the top or bottom of the panel, and the vertical sides to the left or the right. The length of the four wires are given as four numbers in the Constraint string attribute of the child. Positive numbers string the wire "outward" and negative numbers "over" the gadget.
That is
Gadgets.ChangeAttr Constraints "10 20 10 10" ~
sets a constraint on the selected child where the left edge of the gadget is 10 pixels from the left of the panel, the top edge 20 pixels from the panel top, the right edge 10 pixels from the panel right, and the bottom edge 10 pixels from the panel bottom. Thus the sequence of numbers are left, top, right, and bottom wire distances. Changing the 20 to -20 attaches the top edge of the gadget 20 pixels from the bottom of the panel.

### Outline

Generator: Gadgets.Insert Outlines.NewOutline ~ Alias: Outline
Function: An Outline, which functions inside a text gadget only, implements a way to fold text away into a gadget. When folded, the outline is a black rectangle. Middle clicking on the folded outline "unfolds" its content between two arrows. Text in an unfolded outline may be freely edited. Clicking on one of the two arrows folds the text back into the outline: an interesting device for presenting detail or explanatory information without overloading a main text. Be cautious however, deleting an outline arrow may prevent an outline from being folded again. Note that the compiler cannot compile the text contained in folded outlines, you first need to expand them all.

### Panel

Generator: Gadgets.Insert Panels.NewPanel ~ Alias: Panel
Function: see extra description

### PanelDoc

Generator: Gadgets.Insert PanelDocs.NewDoc ~ Alias: PanelDoc
Function: A PanelDoc is a document containing a single a panel gadget. The document can be given a name and can be saved in a file with that name. If the panel document is opened with the command Desktops.OpenDoc (PanelDoc), it appears with a menu bar containing buttons captioned [Close] and [Store]. If it is opened in a viewer of the textual user interface, the menu bar appears with two additional buttons [Copy] and [Grow].

### ProgressMeter

Generator: Gadgets.Insert ProgressMeter.NewFrame ~ Alias: ProgressMeter
Function: Display a meter showing the progression on a data transfer. It is used in the HyperDocs.Panel for example.

### Rectangle

Generator: Gadgets.Insert BasicFigures.NewRect ~ Alias: Rectangle
Function: A rectangle, possibly filled. Selecting a rectangle causes two diagonally opposite control points to appear. The control points can be adjusted by dragging on the middle mouse key. A rubber-banding line indicates the current rectangle which takes its final shape when the mouse key is released.

### Rectangle3D

Generator: Gadgets.Insert BasicFigures.NewRect3D ~ Alias: Rectangle3D
Function: A rectangle with a 3D-effect, possibly filled. Selecting a rectangle causes two diagonally opposite control points to appear. The control points can be adjusted by dragging on the middle mouse key. A rubber-banding line indicates the current rectangle which takes its final shape when the mouse key is released.

### RefFrame

Generator: Gadgets.Insert RefGadgets.NewFrame ~ Alias: RefFrame
Function: A RefFrame (also called visual reference gadget) provides a frame for visualizing a Reference to any object of type Objects.Object. This frame can have three different representations:
    - when it does not refer to an object,
    - when it refers to a visual gadget,
    - when it refers to a model gadget.
The practical advantage of this gadget is that a reference represents an object irrespective of its type (visual gadget or model) and of its size. It can be dragged-and-dropped or copied over to another context just as easily as the object it represents.
A visual reference can be changed either by dropping a visual gadget into its frame or by copying over a selected visual gadget. Alternatively, a reference from another reference can be dropped or copied over with the same effect. When a reference is changed by such a user interaction, it will execute a consume command if so specified. Middle mouse click on a reference to inspect it with Columbus. To remove (or clear) the reference use a right-left interclick inside the reference. Like most other visual gadgets, a reference may execute a command when clicked on. This gadget is used in Objects.Panel and in Libraries.Panel, two components of Columbus for which it was designed, but can be used in any other environment.

### Scope

Generator: Gadgets.Insert Gages.NewFrame ~ Alias: Scope
Function: A bar chart of the previous values taken by the model gadget linked to it. A vertical bar is added to the right when the model changes its value. When the chart fills the scope, the bar chart scrolls to left as new vertical bars are added. The minimum and the maximum value observed in the visible portion of the chart are displayed on the left. The scope adjusts its scale automatically according to this value range.

### RembrandtDoc

Generator: Gadgets.Insert RembrandtDocs.NewDoc ~ Alias: RembrandtDoc
Function: A picture document displaying a single Picture gadget. The contained picture can be edited with the drawing, operation and color tools provided in Rembrandt.Panel. If it is opened with the command Desktops.OpenDoc (RembrandtDoc), it appears with a menu bar containing buttons captioned [Close], [+], [-] and [Store]. [+] magnifies the selection, or the entire picture if there is none. The button may be clicked 5 times in succession to obtain a magnification of 16. This makes it very easy to retouch pictures pixel-wise. [-] reduces the entire picture. The button may be clicked a maximum of 5 times in succession until the original size is restored, and not beyond. If the document is opened in a viewer of the textual user interface, the menu bar appears with two additional buttons [Copy] and [Grow].

### RembrandtFrame

Generator: Gadgets.Insert Rembrandt.New ~ Alias: None
Function: A RembrandtFrame provides a frame for visualizing a single Picture model gadget.

### ScrollView

Generator: Gadgets.Insert Gages.NewFrame ~ Alias: ScrollView
Function: A ScrollView is a View which can be fitted with an horizontal or a vertical scrollbar or both according to its attribute values.

### SetFrame

Generator: Gadgets.Insert SetGadgets.NewFrame ~ Alias: SetFrame
Function: A SetFrame provides a frame for visualizing a Set model gadget. One bit can be included or excluded by clicking on its placeholder (bit 0 start at the left hand side of the gadget). A bit is on when black bar appears at its corresponding position. A SetFrame may be linked to an integer or to a Set model gadget.

### Sisiphus

Generator: Gadgets.Insert Sisiphus.New ~ Alias: Sisiphus
Function: An animated cartoon representing a walking man called Sisyphus. Clicking on a sisiphus activates a screen saver, which is then removed by pressing the Esc key.

### Slider

Generator: Gadgets.Insert BasicGadgets.NewSlider ~ Alias: Slider
Function: see Slider. It may be linked to an integer, a real or a string model gadget. Like any other gadget, a slider can be resized but it's particularity is that it may be resized to a vertical or horizontal device with a handle sliding accordingly.

### Spline

Generator: Gadgets.Insert BasicFigures.NewSpline ~ Alias: Spline
Function: A spline, possibly filled. Selecting a Spline causes control points to appear at the line joints. The control points are adjusted with the middle mouse key. A right interclick while dragging a control point inserts an additional control point. A left interclick while dragging a control point deletes the point.

### TextDoc

Generator: Gadgets.Insert TextDocs.NewDoc ~ Alias: TextDoc
Function: A text document provides the possibility of saving text to files. The child of a text document container is a text gadget. If the text document is opened with the command Desktops.OpenDoc (TextDoc) , it appears with a menu bar with buttons marked [Search], [Replace], and [Store]. The [Search] button searches for the selected text stretch in the text. Each time the [Search] button is pressed, the caret advances to the next location in the text where the pattern appears. When the end of text is reached the searching wraps around to the beginning of the text. The [Replace] button replaces the last searched for pattern with the current text selection. The caret then advances to the next occurrence of the search pattern. Repeatedly pressing the [Replace] button replaces all the following occurrences of the search pattern. A replacement can be skipped by pressing the [Search] button as many times as required. At any time the [Replace] button can be pressed to start replacing occurrences of the search pattern.

### TextField

Generator: Gadgets.Insert TextFields.NewTextField ~ Alias: TextField
Function: A TextField allows the editing of a single line of text. It can be linked to an Integer, a Real, String or compatible model gadget. Full Oberon-like text editing capabilities are available for a text field. The caret or focus point is set with a left mouse key click and selections are processed with the right mouse key. A text field enters a temporary, local editing mode during editing. During this time the frame of the text field seems to pop out from the screen. While in this editing mode, changes made to the contained text string are not immediately reflected in the model gadget linked to the text field. As soon as the cursor is removed or when the RETURN key is pressed, the local editing mode is left and the model and view are made consistent. The previous value (if still available from the model gadget) is restored in the text field when ESC is pressed. When text fields are linked to model gadgets other than the string model gadget, a value conversion will take place to the same format as the model gadget. In some cases, a conversion is not possible, resulting in a default value being shown depending on the exact nature of the model gadget. When multiple text fields are located in the same container, the TAB key advances the caret from one text field to another. Setting the caret and pressing the left and right arrow keys scrolls the contained text horizontally when the content is wider than the width of the text field.

### TextGadget

Generator: Gadgets.Insert Gadgets.New ~ Alias: TextGadget
Function: A text gadget allows the editing of texts. Full Oberon text editing capabilities are available for text gadgets. Most Edit commands also operate on text gadgets. However, the commands Locate, Search and Replace were replaced by similar but more powerful commands implemented in the TextDocs module. In addition to the basic editing facilities of Edit, styles are supported. Styles are inserted in a text gadget by pressing Ctrl-Enter (The keyboard). A style may have one of the following modes: left, middle, right and pad.

### TextHyperlink

Generator: Gadgets.Insert TextGadgets.NewControl ~ Alias: TextHyperlink
Function: A TextHyperlink is a text control, and is only visible in a text gadget when control viewing is switched on with the command TextDocs.Controls. A hyperlink contains an Oberon command to be executed when the colored text located immediately in front of the text is middle clicked on. Note that the text in front of the hyperlink has to be in a different color than black for the hyperlink to activate.

### TextNote

Generator: Gadgets.Insert TextGadgets.New ~ Alias: TextNote
Function: A TextNote is a TextGadget without a scroll bar. The only difference is that due to the absence of scrolling, the text note grows in size automatically (width and height) to ensure that the entire text is visible.This gadget can be used like a memo pad or post-it note and a set of TextNotes may be organized in a note-book. It can also be used as a pop-up menu, as an alternative to a List, with the additional facility of allowing gadgets to flow in the text. Color may be used to enhance the presentation.

### TextStyle

Generator: Gadgets.Insert TextGadgets.NewStyleProc ~ Alias: TextStyle
Function: A TextStyle is a text control gadget that influences the formatting of text. The visibility of style gadgets is toggled with the TextDocs.Controls command. They have the shape of a thin horizontal dotted line with black weights at the end. A style can be inserted at the caret with the TextGadgets.NewStyle command, or by pressing CTRL-ENTER on your keyboard. In that case all the styles are made visible. On the Macintosh, use the num-lock key instead. The style is divided into two sections, the top part, above the dotted line, controls the formatting; the bottom part controls the setting of tabulators (or tabs). Middle mouse key clicks above the dotted line are as follows: when pressing and dragging on the area the black weights occupy, the left border and the formatting width can be specified; clicking next to the weight (but not on top of it), switches the weight on and off. The weights pull the left and right text ends of a text line to them. In this way left, block, center, and right adjust can be selected. A new tab is inserted with a middle and left keys interclick when the mouse focus is positioned below the dotted line. A tab shows up as small black rectangle and can be moved by dragging on the middle mouse key. Tabs are removed by dragging them completely out of the style gadget. All these adjustments can be made more comfortably than with the mouse, by assigning values to the attributes Tabs, Left and Width. Note that tabs only show themselves when left-adjust mode has been selected. Copying a stretch of text always makes a copy of the gadgets contained in that stretch (styles are gadgets too). The Pagebreak attribute is used to specify if a page break should be inserted before the style when printing. Styles that cause a page break are shown with a filled instead of a dotted line. When a TextStyle is named and placed in a public library, it can be re-used many times in the same document or even in different documents

### TimeStamp

Generator: Gadgets.Insert TimeStamps.New ~ Alias: TimeStamp
Function: A TimeStamp shows the date and time the document it is contained in was last stored on disk. The date and the time are formatted according the specifications contained in the DateFormat and the TimeFormat fields in the [System] section of the registry. Default values DD.MM.YY and HH:MM:SS respectively, are assigned to these fields in the registry of a newly delivered system.

### View

Generator: Gadgets.Insert Views.NewView ~ Alias: View
Function: A View acts as a camera displaying a single visual gadget. This allows you to have many different views of the same gadget. A view may be empty, i.e. display nothing, in which case it can consume a gadget for display. Each view has a certain viewpoint of the thing it displays (camera angle). The viewpoint can be changed by picking the displayed gadget up by its border and moving it to its new location. Should the border be invisible because the gadget is too big, an invisible area around the top left corner of the view can be used to grab and move the displayed gadget. Refer also to the ScrollView which is View with optional horizontal and vertical scrollbars.

## The model gadget collection

For an explanation of the model gadgets see Gadgets Introduction and Using Model Gadgets.
Each gadget description contains the following sections:
* Generator: Procedure used to create a new instance of that type.
* Alias: Short form for the New procedure, if one is defined.
* Function: An explanation of the gadget's meaning and usage.

### Boolean

Generator: Gadgets.Link BasicGadgets.NewBoolean Alias: Boolean
Function: A Boolean is a model gadget that stores a BOOLEAN value. Booleans function as models of button and check box gadgets. See Boolean

### Complex

Generator: Gadgets.Link Complex.New Alias: Complex
Function: Complex is a compound model gadget with attributes specifying the real and the imaginary part of a complex number.

### CurrentDirectory

Generator: Gadgets.Link Gages.NewDrv Alias: CurrentDirectory
Function: A CurrentDirectory model gadget stores the working directory the system is currently using. This model gadget is typically visualized by a TextField gadget.
Exercise: Set the caret on the desktop and click on:
    Gadgets.Insert TextField CurrentDirectory ~

### CurrentLoad

Generator: Gadgets.Link Gages.NewLoad Alias: CurrentLoad
Function: A CurrentLoad model gadget stores the current work load of the Oberon system. The workload is estimated from the frequency at which the system obtains control in the Oberon loop. This model gadget is typically visualized by a Scope gadget.
Exercise: Set the caret on the desktop and click on:
    Gadgets.Insert Scope CurrentLoad~

### Event timer

Generator: Gadgets.Link Gages.NewLap Alias: EventTimer
Function: An EventTimer model gadget stores the current system load, which is calculated from the frequency the system gains control in the Oberon tracking and event loop. It is an unscaled number.
Exercise: Set the caret on the desktop and click on:
    Gadgets.Insert TextField EventTimer~

### Integer

Generator: Gadgets.Link BasicGadgets.NewInteger Alias: Integer
Function: An Integer is a model gadget that stores a LONGINT value. It may be visualized by text fields, sliders or buttons. When linked to a set of buttons or check boxes (or a mixture of buttons and check boxes), the buttons and check boxes function as radio buttons. In this case, the buttons and check boxes should be assigned unique integer values to be stored in their respective SetVal attributes. This can be conveniently done with the command BasicGadgets.SetValues. A button or check box is "on" when its assigned integer value corresponds to the integer gadget value. See Integer.

### MemoryUsed

Generator: Gadgets.Link Gages.NewMem Alias: MemoryUsed
Function: A MemoryUsed model gadget contains an up-to-date indication of how much of the Oberon heap is currently being used.
Exercise: Set the caret on the desktop and click on:
    Gadgets.Insert TextField MemoryUsed ~

### Picture

Generator: Gadgets.Link Pictures.NewPicture Alias: Picture
Function: A Picture is a model object containing a colored two-dimensional bitmap visualized by a RembrandtFrame to which it is linked as model. It has no attribute at all, and no further attribute can be attached to it. A picture editor called Rembrandt is included in the system to edit bitmaps.
Exercise: Set the caret on the desktop and click on:
    Gadgets.Insert Rembrandt.New Picture ~

### Real

Generator: Gadgets.Link BasicGadgets.NewReal Alias: Real
Function: A Real is a model gadget that stores a LONGREAL value. It can be linked to slider or text field gadgets. See Real

### Reference

Generator: Gadgets.Link RefGadgets.NewReference Alias: Reference
Function: A reference to any object which is an extension of Objects.Object. This model gadget is visualized by a RefFrame gadget.

### Set

Generator: Gadgets.Link SetGadgets.NewSet Alias: Set
Function: A Set is a model gadget that stores a 32-bit set. It is normally visualized by a SetFrame gadget, but it may also be linked to a text field, a slider, a button or a group of them.

### String

Generator: Gadgets.Link BasicGadgets.NewString Alias: String
Function: A String is a model gadget that stores a string value of up to 64 characters. See String

### Text

Generator: Gadgets.Link Texts.New Alias: Text
Function: Text is the abstract data type used for manipulating text in the Oberon system. Text can be of (practically) unlimited length, and contain font, color and vertical offset information. Gadgets can float inside a text stream. Texts are not true gadgets and have no attributes.

## The Gadgets module
### How to copy gadgets - Gadgets.Copy

Copying gadgets can be done in two different ways. Copying both the visual and the model gadgets is called a deep copy. Copying only the visual gadget which then visualizes the same model gadget as the original is called a shallow copy. A shallow copy can be made directly with the mouse. For example, dragging a gadget with the middle key followed by a right interclick causes a shallow copy of the gadget(s) to be inserted at the mouse position. A deep copy has to be made explicitly with the command:
    Gadgets.Copy
It takes the selection, makes a deep copy of it, and inserts it at the caret position. Deep copies are structure preserving. The Gadgets.Panel provides a button to make deep copies.

### Using model gadgets

To allow programmers to add new model gadgets that function with existing visual gadgets (sliders, buttons, text fields etc), a message protocol between model and visual gadgets is used. The message protocol is currently limited to the simple types boolean, integer, string and real. In essence, a visual gadget can indicate in which attribute (or field or component) of the model gadget it is interested in. A few visual gadgets have a string attribute called "Field" which contain such an attribute name. If this attribute is empty, the default attribute "Value" is assumed. Thus model gadgets may be of a compound nature and can be visualized by many different visual gadgets, each of which is displaying a different attribute of the model gadget they are linked to. Should the model or the view change, the message exchange protocol is activated to ensure the consistency between model and view.
In addition to the commands that instantiate a gadget and manipulate attributes, the gadget module also exports the following commands:

### Changing the type of a visual gadget - Gadgets.Change

Gadgets.Change viewNewProcedure ~ changes the selected (of course visual) gadgets into a new type. The old models of these gadgets are kept.

### Setting an attribute value - Gadgets.Set

Gadgets.Set Obj.Attr value ~ changes the attribute of the indicated gadget. This command must be executed from the same context as the target's context.

### Setting an attribute - Gadgets.ChangeAttr

Gadgets.ChangeAttr attrName attrValue ~ sets the value of the attribute of the selected gadget.
Attributes can be set directly using Oberon commands. These are used seldomly, but are sometimes useful to change attributes under the control of another gadget.
AttributeValue can take several forms, depending on the type of the attribute:
       names For string attributes Yes/No For boolean attributes 1234 For number attributes "strings"  For string attributes
Note that you may add any attribute you want to a gadget. Attributes that the gadget knows about will be forced to a certain type. Attributes that are unknown will be stored, but ignored.

## Macros

Macros are used to process the attributes of gadgets. They act as the glue between different gadgets. Typically, a gadget executes a command when activated, the parameters of which are retrieved from the display. The parameters may be the selection, for example, or the value of an attribute of a certain gadget. The macros are first expanded completely and the resulting text is passed to the executed procedure in the normal Oberon fashion. This makes it possible to add user interfaces to existing Oberon applications. The system massages the parameters in such a way that it can be parsed in the conventional way.

### Lookup macro &

The lookup macro is useful when you want to pass a command a parameter, where the value of the parameter is the attribute value of a certain gadget. The macro has the syntax &ObjName.AttrName and on expansion it searches for the object named ObjName inside the current scope, extracts its AttrName attribute value, and inserts this value into the command string. An example is when you wish to open a text file (the name of which is written in a text field) when you click on a button. First you have to name the text field, say TF, using Columbus. Then by executing the following command, the Cmd attribute of the button can be set:
    Gadgets.ChangeAttr Cmd "Edit.Open &TF.Value"
Note that both the button and text field must be in the same name scope i.e. have the same container.

### Activator macro #

The activator macro returns an attribute value of the gadget that is executing the command. It is used in the form #AttrName, where AttrName identifies the name of the attribute. An example can be found in the List gadget. Here an attribute Point contains the item that is clicked on in the list.

### Initiator macro !

When objects are consumed by other objects, the objects being consumed are called the initiators or senders, and the object doing the consuming is called the recipient or receiver. This macro appears often in ConsumeCmd attributes, and allows access to the attribute values of the initiators. The consume command is executed by the recipient. The macro takes the form !AttrName, and expands to a list of attribute values of each object in the group of initiators. It can be used for compiling a list of files when you drop their icons on a compiler icon. Suppose the attribute Filename indicates the name of the file (it must be an attribute of the file icons), then the following may be used to set the ConsumeCmd attribute of the compiler icon:
    Gadgets.ChangeAttr ConsumeCmd "Compiler.Compile !Filename ~"

### Selection macro ^

As in the standard Oberon system, this macro expands to the current selection. The Gadgets System uses a slightly extended selection semantics. Here a macro in the form ^AttrName expands into a list of attribute values of all selected objects. If no gadget is selected, the text selection is assumed. This allows, for example, the creation of a command that act on a group of selected gadgets. As before, this device can be used to elegantly build a compile button that takes the selection as parameter. Note that the selection returned always contains at least a whole word even when only the beginning of the word is selected.

### Processor macros {, }, |

A processor macro always has the following form: { prefix | suffix | list}. When it expands, each word in the list is given a prefix and/or a suffix as indicated. Prefix and postfix may be omitted. A processor sequence like { | /s | ^ } would expand to the current selection with each word with a /s suffix.

### String concatenation

Most macros behave in a way that may seem strange at first. Macros are identified by a special initial symbol !, &, etc followed by a parameter. While expanding macros, the system needs to know when to terminate parsing the parameter. By default, this is when no character is left to be scanned (end of string) or a space is reached. However, when a space is reached first, the space is not included in the expanded macro. If you want a space to be included in the expanded text, you have to explicitly insert another space after the first one. This feature allows you to concatenate macros. For example, if O1.Value is "Hello" and O2.Value is "World", then:
    "&O1.Value &O2.Value" (one space separator)
will expand to "HelloWorld", while:
    "&O1.Value &O2.Value" (with two spaces in-between)
will expand to "Hello World".

## Interactive composition of gadgets

One of the most interesting and novel aspects of the gadgets is that they can be changed in size and position, in addition to being used, from creation onwards until they are explicitely locked by the user. This is in contrast to most other systems where the user receives his user interface locked, and must "take it or leave it". A significant part of a user's time can be spent organizing the existing user interface or building a new one. This can be compared to the user adjusting his private text tools in the classic Oberon system.
This chapter explains how interactive composition of gadgets is done at run-time. Creating a new interface or changing an interface does not necessarily require programming.

### A simple composition exercise

Try this simple example of interface composition. A step-by-step execution of the following instructions will lead you to create a simple compiler interface panel.

#### Creating a panel

* Create a new, empty panel: Desktops.OpenDoc (PanelDocs.NewDoc).
* Open the Gadgets.Panel: Desktops.OpenDoc Gadgets.Panel.
* Place the caret in the newly created panel and insert a button by clicking on "Button" in the "View" list in the Gadgets.Panel.
* Click on the button a few times, see how it works.

#### Adapting the panel

* Open the inspector by clicking on the [Columbus] button in the Gadgets.Panel.
* Select the new button with the right mouse key.
* Hit the [Inspect] button of the inspector.
* Change the "Caption" text field to Compile.
* Type Compiler.Compile * in the "Cmd" text field.
* Check the "Popout" check box.
* Hit the [Apply] button. Note that the button's caption has changed.
* Deselect the button by hitting the Esc key or by selecting the button with the right key again.
* Open a text viewer with an Oberon source text (any *.Mod file).
* Mark the viewer.
* Hit the [Compile] button to start the compilation.

#### Storing the finalized panel and using it

* Place the caret into the name plate and give the panel a name by typing "My.Panel".
* Store the panel by clicking on the "Store" button in the menu bar (of the panel). Your work is now saved and ready for repeated use.
* Close the panel by clicking on the [Close] button in the menu bar.
* Re-open the panel to use it Desktops.OpenDoc My.Panel.

### A gadgets composition tool

To help you to compose new user interfaces or modify existing ones we are providing the Gadgets.Panel. Behind the scene it uses a set of Gadgets module commands which have been reviewed earlier. Do not forget, these commands can also be executed directly in text in the usual Oberon manner.
The two lists contain the standard set of visual and model gadgets. Note in passing that 'View' is briefer than 'visual gadget' and 'Model' more concise than 'model gadget'. Also for the user's convenience, the list entries are aliases of the real New procedure names. Clicking on one of the entries in the View list inserts a gadget of that type at the caret position. Clicking on an entry in the Model list links a model gadget of that type to the selected gadget or gadgets. The [Recall] button recalls the last deleted panel (Note: it only works for a panel gadget). The [Columbus] button opens a fresh Columbus panel, and the buttons [Back] and [Front] change the display priority of the selected gadgets. By display priority is meant which gadgets overlap others in a panel. By default, new gadgets are always inserted in front of the gadgets already located in a container, and keep their current priority until it is explicitly changed. One exception is the document gadget; these pop to the front when they are focused. If you want to bring a gadget to the front of the container, the consume interclick combination can be used as a short cut. Notice however that the new consume position is the same container as before, otherwise the gadget may change containers unexpectedly.
The [Deep Copy] button controls the execution of a Gadgets.Copy command.
The Align Menu panel allows you to control the alignment of the selected gadgets:
Alignment normally takes place relative to some imaginary line. For example, Left alignment means that all selected gadgets should be lined up on their left edges, the reference line being the the left-most gadget of the selection.

#### Aliases

To remember all New procedures can be quite difficult. Gadgets includes an aliasing feature which allows you to use shorter names for New procedures. The [Aliases] section in the registry (_OBERON.INI) determines these aliases. The complete list of aliases currently defined can be displayed in the system log with the following command: System.Get Aliases
Each alias appears once in this section on a text line with the following format:
    AliasName = M.P
where AliasName identifies an alias for the New procedure M.P. It is now possible to use the following much shorter command to create a Model-View pair, as in this example:
    Gadgets.Insert Button Boolean ~
Aliasing is only available with the commands "Gadgets.Insert" and "Gadgets.Link".
To modify an alias, use the command: System.Set Aliases AliasName := M.P ~

## What's next?

Learn how to manipulate gadgets from within Oberon programs in Using Gadgets from within Oberon.
If you had liked to develop your own Gadgets learn all about it in Programming new Gadgets.

## Index

A
activator macro # aliases attributes
B
Boolean Button
C
Calendar Caption CheckBox Circle Clock Cmd attribute color attribute ColorPicker Complex composition tool concatenation ConsumeCmd attribute CurrentDirectory CurrentLoad
D
deep copy DigitalClock
E
RembrandtFrame EventTimer
F
Finder
G
gadget composition gadget instance Gadgets.Change Gadgets.ChangeAttr Gadgets.Copy Gadgets.Insert Gadgets.Insert Gadgets.Link Gadgets.Set Gen attribute generator grid snap attribute GUI
I
Icon Iconizer initiator macro ! Integer
L
Line List locked attribute lookup macro &
M
macro MemoryUsed Model-View
N
Name attribute NamePlate Navigator New procedure NoteBook
O
Organizer Outline
P
Panel PanelDoc Picture processor macros {, }, | ProgressMeter
R
Real Rectangle3D Rectangle Reference RefFrame RembrandtDoc
S
Scope ScrollView Selection macro ^ SetFrame Set shallow copy Sisiphus Slider Spline String
T
TextDoc TextField TextGadget TextHyperlink TextNote TextStyle Text TimeStamp
U
user interfaces
V
View
Revised, afi 26 Nov 1996 Installed on 30 05 1997