# Friendlier interaction

## Contents

- Introduction
- Menus
- Dialogs

- Lines you can use in dialogs
- Other dialog information

- Toolbars

- Toolbar.oph
- Typical Toolbar.opo usage

- Giving information

## Introduction

Everyday OPL programs can use the same graphical interface seen throughout the system:

- Menus offer lists of options for you to choose from. You can also select these options with shortcut keys like Ctrl+A, Ctrl+B etc.
- Dialogs let a program ask for all kinds of information numbers, filenames, dates and times etc. in one go.
- Screen messages such as ‘Busy’ are available.

Menu keywords begin with an `M`, and dialog keywords with a `D`. In this manual a lower case is used for these letters for example, `mINIT` and `dEDIT` but you can type them using upper or lower case letters.

## Menus

Section Contents

- Defining the menus
- Menu flags
- Displaying the menus
- Problems with menus
- A menu example

Menus provide a simple way for any reasonably complex OPL program to let you choose from its various options.

To display menus in OPL generally takes three basic steps:

- Use the `mINIT` command. This prepares OPL for new menus.
- Use the `mCARD` and `mCASC` commands to define each menu.
- Use the `MENU` function to display the menus.

You use the displayed menus like any others on the system. Use the arrow keys or the pen to move around the menus. Tap an option, press Enter when it is selected, or press the option’s shortcut key to use it, or press Esc or Menu again to cancel the menus without making a choice. In either case, the menus are removed, the screen redrawn as it was, and `MENU` returns a value to indicate the selection made.

#### Defining the menus

The first argument to `mCARD` is the name of the menu. This will appear at the top of the menu; the names of all of the menus form a bar across the top of the screen.

Any number of options on the menu may be defined, each specified by two arguments. If there are more items than can be displayed on the screen at once, then the menu is displayed with a scroll bar. It is recommended that the number of menu items on a menu does not exceed the maximum number displayable at once on the screen of the target device; keeping the number of menu items small means that the user can select the menu item without having to scroll the menu.

The first argument in a menu item pair is the option name, and the second is the keycode for a shortcut key. This specifies a key which when pressed together with the Ctrl key should select the option. (Your program must still handle shortcut keys which are pressed without using the menu.) It is easiest to specify the shortcut key with `%` e.g. `%a` gives the value for `a`.

If an upper case character is used for the shortcut key keycode, the Shift key must be pressed as well to select the option; this will appear as ‘Shift+Ctrl+A’ in the menu. If you supply a keycode for a lower case character, the option is selected only without the Shift key pressed. Both upper and lower case keycodes for the same character can be used in the same menu (or set of menus). This feature may be used to increase the total number of shortcut keys available, and is also commonly used for related menu options e.g. `%m` might be used for zooming to a larger font and `%M` for zooming to a smaller font (as in the built-in applications).

For example,

        mCARD "Comms","Setup",%s,"Transfer",%t

defines a menu with the title `Comms`. When you move to this menu, you’ll see it has the two options `Setup` and `Transfer`, with shortcut keys Ctrl+S and Ctrl+T respectively (and no Shift key required). On the other hand,

        mCARD "Comms","Setup",%S,"Transfer",%T

would give these options the shortcut keys Shift+Ctrl+S and Shift+Ctrl+T.

The options on a large menu may be divided into logical groups (as seen in many of the menus for the built-in applications) by displaying a line under the final option in a group. To do this, you must pass the negative value corresponding to the shortcut key keycode for the final option in the group. For example, `-%A` specifies shortcut key Shift+Ctrl+A and displays a grey line under the associated option in the menu.

Each subsequent `mCARD` defines the next menu to the right. A large OPL application might use `mCARD` like this:

        mCARD "File","New",%n,"Open",%o,"Save",%s
        mCARD "Edit","Cut",%x,"Copy",%c,"Paste",-%v,"Eval",%e
        mCARD "Search","First",%f,"Next",%g,"Previous",%p

#### Menu flags

It is possible to have menu items without shortcuts, by specifying shortcut values between 1 and 32. The value specified is still returned if the item is selected.

Dimming, checkboxes and option buttons are controlled by adding the following values to the shortcut keycode (the constants are found in Const.oph.):

`KMenuDimmed%` | `$1000` | item dimmed
`KMenuCheckBox%` | `$0800` | item has checkbox
`KMenuOptionStart%` | `$0900` | item starts option button list
`KMenuOptionMiddle%` | `$0A00` | item in middle of option button list
`KMenuOptionEnd%` | `$0B00` | item ends option button list
`KMenuSymbolOn%` | `$2000` | symbol on (checkbox/option button)
`KMenuSymbolIndeterminate%` | `$4000` | symbol indeterminate

Dimming a menu item makes it unavailable and on trying to select it, the info print ‘This item is not available’ is automatically displayed. Items with checkboxes have a tick symbol on or off on their left hand side to show whether or not they have been selected. The start, middle and end option buttons are for specifying a group of related items that can be selected exclusively (i.e. if one item is selected then the others are deselected). The number of middle option buttons is variable.

Adding in the `KMenuSymbolOn%` flag sets the tick on a checkbox or the button on an option button item on. The display of ticks and option buttons is automatically changed appropriately when you select one of these items, but your program needs to maintain the state of any checkbox or option button between displays of the menu.

A single menu card can have more than one set of option buttons and checkboxes, but option buttons in a set should be kept together. For speed, OPL does not check the consistency of these items’ specification.

Cascaded items on which less important menu items can be displayed may also be created. The cascade must be defined before use in a menu cascade card. The following is an example of a ‘Bitmap’ cascade under the File menu of a possible OPL drawing application.

        mCASC "Bitmap","Load",%L,"Merge",%M
        mCARD "File","New",%n,"Open",%o,"Save",%s,"Bitmap>",16,"Exit",%e

The trailing `>` character specifies that a previously defined cascade item is to be used in the menu at this point: it is not displayed in the menu item. A cascade has a filled arrow head displayed along side it in the menu. The cascade title in `mCASC` is also used only for identification purposes and is not displayed in the cascade itself. This title needs to be identical to the menu item text apart from the `>`. For efficiency, OPL doesn’t check that a defined cascade has been used in a menu and an unused cascade will simply be ignored.

Shortcut keys used in cascades may be added with the appropriate constant values to enable checkboxes, option buttons and dimming of cascade items.

As is typical for cascade titles, a shortcut value of 16 is used in the example above. This prevents the display or specification of any shortcut key. However, it is possible to define a shortcut key for a cascade title if required, for example to cycle through the options available in a cascade.

#### Displaying the menus

The `MENU` function displays the menus defined by `mINIT` and `mCARD`, and waits for you to select an option. It returns the shortcut key keycode of the option selected, in the case supplied by you, whether you used the pen or Enter or the shortcut key itself to select it. If you supplied a negative shortcut key keycode for an underlined option, it is converted to its positive equivalent.

If you cancel the menus by pressing Esc, MENU returns 0.

##### Displaying a popup menu

A popup menu which appears at a specified point on the screen, may also be defined and drawn using `mPOPUP`. Note that popup menus have only one pane and need not and should not be within the `mINIT`...`MENU` structure. `mPOPUP` returns the value of the shortcut code in the same way as `MENU`. For example,

        mPOPUP(0,0,KMPopupPosTopLeft%,"Continue",%c,"Exit",%e)

The first two arguments specify the position of one corner and the third argument specifies which corner this is. This third argument takes values as follows,

`KMPopupPosTopLeft%` | 0 | Top left.
`KMPopupPosTopRight%` | 1 | Top right.
`KMPopupPosBottomLeft%` | 2 | Bottom left.
`KMPopupPosBottomRight%` | 3 | Bottom right.

Thus, the example above specifies a popup menu with `0,0` as its top left-hand corner and with the items ‘Continue’ and ‘Exit’, with the shortcuts `Ctrl+C` and `Ctrl+E` respectively.

You can add the same values to the shortcut key keycode as those used with `mCARD` and `mCASC` to display dimmed items, checkboxes and option buttons. Note, however, that cascades in popup menus are not supported. For example,

        mPOPUP(0,0,KMPopupPosTopLeft%,"View1",%v OR $2900,"View2",%b OR $A00,"View3",%n OR $B00)

would display a popup menu with option buttons, with the symbol initially set on on the `View1` item (`$2000` is `OR`ed into it as well as `$900`).

#### Problems with menus

You must ensure that you do not use the same shortcut key twice when defining the menus, as OPL does not check for this.

Each menu definition uses some memory, so ‘No system memory’ errors are possible.

Don’t forget to use `mINIT` before you begin defining the menus.

If the menu titles defined by `mCARD` are wider than 40 characters, `MENU` will raise a ‘Too wide’ error.

Shortcut values must be alphabetic character codes or numbers between the values of 1 and 32. Any other values will raise an ‘Invalid arguments’ error.

Note also that a menu is discarded when an item fails to be added successfully. In effect the previous `mINIT` statement is discarded together with any previous `mCARD` statements. This avoids the problem of trying to use a badly constructed menu item.

It is therefore incorrect to ignore `mCARD` errors by having an `ONERR` label around an `mCARD` call (see Error Handling for more details). If you do, the menu is discarded and a ‘Structure fault’ will then be raised on using `mCARD` or `MENU` without first using `mINIT` again.

#### A menu example

This procedure allows you to press the Menu key and see a menu. You might instead be typing a number or some text into the program, or moving around in some way with the arrow keys, and this procedure returns any such keypresses. You could use this procedure instead of a simple `GET` whenever you want to allow a menu to be shown, and its shortcut keys to work.

Each of the options in the menus have a corresponding procedure named `proc` plus the shortcut key letter so for example, the option with shortcut key Ctrl+N (Psion-N) is handled by the procedure `procn`.

This procedure uses the technique of calling procedures by strings, as described in Advanced Topics. For example:

        PROC kget%:
              LOCAL k%,h$(9),a$(5)
              h$="nosciefgd"              REM our shortcut keys
              WHILE 1
                  k%=GET
                  IF k%=$122        REM Menu key
                      mINIT
                      mCARD "File","New",%n,"Open",%o,"Save",%s
                      mCARD "Edit","Copy",%c,"Insert",-%i,"Eval",%e
                      mCARD "Search","First",%f,"Next",%g,"Previous",%d
                      k%=MENU
                      IF k% AND (LOC(h$,CHR$(k%))<>0)    REM MENU CHECK
                          a$="proc"+CHR$(k%)
                          @(a$):       REM procn:, proco:, ...
                      ENDIF            REM END OF MENU CHECK
                  ELSEIF KMOD AND $4   REM shortcut key pressed directly?
                      k%=k%+$40        REM remove Ctrl modification
                      IF LOC(h$,CHR$(k%)) REM DIRECT SHORTCUT KEY CHECK
                          a$="proc"+CHR$(k%)
                          @(a$):       REM procn:, proco:, ...
                      ENDIF     REM END OF DIRECT SHORTCUT KEY CHECK
                  ELSE                 REM some other key
                          RETURN k%
                    ENDIF
              ENDWH
        ENDP

`procn:`, `proco:`, etc. would need to be specified to use this example in practice on any of the machines:

        PROC procn:
              ...
        ENDP

        PROC proco:
              ...
        ENDP
        ...

Note that this procedure allows you to press a shortcut key with or without the Shift key. So Ctrl+Shift+N would be treated the same as Ctrl+N.

Neither LOC nor the `@` operator (for calling procedures by strings) differentiate between upper and lower case. If you have Shifted shortcut keys you will need to compare against two sets of shortcut key lists. For example, with shortcut keys `%A`, `%C`, `%a` and `%d`, you would have upper/lowercase shortcut key lists like `hu$="AC"` and `hl$="ad"`, and the "`MENU CHECK`" section becomes:

        IF k%<=%Z                   REM if upper case shortcut key
            IF LOC(hu$,CHR$(k%))
            a$="procu"+CHR$(k%)
                @(a$):              REM procua:, procuc:, ...
            ENDIF
        ELSE                        REM else lower case shortcut key
            IF LOC(hl$,CHR$(k%))
                a$="procl"+CHR$(k%)
                @(a$)               REM procla:, procld:, ...
            ENDIF
        ENDIF

(This calls procedures `procua:`, `procuc:`, `procla:` and `procld:`). If a shortcut key was pressed directly you cannot tell from `k%` whether Shift was used; so make the same change to the "DIRECT SHORTCUT KEY CHECK" section, but use `IF KMOD AND 2` instead of `IF k%<=%Z`.

## Dialogs

Section Contents

- Lines you can use in dialogs

- Strings, secret strings and filenames
- Choosing one of a list
- Numbers, dates and times
- Results from dDATE
- Displaying text
- Displaying exit keys

- Other dialog information

- Positioning dialogs
- Other dialog features
- Restrictions on dialogs

In OPL, dialogs are constructed in a similar way to menus:

- Use the `dINIT` command to prepare OPL for a new dialog. If you give a string argument to `dINIT` it will be displayed as a title for the dialog. The title will be in a grey box at the top of the dialog.
- Define each line of the dialog, from top to bottom. There are separate commands for each type of item you can use in a dialog for example, `dEDIT` for editing a string, `dDATE` for typing in a date, and so on.
- Use the `DIALOG` function to display the dialog. In general it returns a number indicating the line you were on when you pressed Enter (counting any title line as line 1), or 0 if you pressed Esc.

Use the up and down arrows to move from line to line, and enter the relevant information, as in any other dialog. You can even press Tab to produce vertical lists of options when appropriate.

Each of the commands like `dEDIT` and `dDATE` specifies a variable to take the information you type in. If you press Enter to complete the dialog, the information is saved in those variables. The dialog is then removed, and the screen redrawn as it was.

You can press Esc to abandon the dialog without making any changes to the variables.

If you enter information which is not valid for the particular line of the dialog, you will be asked to enter different information.

Here is a simple example. It assumes a global variable `name$` exists:

        PROC getname:
              dINIT "Who are you?"
              dEDIT name$,"Name:"
              DIALOG
        ENDP

This procedure displays a dialog with `Who are you?` as its top-line title, and an edit box for typing in your name. If you end by pressing Enter, the name you have typed will be saved in `name$`; if you press Esc, `name$` is not changed.

When the dialog is first displayed, the existing contents of `name$` are used as the string to edit.

Note that the dialog is automatically created with a width suitable for the item(s) you defined, and is centred in the screen.

### Lines you can use in dialogs

This section describes the various commands that can define a line of a dialog. In all cases:

- `prompt$` is the string which will appear on the left side of the line.
- `var` denotes an argument which must be a `LOCAL` or `GLOBAL` variable, because it takes the value you enter. Single elements of arrays may also be used, but not field variables or procedure parameters. (`var` is just to show you where you must use a suitable variable you don’t actually type `var`.)

Where appropriate, this variable provides the initial value shown in the dialog.

Although examples are given using each group of commands, you can mix commands of any type to make up your dialog.

More details of the commands may be found in Keyword Reference.

#### Strings, secret strings and filenames

        dEDIT var str$,prompt$,len%

defines a string edit box.

`len%` is an optional argument. If supplied, it gives the width of the edit box (allowing for the widest possible character in the font). The string will scroll inside the edit box, if necessary. If `len%` is not supplied, the edit box is made wide enough for the maximum width `str$` could be. (You may wish to set a suitably small `len%` to stop some dialogs being drawn all the way across the screen)

        dXINPUT var str$,prompt$

defines a secret string edit box, such as for a password. A special symbol will be displayed for each character you type, to preserve the secrecy of the string.

        dFILE var str$,prompt$,f%,Uid1&,Uid2&,Uid3&

defines a filename editor or selector box. `dFILE` automatically has ‘Folder’ and ‘Disk’ selectors on the lines below it. `f%` controls whether you have a file editor or selector in your dialog, and the kind of input allowed. Files selected may also be restricted by UID. See `dFILE` in Keyword Reference for full details of how to do this.

Here is an example dialog using these commands:

        PROC info:
              LOCAL n$(30),pw$(16),f$(255)
              dINIT "Your personal info"
              dEDIT n$,"Name:",15
              dXINPUT pw$,"Password:"
              dFILE f$,"Log file,Folder,Disk",0
              RETURN DIALOG
        ENDP

This procedure returns ‘True’ if Enter was used, indicating that the GLOBAL variables `n$`, `pw$` and `f$` have been updated.

`dEDITMULTI var pData&,p$,widthInChars%,numLines%,maxLen%
`defines a multi-line edit box to go into a dialog. Normally the resulting text would be used in a subsequent dialog, saved to file or printed using the Printer OPX (see About OPXs). The use of this dialog command is more complicated than the others (see Keyword Reference for full details).

#### Choosing one of a list

        dCHOICE var choice%,prompt$,list$

defines a choice list. `list$` should contain the possible choices, separated by commas for example, `"Yes,No"`. The `choice%` variable specifies which choice should initially be shown 1 for the first choice, 2 for the second, and so on.

For example, here is a simple choice dialog:

        PROC dcheck:
              LOCAL c%
              c%=2                              REM default to "View2"
              dINIT "Change View"
              dCHOICE c%,"View:","View1,View2,View3"
              IF DIALOG                   REM returns 0 if cancelled
                    ...                         REM change view
              ENDIF
        ENDP

Extended choice lists may also be defined by using more than one `dCHOICE` statement (see Keyword Reference for full details of how to do this).

        dCHECKBOX chk%,prompt$

creates a checkbox entry. This is similar to a choice list with two items, except that the list is replaced by a checkbox with the tick either on or off. The state of the checkbox is maintained across calls to the dialog. Initially you should set the live variable chk% to 0 to set the tick symbol off and to any other value to set it on. chk% is then automatically set to 0 if the box is unchecked or -1 if it is checked when the dialog is closed.

#### Numbers, dates and times

        dLONG var long&,prompt$,min&,max&

and

        dFLOAT var fp,prompt$,min,max

define edit boxes for long integers and floating-point numbers respectively. Use `dFLOAT` to allow fractions, and `dLONG` to disallow them. `min(&)` and `max(&)` give the minimum and maximum values which are to be allowed. There is no separate command for ordinary integers use `dLONG` with suitable `min&` and `max&` values.

        dDATE var long&,prompt$,min&,max&

and

        dTIME var long&,prompt$,type%,min&,max&

define edit boxes for dates and times. `min&` and `max&` give the minimum and maximum values which are to be allowed.

For `dDATE`, `long&`, `min&` and `max&` are specified in "days since 1/1/1900". The `DAYS` function is useful for converting to "days since 1/1/1900".

For `dTIME`, `long&`, `min&` and `max&` are in "seconds since 00:00". The `DATETOSECS` and `SECSTODATE` functions are useful for converting to and from "seconds since midnight" (they actually use "seconds since 00:00 on 1/1/1970").

`dTIME` also has a `type%` argument. This specifies the type of display required:

0 | absolute time without seconds
1 | absolute time with seconds
2 | duration without seconds
3 | duration with seconds
4 | absolute times in 24 hour clock
8 | time not displaying hours

Constants for these values are defined in Const.oph.

For example, `03:45` is an absolute time, while 3 hours 45 minutes is a duration.

This procedure creates a dialog, using these commands:

        PROC delivery:
              LOCAL d&,t&,num&,wt
              d&=DAYS(DAY,MONTH,YEAR)
              DO
                    t&=secs&:
              UNTIL t&=secs&:
              num&=1 :wt=10
              dINIT "Delivery"
              dLONG num&,"Boxes",1,1000
              dFLOAT wt,"Weight (kg)",0,10000
              dDATE d&,"Date",d&,DAYS(31,12,1999)
              dTIME t&,"Time",0,0,DATETOSECS(1970,1,1,23,59,59)
              IF DIALOG                              REM returns 0 if cancelled
                    ...                               REM rest of code
              ENDIF
        ENDP

        PROC secs&:
              RETURN HOUR*INT(3600)+MINUTE*60
        ENDP

The `secs&:` procedure uses the `HOUR` and `MINUTE` functions, which return the time as kept by the machine. It is called twice to guard against an incorrect result, in the (albeit rare) case where the time ticks past the hour between calling `HOUR` and calling `MINUTE`.

The `INT` function is used in `secs&:` to force OPL to use long integer arithmetic, avoiding the danger of an ‘Overflow’ error.

`d&` and `t&` are set up to give the current date and time when the dialog is first displayed. The value in `d&` is also used as the minimum value for `dDATE`, so that in this example you cannot set a date before the current date.

`DATETOSECS` is used to give the number of seconds representing the time 23:59. The first three arguments, `1970`, `1` and `1`, represent the first day from which `DATETOSECS` begins calculating.

#### Results from dDATE

`dDATE` returns a value as a number of days

To convert this to a date use `DAYSTODATE` which converts a number of days since 1/1/1990, to the corresponding date. See `ref.toc` for full details.

#### Displaying text

        dTEXT prompt$,body$,type%

defines `prompt$` to be displayed on the left side of the line, and `body$` on the right. There is no variable associated with `dTEXT`. If you use a null string (`""`) for `prompt$`, `body$` is displayed across the whole width of the dialog.

`type%` is an optional argument. If specified, it controls the alignment of `body$`:

0 | left align `body$`
1 | right align `body$`
2 | centre `body$`

Note that alignment of `body$` is only supported when `prompt$` is null, with the body being left aligned otherwise.

In addition, you can add any or all of the following three values to `type%`, for these effects:

$200 | draw a line below this item.
$400 | make the prompt (not the body) selectable.
$800 | make this item a text separator

`dTEXT` is not just for displaying information. Since `DIALOG` returns a number indicating the line you were on when you pressed Enter (or 0 if you pressed Esc), you can use `dTEXT` to offer a choice of options, rather like a menu:

        PROC selact:
              dINIT "Select action"
              dTEXT "Add","",$402
              dTEXT "Copy","",$402
              dTEXT "Review","",$402
              dTEXT "Delete","",$402
              RETURN DIALOG
        ENDP

In each case `type%` is `$402` ($400+2). The `$400` makes each prompt selectable, allowing you to move the cursor on to it. Note that only the prompts are selectable. However, the items will be centre aligned in the dialog.

See the Keyword Reference for full details of `dTEXT`.

#### Displaying exit keys

Most dialogs are completed by pressing Enter to confirm the information typed, or Esc to cancel the dialog. These keys are not usually displayed as part of the dialog.

However, some dialogs offer you a simple choice, by showing pictures of the keys you can press. A simple "Are you sure?" dialog might, for example, show the two keys ‘Y’ and ‘N’, and indicate the one you press.

If you want to display a message and offer Enter, Esc and/or Space as the exit keys, you can display the entire dialog with the `ALERT` function.

If you want to use other keys, such as `Y` and `N`, or display the keys below other dialog items such as `dEDIT`, create the dialog as normal and use the `dBUTTONS` command to define the keys.

`ALERT` and `dBUTTONS` are explained in detail in Keyword Reference.

### Other dialog information

#### Positioning dialogs

If a dialog overwrites important information on the screen, you can position it with the `dPOSITION` command. Use `dPOSITION` at any time between `dINIT` and `DIALOG`.

`dPOSITION` uses two integer values. The first specifies the horizontal position, and the second, the vertical. `dPOSITION -1,-1` positions to the top left of the screen; `dPOSITION 1,1` to the bottom right; `dPOSITION 0,0` to the centre, the usual position for dialogs.

`dPOSITION 1,0`, for example, positions to the right-hand edge of the screen, and centres the dialog half way up the screen.

#### Other dialog features

`dINIT` can take a second optional parameter to specify additional dialog features. This may be any ORed combination of the following constants,:

value | effect
1 | buttons positioned on the right rather than at the bottom
2 | no title bar (any title in dINIT is ignored)
4 | use the full screen
8 | don’t allow the dialog box to be dragged
16 | pack the dialog densely (not buttons though)

Constants for these flags are supplied in Const.oph.

It should be noted that dialogs without titles cannot be dragged regardless of the "No drag" setting. Dense packing enables more lines to fit on the screen for larger dialogs.

For example, the following could be used for a large dialog:

        dINIT "Big Dialog",$15

so that the dialog covers the full screen, has buttons (as defined by `dBUTTONS`) on the right and has items densely packed.

#### Restrictions on dialogs

The following general restrictions apply to all dialogs:

- Only one dialog may be in use at a time.
- A dialog must be initialised (`dINIT`), defined (`dEDIT` etc.) and displayed (DIALOG) in the same procedure.
- No error is raised if the dialog is too wide or too long to fit on the screen: it is up to the programmer to ensure the dialog is displayed in a suitable way.

## Toolbars

Section Contents

- Toolbar.oph
- Typical Toolbar.opo usage

- TBarLink:
- TBarColor:
- TBarInit:
- TBarInitC:
- TBarSetTitle:
- TBarButt:
- TBarOffer%:
- TBarLatch:
- TBarShow:
- TBarHide:
- Public Toolbar globals

All OPL programs should use the ROM module `Z:\System\Opl\Toolbar.opo` to create a toolbar window with a title, four buttons and a clock.

The public interface to `Toolbar.opo` is supplied in `Z:\System\Opl\Toolbar.oph` which is reproduced below. The procedures and their usage are then discussed in detail.

### Toolbar.oph

        rem Toolbar.oph
        rem Header file for OPL's toolbar
        rem Copyright (c) 1997-1998 Symbian Ltd. All rights reserved.

        external TBarLink:(appLink$)
        external TBarInit:(title$,scrW%,scrH%)
        external TBarInitC:(title$,scrW%,scrH%,winMode%)
        external TBarInitNonStd:(name$,scrW%,scrH%,width%)
        external TBarSetTitle:(name$)
        external TBarButt:(shortCut$,pos%,text$,state%,bit&,mask&,flags%)
        external TBarOffer%:(winId&,ptrType&,ptrX&,ptrY&)
        external TBarLatch:(comp%)
        external TBarShow:
        external TBarHide:
        external TBarColor:(fgR%,fgG%,fgB%,bgR%,bgG%,bgB%)

        rem The following are global toolbar variables usable by Opl programs
        rem or libraries: usable after toolbar initialisation:
        rem   TbWidth%         the pixel width of the toolbar
        rem   TbVis%           -1 if visible and otherwise 0
        rem   TbMenuSym%       the current 'Show toolbar' menu
        rem                    symbol (to be ORed with shortcut
        rem                    letter)
        rem Flags for toolbar buttons

        const KTbFlgCmdOnPtrDown%=$01

        rem The order and values of the following are significant so don't change without due care

        const KTbFlgLatchStart%=$12            rem start of latchable set
        const KTbFlgLatchMiddle%=$22      rem middle of latchable set
        const KTbFlgLatchEnd%=$32                  rem end of latchable set
        const KTbFlgLatched%=$04                  rem set for current latched item in set

        rem End of Toolbar.oph

### Typical Toolbar.opo usage

Typically a program would use `Toolbar.opo` in the following way:

- `LOADM "Z:\System\Opl\Toolbar.opo"` to load the toolbar module. This module must remain loaded as long as you need to use the toolbar.
- ‘Link’ the toolbar-specific globals into the top-level of your program, using `TBarLink:`
- (Possibly) initialise the toolbar’s title colours using `TBarColor:`.
- Initialise the toolbar, creating an invisible toolbar window with title and clock, using `TBarInit:`( : `TBarInitC:` can be used instead to supply a colour mode for the toolbar).
- Add normal or latchable toolbar buttons to the toolbar, using `TBarButt:`
- Make the toolbar visible, using `TBarShow:`
- Offer all pointer events to the toolbar so that it can call your commands, change the system clock type or display the task list, using `TBarOffer%:`
- Latch a button down to represent the current view when the view changes, using `TBarLatch:`
- Change the toolbar title to the current document name, using `TBarSetTitle:`
- Show and hide the toolbar as appropriate, using `TBarShow:` and `TBarHide:`
- Provide command-handling procedures to be called by `Toolbar.opo` when a toolbar button is pressed.

#### TBarLink:

Usage: `TBarLink:(appLink$)`

TBarLink: provides all toolbar globals required in your application. It has to be called before TBarInit: and from a higher level procedure in your application than the one in which the globals are used.

`appLink$` is the name of the so-called continuation procedure in your main application. TBarLink: calls this procedure, which should then go on to run the rest of your program. This allows the globals declared in TBarLink: to exist until the application exits. `appLink$` must represent a procedure with name and parameters like:

        PROC appContTBarLink:
              REM Continue after ‘linking’ toolbar globals
              myAppInit:            REM run rest of program
              ...
        ENDP

i.e. taking no parameters and with no return-type specification character, so that it can be called using `@(appLink$):`.

#### TBarColor:

Usage: `TBarColor:(foreR%,foreG%,foreB%,backR%,backG%,backB%)`

Within the toolbar, the colours for the title text, title background and the clock border background default to black ($00,$00,$00) for the foreground and white ($ff,$ff,$ff) for the background.

`TBarColor:` sets the RGB values for the foreground colour, and the RGB values for the background colour.

Note: in order to set the colours, the `TBarColor:` procedure should be called before initialising the toolbar with `TBarInit:` or `TBarInitC:` (below).

#### TBarInit:

Usage: `TBarInit:(title$,scrW%,scrH%)`

Called at start of application only, this procedure creates the toolbar window, which guarantees that there will be sufficient memory available to display the toolbar at any subsequent time. The toolbar is made invisible when not shown. This procedure also draws all toolbar components except the buttons.

Note that, for speed, `TBarInit:` turns graphics auto-updating off (using `gUPDATE OFF`). If automatic updating is required, use `gUPDATE ON` after `TBarInit:` returns.

Note also that TBarInit: sets compute mode off (see `SETCOMPUTEMODE:` in `System.opx` — EPOC system functions) allowing the program to run at foreground priority when in foreground. By default OPL programs have compute mode on (i.e. they run at background priority even when in foreground).

Note: The toolbar needs a minimum of 4 greys to display the buttons and clock correctly. You should ensure the mode is at least 2-bit (`KColorDefWin4GrayMode%`) if using `TBarInit`.

- `title$` is the title shown in the toolbar. You should change this to the name of your current file, using `TBarSetTitle:`.
- `scrW%` is the full-screen width (`gWIDTH` at startup).
- `scrH%` is the full-screen height (`gHEIGHT` at startup).

See also `TBarInitC:`, below.

#### TBarInitC:

Usage: `TBarInitC:(title$,scrW%,scrH%,winMode%)`

Initialises the toolbar in colour mode. `TBarInitC:` is based on `TBarInit:` but takes an additional parameter `winMode%` which defines the window mode used to create the toolbar. You should use at least 4 grey mode (`KColorgCreate4GrayMode%`) for the window mode as explained above.

See `gCREATE` for the possible values of `winMode%`.

#### TBarSetTitle:

Usage: `TBarSetTitle:(name$)`

Sets the title in the toolbar.

`name$` is the name of your current file for file-based applications (i.e. applications with the `APP`...`ENDA` construct containing `FLAGS 1`), or the name of your application for non-file applications.

#### TBarButt:

Usage: `TBarButt:(shortcut$,pos%,text$,state%,bit&,mask&,flags%)`

Adds a button to the previously initialised toolbar.

`shortcut$` is the command shortcut for your application, which is used by `Toolbar.opo` to perform the command when a toolbar button is selected. On selecting the toolbar button, `Toolbar.opo` calls your procedure to perform the required command or action. `shortcut$` is case sensitive in the sense that `Toolbar.opo` calls your procedure named:

- `"cmd"+shortcut$+%:` for unshifted, lower-case shortcuts,
- `"cmdS"+shortcut$+%:` for shifted, upper-case shortcuts.

For example, if you have the following two commands that also have associated toolbar buttons:

        mCARD "View","DoXXX",%x,"DoYYY",%Y
        REM shortcuts Ctrl+X,Shift+Ctrl+Y

you would need to provide command-handling procedures:

- `PROC cmdX%:
  REM handle shortcut Ctrl+X (lower case shortcut$="x")`
- `PROC cmdSY%:
  REM handle shortcut Shift+Ctrl+Y (upper case shortcut$="Y")`

and you would create buttons using, e.g.

- `TBarButt:("x",1,"DoXXX",0,XIcon&,XMask&,0)
  REM Button for calling cmdX:`
- `TBarButt:("Y",1,"DoYYY",0,YIcon&,YMask&,0)
  REM Button for calling cmdSY:`

`pos%` is the button position, with `pos%=1` for the top button.

`text$` and `state%` take values as required for gBUTTON.

`bit&` and `mask&` are the button’s icon bitmap and mask, used in in the same way as for gBUTTON. Note that a button is a purely graphical entity and so doesn't own the bitmaps. Therefore the bitmap may not be unloaded while the button is still in use.

`flags%` lets you control how the button is used in two distinct and mutually exclusive ways, as follows:

Two latchable buttons are often used by the built-in applications to indicate the current view. For an example, see the latchable ‘Desk’ and ‘Sci’ buttons in the built-in Calc application.
A set of latchable toolbar buttons can be specified in TBarButt: by setting `flags%` to one of:

- `KTbFlgLatchStart%` for the first button in the latchable set.
- `KTbFlgLatchMiddle%` for any middle buttons (these are optional and not generally used).
- `KTbFlgLatchEnd%` for the last button in the latchable set.

To latch a button down initially to represent the initial setting, OR `KTbFlgLatched%` with one of the above settings. E.g.

        TBarButt:(sh1$,pos%,txt1$,st%,bit1&,msk1&,
                  KTbFlgLatchStart%)
        TBarButt:(sh2$,pos%,txt2$,st%,bit2&,msk2&,
                  KTbFlgLatchEnd% OR TbFlgLatched%)

will latch down the second button in the set initially.

In the toolbar window, the button with `KTbFlgLatchStart%` set must be above the buttons (if any) with `KTbFlgLatchMiddle%` set, and these in turn must be above the button with `KTbFlgLatchEnd%`.

Only one button in a set is ever latched and pressing another button unlatches the one that was previously set. After pressing and releasing a previously unlatched button in a latchable set, `Toolbar.opo` will, as usual, call your command-handling procedure. When the command has succeeded in changing view, this procedure should set the new state of the button by calling `TBarLatch:(comp%)` where `comp%` is the button number to be latched. This will also unlatch any button that was previously latched. The example below shows how a ‘View1’ button press, with ‘v’ as shortcut, should be handled. The other latchable button in this set might be ‘View2’ with shortcut ‘w’:

        PROC cmdV%:
              IF SetView1%:=0         REM if no error
                    TBarLatch:(KView1TbarButton%)
                    REM your CONST KView1TBarButton%
                    CurrentView%=1
              ENDIF
        ENDP

        PROC cmdW%:
              IF SetView2%:=0                     REM if no error
                    TBarLatch:(KView2TbarButton%)
                    REM your const KView2TBarButton%
                    CurrentView%=2
              ENDIF
        ENDP

You should call the same command-procedures when the command is performed via a menu or via a keyboard shortcut. This will ensure that the button is latched as required.

A setting of `flags%` can also be used to specify that your procedure should be called when the toolbar button is tapped (rather than when the button is released, which is the default). The ‘Go to’ button in the Program editor works in this way, displaying the popup list of procedures when the button is touched. To implement this using TBarButt:, pass `flags%=KTbFlgCmdOnPtrDown%` and provide a procedure named:

        "cmdTbDown"+shortcut$+%:

which could provide a popup menu, as follows:

        PROC cmdTbDownC%:
            REM popup next to button, with point specifying
            REM top right corner of popup
            IF mPOPUP(ScrWid%-TbWidth%,97,KMPopupPosTopRight%,
                                       "Cancel",0,"Clear",%c)
                cmdC%:    REM Do the command itself
            ENDIF
        ENDP

In this case the shortcut is not case-sensitive. Note that when this flag is used, the menu command-procedure is not used directly because a popup is not required when the command is invoked via the menu or via a keyboard shortcut.

#### TBarOffer%:

Usage: `TBarOffer%:(winId&,ptrType&,ptrX&,ptrY&)`

Offers a pointer event to the toolbar, returning -1 if used and 0 if not used. If not used, the event is available for use by your application.

It is important to call this procedure whenever you receive a pointer event, even when the event is not in the toolbar window, thus enabling `Toolbar.opo` to release the current button, both visually and otherwise.

TBarOffer%: handles:

- the tapping of the clock to change the type between analog and digital system-wide.
- the tapping of the toolbar title to display the task list.
- the selection toolbar buttons, calling your command procedures.
- drawing of the button in the appropriate state.

As usual, the word ‘pointer’ indicates a pen.

`winId&` is the ID of the window that received the pointer event.

`ptrType&` is pointer event type as returned by `GETEVENT32` (pen up, pen down or drag).

`ptrX&,ptrY&` is co-ordinate of pointer event.

#### TBarLatch:

Usage: `TBarLatch:(button%)`

Latches down a toolbar button, where `button%=1` for the top button in the toolbar. TBarLatch: also unlatches any button in the latchable set that was previously latched. See TBarButt: for further details on latching buttons.

#### TBarShow:

Usage: `TBarShow:`

Makes the toolbar visible. The toolbar must exist before calling this procedure. Use TBarInit: to create an invisible toolbar with no buttons. Use TBarButt: to add buttons.

#### TBarHide:

Usage: `TBarHide:`

Makes the toolbar invisible.

#### Public Toolbar globals

The following toolbar globals, provided by `TBarLink:`, may be used inOPL applications:

- `TbWidth%` is the pixel width of the toolbar. The rest of the screen width is available for the application.
- `TbVis%` is -1 if visible and otherwise 0
- `TbMenuSym%` is the current ‘Show toolbar’ menu symbol to be added to menu shortcut for View|Show toolbar, e.g.

`mCard "View","Show toolbar",%t or TbMenuSym%`

`TbMenuSym%=(KMenuCheckBox% OR KMenuSymbolOn%)` if the Toolbar is visible and

`TbMenuSym%=KMenuCheckBox%` if invisible. The menu item will therefore be a checkbox item, with the check present or not as appropriate.

## Giving information

Section Contents

- Information messages
- ‘Busy’ messages

#### Information messages

`GIPRINT` displays an information message for 2 seconds, in the bottom right corner of the screen. For example, `GIPRINT "Not Found"` displays `Not Found`. If a string is too long for the screen, it will be clipped.

You can add an integer argument to control the corner in which the message appears:

value | corner
0 | top left
1 | bottom left
2 | top right
3 | bottom right

Constants for these corner values are supplied in Const.oph.

For example, `GIPRINT "Who?",0` prints `Who?` in the top left corner.

Only one message can be shown at a time. You can make the message go away for example, if a key has been pressed with `GIPRINT ""`.

#### ‘Busy’ messages

Messages which say a program is temporarily busy, or cannot respond for some reason, are by convention shown in the bottom left corner. The `BUSY` command lets you display your own messages of this sort. Use `BUSY OFF` to remove it.

`BUSY "Paused..."`, for example, displays `Paused...` in the bottom left corner. This remains shown until `BUSY OFF` is used.

You can control the corner used in the same way as for `GIPRINT`.

You can also add a third argument, to specify a delay time (in half seconds) before the message should be shown. Use this to prevent BUSY messages from continually appearing very briefly on the screen.

For example, `BUSY "Wait:",1,4` will display `Wait:` in the bottom left corner after a delay of 2 seconds. As soon as your program becomes responsive to the keyboard, it should use `BUSY OFF`. If this occurs within two seconds of the original `BUSY`, no message is seen.

The maximum string length of a `BUSY` message is 80 characters and an ‘Invalid argument’ error is returned for any value in excess of this.

Only one message can be shown at a time.