[Top] [Contents] [Index] [ ? ]

A `Menu Language' introduction

Abstract
This document describes the M-Language (ML). The M-Language is a notation for describing menu-directed user interfaces which are to be displayed on small LCD-panels (16x4 or 20x4). ML independently describes a) menu hierarchy and b) the contents of each menu line. The menu line contents can be constructed by using many different building blocks, e.g. strings, integer i/o-fields, switches, options, soft functions keys flexible horizontal whitespace and many more. ML was designed to fit the needs for embedded system design. A compiler for ML written in Python generates a block of tagged binary data which is self-containing and can easily be included into ones own embedded application. See section `Introduction' in MEX - The Menu Executor.

Copyright (C) 1997-2004 Hubert Hoegl

Edition 0.9.1 Last change: 2004-05-24

1. Document History  
2. Introduction  
3. Elements of ML  
4. The Portable-Menu-Format  (Portable Menu Format)
5. An example menu specification  


1. Document History

2004-05-24

* Changed float format in mel.txi (added min, max, step fields).


2. Introduction

2.1 Why menus?  
2.2 General concept  
2.3 Some commonly used notions  
2.4 Structure of this document  


2.1 Why menus?

In many cases a hierarchical ordering of information from general to exact description can improve the readability of complex information. The menu-based user interface, which is realized in many past and present computer systems (examples are the Atari Desktop, the DOS SAA user-interface and of course all modern graphical user interfaces as X-Window and MS-Windows) is an example for structured ordering of the interaction between man and computer.

Typical ordinary menu-based user interfaces in general only allow to `trigger' an event by selecting an appropriate menu entry. As a consequence of triggering an event often entry fields pop up on the screen where the user can enter numbers, select options and so on. This is possible because the character space of the screen is in general so large that the user has a consistent view of the human interface, even when there two, three or more input masks are popped up.

Problems arise, when the character space of the visual output device is rather small. Think of LC-displays of size 16x2, 16x4, 20x2 or 20x4 characters. Because the screen is so tiny, it is very important that a complex user interface is designed acccording to some fixed paradigm, so that the user is well-informed about every step in the interaction with the system. In character-limited devices interaction based on menus is even more important than on ordinary screens.

The principal idea presented in this document is to force the integration of the whole user interface into a menu structure. This means that not only the triggering of events is selected in the menu hierarchy, but also processing of possibly dozens of text-, input-, output- and notifier-fields. These elements are tightly integrated into the whole menu structure and thus make it superfluous, to have separate pop up fields for entering variables etc.

The sketch below shows a 16x4 LC-display, to give you an impression of the tinyness of the available character space.

 
 ________________
|................|
|................|
|................|
|................|
+----------------+

A 16x4 LC-display


2.2 General concept

The M-Language is a notation for describing menu-directed user interfaces which are displayed on small LCD-panels (16x4 or 20x4). The menu-tree can be constructed by using many different elements, e.g. strings, integer i/o-fields, switches, options, soft functions keys and many more. Thus ML is especially well suited for embedded system design. A compiler for ML written in Python generates a block of tagged binary data which is self-containing and can easily be incorporated into ones own embedded application. In the sketch below mlc is applied to a menu specification `foo.m'. The binary menu image is generated into file `foo.c'. The interface declarations of the menu variables are contained within `foo.h'.

 
                       mlc      foo.c  
 menu specification --------->   
      (foo.m)                   foo.h  

On an embedded system connected to a LC-display, the binary menu data is `executed' with MEX, the "Menu Executor". MEX has no built in knowledge about a specific menu and is thus a generic piece of code which can easily be ported to other microcontrollers and embedded systems. MEX is fully written in the Ansi-C language, currently available for the 68HC11 and documented in See section `Introduction' in MEX --- The Menu Executor.

A typical case how to use M-language and MEX is depicted in the following sketch. Software for an embedded system consists in this picture of four primary object modules. A multitasker (MT), a system library (SYS) which contains low-level I/O functions, the application itself (APP) and the Menu Executor (MEX). MEX includes the binary menu image (`foo.c'). The application includes the header file generated by MLC (`foo.h'). The menu variables are either accessed directly from the application or via the generic entry-field functions contained in MEX. On leaving an entry-field a user installable callback-handler is called (see arrow `callback').

 
       +----> APP  <--- foo.h
       |      MT     
 callback     SYS
       +----- MEX  <--- foo.c, foo.h


2.3 Some commonly used notions

The M-Language was designed for describing menus to be displayed on small LCDs. To understand the concepts behind, one first has to define some notions, which are often used in this document. Some of the examples below depend on the actual display-algorithms for the menu which are implemented in MEX, so for details see the MEX documentation. See section `Introduction' in MEX -- The Menu Executor.

`menu-line'
A `menu-line' is a single line or row of characters on an LC-display. Depending on the type of the LCD, a line holds in general between 16 and 40 characters. Typical values are 16 or 20. Each line consists of a sequence of fields, or `line-components'.

`menu-line-component (or line-component)'
A line-component is the basic building block of a line. The most primitive and important line-component is an ASCII string. Another one is for example an input field for a two-digit decimal number. The following example shows a menu-line with two line-components. First a string Temp.......... and second a two-digit input/output field, shown by placeholder ##.

 
|Temp..........##|

A line can of course hold more than two line-components. The following example shows four components (string `'T1:'', integer field `##', string `' Time:'' and time-field `##.##').

 
|T1:## Time:##.##|

`menu-table (or menu-struct)'
A menu-table is a sequence of menu-lines. Menu-lines which may be grouped under a special topic, e.g. all temperatures measured by sensors, frequently form a menu-table. The following example shows a menu-table with three menu-lines, showing the temperatures of well known drinks:

 
|T_Beer........##|
|T_Whiskey.....##|
|T_Wodka.......##|

`menu'
A `menu' is the notion for the whole thing: a set of menu-tables which are hierarchically ordered. For this purpose, every menu-line must be given the attribute of either a leaf or a submenu. In the first case, a menu-line is simply a line as described above. In the latter case, a menu line can be opened to access just another menu-table. The accessed menu-table is also frequently given the name sub-menu. Once "jumped" into a sub-menu, it is also possible to go back to the previous position, which is also known as step up to the parent-menu. The example below shows again the well-known temperature table, but now the first line has a sub-menu. This is indicated by the > character. Note that > is not one of the line-components but is placed there by the Menu EXecutor if it recognises a sub-menu. If the submenu has an access password the character P is shown instead of >.

 
|T_Beer.........>|
|T_Whiskey....## |
|T_Wodka......## |

The following lines show a possible sub-menu of menu-line T_Beer. It is displayed after pressing the key which is dedicated for entering submenus.

 
|T_Budweiser...##|
|T_Guinness....##|               
|T_Porter......##|

`menu-variable'
Sometimes in this documentation the notion `menu-variable' is used for a variable which holds the current value of an editable or read-only field. The variable references in the header file emitted by MLC are pointers to menu-variables.


2.4 Structure of this document

The next chapter (see section 3. Elements of ML) first introduces some elementary concepts about ML. Thereafter the three different sections of a ML specification are introduced (menu-descriptor, menu-structs, menu-lines).

The structure of the Portable-Menu-Format (PMF) is featured in chapter (see section 4. The Portable-Menu-Format).

The last chapter contains an example ML specification which uses all of the concepts introduced in this document.


3. Elements of ML

A menu specification in ML (Menu Language) is an ASCII text file with a simple list-based syntax. Currently the full description of a menu may be stored in one and only one file, because there exists no mechanism for including files into others. A ML-specification consists of three sections.

Section one, at the beginning of the specification, is the menu-descriptor, which holds some attributes concerning the appearance of the whole menu.

The next section comprises all menu-tables in the menu to be specified. The menu-tables fully describe the tree structure of the menu. They do not describe the individual outlook of each line. Section two is a sequence of all menu-tables in a tree.

Section three, the last section, is the description of the outlook of every single menu-line. Every menu-line in the whole menu must have a description of it's line-components in this third section.

Keywords of menu-specifications should be all written in lower-case.

3.1 Elementary ML  
3.2 The Menu-Descriptor  
3.3 The Menu-Table  
3.4 The Menu-Line  
3.5 The Menu-Line-Component (LC)  


3.1 Elementary ML

The universal building block of ML is a list. An example of a simple list is the following one:

 
 (keyword  ...)

A list always begins with a ( character and ends with a ) character. The first word after the opening brace is a keyword, which has to be selected according to the context. Note that keywords may contain - characters. The above example contains also some further specification, which is denoted by .... This is also referred to as the tail of the list. In the simplest form this is either a string, an identifier, or a numerical value.

 
 (value    'a string')   # string
 (mnu-id  menu0)        # identifier (no quotes!)
 (delay    13)           # numeric value

In the above example we have three lists with the keywords value, menu-id and delay. The first line has some string data, the second line an identifier data field and the third line has a numeric value. Note also that # is the comment leading character. All characters after # in the current line are ignored by the ML compiler.

The tail of a list is not restricted to those three simple formats but may contain also one or more other lists, as shown in the following example.

 
 (format
    (key-1  ... )
    (key-2  ... )
    (key-3  ... )
 )


3.2 The Menu-Descriptor

Below is an example of the menu-descriptor, which is the first main component of a ML specification. According to the introducing words in (see section 3.1 Elementary ML), it is a list containing some other lists.

 
 (menu-descriptor
     ( menu-id          m0)
     ( author           'H. Hoegl' )
     ( date             '3.1.1997' )
     ( ml-version       '0.1'      )
     ( delay-reset-all  120)
     ( delay-passwd     10)                                 
     ( delay-help       2)                                      
     ( org-var          0x8400 )
 )

The following table is a short description of the different elementary lists one must specify in the menu-descriptor.

`menu-id'
The `menu-id' is the name of the toplevel menu-table (or menu-struct). Note: This is no string.

`author'
Name of the menu author.

`date'
Date when menu specification was written.

`ml-version'
Menu specification is written in this version of ML.

`delay-reset-all'
This value specifies a delay time after which automatically the toplevel menu is displayes. Suppose you stepped into deeply nested submenus. If you don't press a key for delay-reset-all seconds, then the display switches automatically to the toplevel menu-table.

`delay-passwd'
To prevent that the average user has access to a submenu, a menu-line which leads to a submenu may be combined with a password. On entering such a line a password field will pop up where the user can enter a numeric password. If there is no key pressed for delay-passwd seconds, then the password entry field will disappear.

`delay-help'
After delay-help seconds a possibly displayed help text will disappear.

`org-var'
This variable specifies the start of menu variables. See the MLC documentation.


3.3 The Menu-Table

This is the second part of a menu specification. It consists of one or more `menu-struct's' which define the hierarchy of the menu-lines. It is not a description of the actual line contents!

The following code example shows two menu-structs which define two menu-tables. On the first level, there are three lines m1, m2 and m3. Line m1 points to a submenu containing line m21.

The `menu-id' is needed to assign a menu-line with a short identifier which is also needed later when the actual contents of a line are described. Note that there are no qotes around the menu-id although it is not a keyword.

The `menu-parent' denotes the menu-id of the parent line. Note that the `menu-parent' of the topmost menu-table must have the value `nil'.

All lines in a menu-table must be listed with their menu-ids in the `menu-list' and attributed with either `leaf' or `submenu'.

The `menu-title' is an arbitary string which is compiled directly into the binary menu image. The menu executor can use this information freely. The current version of MEX writes this string left-adjusted to the first LCD line which is devoted entirely to status-information. It is recommended that this string reflects the current nesting level in a clear way: For example on should separate short level descriptors by a point as in `TOP.TEMP'.

 
 (menu-struct 
   ( menu-id m0 ) 
   ( menu-parent nil )
   ( menu-title 'TOP' )
   ( menu-list 
        (menu-id m1 submenu)      
        (menu-id m2 leaf)       
        (menu-id m3 leaf)      
   )
 )

 (menu-struct  
   ( menu-id m1 ) 
   ( menu-parent m0 )
   ( menu-title 'TOP.B' )
   ( menu-list 
        (menu-id m21 leaf)       
   )
 )

In principle each line can be attributed as a submenu and submenus may be nested to a reasonable level. The nesting level depends primarily on the chosen menu executor. The current implementation restricts this value due to low memory allocation to three.


3.4 The Menu-Line

The third section of a menu-description are one or more `menu-line' descriptors. In the previous section each menu-line got it's place in the menu hierarchie. Now each line is filled with it's actual line contents.

A menu-line is described by a list containing at least the two sublists menu-id and format. The menu-id must be identical to one of the menu-ids which have already been assigned in the `menu-struct' section.

If a line points to a submenu, the process of entering this submenu can be protected by a third sublist key.

 
 (menu-line 
    (menu-id m1 )
    (format
       ( <line-component> ... )
       ( <line-component> ... )
       ...
       ( <line-component> ... )
   )
   (key '0815')    # optional access key for entering sub-menu
 )


3.5 The Menu-Line-Component (LC)

A line-component is (nearly) the basic building block of a menu-line. Currently ML defines 10 different line-component types. Two of the line components have may appear in different formats: The `integer' field supports 10 different formats and the `float' field 2 different formats.

This section only defines the M-language syntax for line components. It does not tell anything about how the navigation and editing process is done (what keys have to be pressed etc.). Refer to the following document on how to edit writeable fields composed of these line components: See section `Introduction' in MEX - The Menu Executor.

A detailed description of how each line components is translated into header file declarations is given in the MLC documentation.

3.5.1 String  
3.5.2 Integer  
3.5.3 Float  
3.5.4 Counter  
3.5.5 Switchbox  
3.5.6 Options  
3.5.7 Time  
3.5.8 The LC date  
3.5.9 The LC hfill  
3.5.10 The LC trigger  


3.5.1 String

The `string' line component is the most basic one, because virtually in every menu-line a string is the first component. This string may specify the name of an input/output field, or be the name of a submenu and so on.

 
 (string
    (blink    off)
    (value    'T_Beer........')
    (access   ro)
    (update   0)
 ) 

`blink'
The `blink' attribute has to values: either on or off. In the on case the string should blink with a fixed frequency. Note that the attribute values are not strings. There must be no `' surrounding the off or on values.

`value'
The `value' attribute gives the contents of the string.

`access'
This is either ro (read only) or rw (read/write). In the first case (rp) the string is fixed and can not be altered by the user. The character sequence forming the string is simply stored in the menu binary block. In the second case (rw), the string is alterable by the user. Therefore it is necessary to copy the string from the menu binary block to RAM. The rw attribute for strings is currently not supported.

`update'
The attribute update is only of any use when the access attribute is rw. It holds a numeric value specifying the period of time in seconds between two updates of the string value. Maybe in a multitasking environment one task alters the contents of the string, while another task implements the Menu EXecutor. MEX knows when to update the string by the attribute update. Note that the update value 0 denotes an infinitely long period; this means the string is always displayed without an udpate.


3.5.2 Integer

The integer field subsumes 10 different formatting styles. Depending on the style option it allows to display and, if writeable, also to edit either a two-byte or a one-byte integer. In many examples of embedded systems user-interfaces the range of these values is sufficient.

Future enhancements will bring also four-byte integers.

 
 (integer 
    (blink    off)
    (type     dd)     # dd, sdd, ddd, sddd, SDDD, DDD, DDDD, DDDDD,
                      # hh, HHHH
    (access   rw)
    (update   10)
    (default  18)
    (var      'hztemp')
 )

`blink'
See section 3.5.1 String.

`type'
The type attribute determines the format of the integer field. There possible values are given in the following list. The width of the integer field is equal to the number of characters in the format string. Thus dd has a width of two characters. See the table below for a list of all possible formatting options.

`dd'
Size: 1 byte
Range: 0 ... 99

`sdd'
Size: 1 byte
Range: -99 ... +99

`ddd'
Size: 1 byte
Range: 0 ... 255

`sddd'
Size: 1 byte
Range: -128 ... +127

`SDDD'
Size: 2 byte
Range: -999 ... +999

`DDD'
Size: 2 byte
Range: 0 ... 999

`DDDD'
Size: 2 byte
Range: 0 ... 9999

`DDDDD'
Size: 2 byte
Range: 0 ... 65535

`hh'
Size: 1 byte
Range: 0 ... FF

`HHHH'
Size: 2 byte
Range: 0 ... FFFF

`access'
See section 3.5.1 String.
`update'
See section 3.5.1 String.

`default'
This is the default value of the variable, which is shown after initialization.

`var'
This is the variable name, which is used in the header file generated by MLC.


3.5.3 Float

The float field subsumes 2 different formatting styles. Both have one digit behind the point and two or three integer digits. This is only a first attempt to integrate floats into the M-language. Probably other formats will also be necessary.

 
 (float
    (blink    off)
    (type     sii.f)  # sii.f, siii.f 
    (access   rw)
    (update   10)
    (default  +2.4)
    (min      -10.0)
    (max      +10.0)
    (step     0.1)
    (var      flt_var)
 )

The table below only shows the different formatting styles. For the other attributes see for example See section 3.5.2 Integer.

`sii.f'
Size: 4 byte
Range: -99.9 ... +99.9

`siii.f'
Size: 4 byte
Range: -999.9 ... +999.9

Note: Currently only the sii.f format is supported by MLC.


3.5.4 Counter

A `counter' is an integer input/output field, which allows only a fixed number of numerical values. There is a start value from, an end value to and the step size step. All values can be displayed which can be reached by subsequent addition or subtraction of `step' from the default value.

 
  (counter
     (blink    off)
     (from     0)
     (to       10)
     (step     2)
     (default  8)
     (access   rw)
     (update   0)
     (var      'hzcounter')
  )

`blink'
`from'
`to'
`step'
`default'
`access'
`update'
`var'

If for example an input field needs to select among the values 0,2,4,6,8,10 then the best choice for the line-component type would be the `counter' (from = 0, to = 10, step = 2).

A hint for MEX implementations: The input field should not be changeable via the numerical keypad, but only via some cursor keys.


3.5.5 Switchbox

The switchbox is an input/output field that is similar to the switch-arrays used in Printed Connection Board design. An array of switches is shown as a string, where each character has either an `on' and `off' value. If the characters `*' and `.' mean on and off respectively, then the string

 
"*...*..*"

defines a switch array, where the switches 1, 5 and 8 are in the `on'-state, and switches 2,3,4,6 and 7 are in the `off' state.

 
 (switch 
    (blink   off)
    (nswitch 12) 
    (swinfo  'Jan' 'Feb' 'Mar' 'Apr' 'Mai' 'Jun' 'Jul' 'Aug' 
             'Sept' 'Oct' 'Nov' 'Dec')
    (on-char  '*')
    (off-char '.')
    (access   rw)
    (default  '***..**....*')
    (update   0)
    (var      'month_switch') 
 )

`nswitch'
This field defines the number of switches.

`swinfo'
This field defines for every switch a small help string which is displayed when the cursor points to each individual switch.

`on-char'
Character used to denote a `on' switch.

`off-char'
Character used to denote a `off' switch.

`default'
This string is the default value.

`access'
As usual.

`update'
As usual.

`var'
As usual.


3.5.6 Options

The `option' line-component type is useful if an i/o-field may contain a value from a fixed list of alternatives. An easy example are the alternatives `on' and `off'.

 
 (option 
    (blink    off)
    (nopts    2)
    (opts     'on' 'off')
    (default  0)      
    (access   rw)
    (update   0)
    (var      'my_opt')
 )

`nopts'
Number of options or alternatives.

`opts'
All alternatives are given in a list of strings.

`default'
This is the default value after initialization. The range for the default value spans 0 to nopts-1. The example above would have default equal to 0 for 'on', or equal to 1 for 'off'.

`access'
As usual.

`var'
As usual.


3.5.7 Time

The following shows two examples how to specify a time value of type `long' and one of type `short'.

 
 (time 
    (blink   off)
    (type    long)     
    (var     'time_x')
    (access  rw)
    (update  1)
    (default '12:00.00')
 )

 
 (time 
    (blink   off)
    (type    short)     
    (var     'time_y')
    (access  rw)
    (update  60)
    (default '12:00')
 )

Note that the long format consists of three sub-components and the short format of two.


3.5.8 The LC date

 
 (date 
    (blink   off)
    (type    long)     
    (var     'date_x')
    (default '01/04/1997')
    (access  rw)
    (update  0)
 )

 
 (date 
    (blink   off)
    (type    short)    
    (var     'date_y')
    (default '01/04/97')
    (access  rw)
    (update  0)
 )


3.5.9 The LC hfill

The `hfill' line component insert whitespace characters between two other line-comps or between the beginning/ending of a line and a line-comp. It takes one argument which, if greater than zero, specifies the number of whitespace chars to be inserted.

If the argument is zero, than as many whitespaces are inserted so that the whole LCD line (e.g. 16 or 20 chars) is filled. This flexible whitespace field is useful for filling automatically the LCD width given in the display size (--lcd option of mlc.py). Note that currently only a single `(hfill 0)' is allowed within a menu line. With argument greater than zero there may be more than one `hfill's' within one line.

 
 (hfill 2)    # insert two whitespace chars
 (hfill 0)    # flexible `glue' whitespace


3.5.10 The LC trigger

 
 (trigger
    (blink   off)
    (var     'TRIG_X')
 )

This entry field triggers some action. There are no other specifiers as the ones which are shown in the example. Character `X' is the symbol shown for the trigger or push-button. This line component is similar to pressing a push-button or a function key by calling the callback handler for this line-component.


4. The Portable-Menu-Format

PMF is is the compact binary representation of a menu specified in the M-Language. Sometimes this binary menu data is also referred to as "binary menu image". All neccessary information is encapsuled within this image. Brought onto an embedded system, a generic program (the Menu Executor) interprets this image, displays the menu hierarchy on the LC-display and reacts upon keyboard input.

The following sections contain the specification of PMF.

4.1 Notation  
4.2 Overall Structure  
4.3 LDTAGs (line descriptor tag, ldtag)  
4.4 Line Options (line-opts)  
4.5 LCTAGs (line component tag, lctag)  
4.6 LCOs (Line Component Options, line-comp-opts)  


4.1 Notation


4.1.1 Terminal symbols

Terminal symbols are enclosed in braces <..>

 
    <foo:2>[2,0]
      |  |     |
      |  |     +- bits 2,1,0
      |  +------- size in bytes
      +---------- terminal symbol

A sequence of bytes is stored big-endian. Example:

 
  <foo:2>[2:0] is stored as x->|........|.....210| 
                            x points to foo


4.1.2 Nonterminal symbols (without < > braces)

Examples:

 
   foo
   foo-bar


4.1.3 Repetition

 
   { foo }    means zero or more repetitions


4.2 Overall Structure

 
menu ::= 
    menu-table { menu-table }

menu-table ::= 
    <menu-entry-tag:2> menu-head menu-line { menu-line } 

menu-head ::=
    # Offset to first line-descriptor. The offset is at maximum 256.
    # Note that the header length does not include the menu-entry-tag. Add 2 
    # if this is what you want.
    <header-length:1>  

    # Offset to next menu                  
    <next-menu-ofs:2>  

    # Offset to prev menu
    <prev-menu-ofs:2>  

    if <menu-entry-tag:2> == 0: 
        # This is the toplevel menu
 
        # Version numbering 0.1 ... 256.256
        <ml-version:2>           
 
        # Automatically go to topmenu after n sec
        <delay-to-top:1>         
 
        # Make help disappear after n sec
        <delay-clr-help:1>       
 
        # Delay for password entry
        <delay-passwd:1>         

        # Menu name (will be display on the top left corner of the LCD)
        <menu-name-str:n>  
   
menu-line ::= 
    <ldtag:1> line-opts line-comp { line-comp }

line-comp ::= 
    <lctag:1> line-comp-opts

The `<menu-entry-tag:2>[3:0]' contains the menu level, e.g. 0 for the top menu entry, 1 for the first level submenu entry, 2 for the second level submenu entry and so on.

The elements `ldtag', `line-opts', `lctag' and `line-comp-opts' are described in the following sections.


4.3 LDTAGs (line descriptor tag, ldtag)

 
<ldtag:1>[1,0]
    00  : >= 3 lines, not first nor last
    01  : first menu line
    10  : last menu line
    11  : first is equal last line 

<ldtag:1>[3,2]
    00  : no submenu, no parent
    01  : is submenu, no parent
    10  : has parent, no submenu 
    11  : is submenu and has parent

<ldtag:1>[4]
    0   : if submenu, no passwd needed
    1   : if submenu, passwd needed


4.4 Line Options (line-opts)


4.4.1 Line Option Specification


4.4.1.1 No parent, no submenu, any line ('nx')

 
if (<ldtag>[3,0] == 00xx) 
    line-opts ::= <next-ofs:2> <prev-ofs:2>


4.4.1.2 Submenu only, any line ('sx')

 
if (<ldtag>[3,0] == 01xx) 
    line-opts ::= <next-ofs:2> <prev_ofs:2> <dn-menu-OFS:2> 


4.4.1.3 Both parent and submenu, is first line ('bf')

 
if (<ldtag>[3,0] == 11x1) 
    line-opts ::= <next-ofs:2> <up-menu-ofs:2> <dn-menu-OFS:2> 


4.4.1.4 Both parent and submenu, not first line ('bn')

 
if (<ldtag>[3,0] == 11x0) 
    line-opts ::= <next-ofs:2> <prev-ofs:2> <dn-menu-OFS:2> 


4.4.1.5 Only parent, first line ('pf')

 
if (<ldtag>[3,0] == 10x1) 
    line-opts ::= <next-ofs:2> <up-menu-OFS:2> 


4.4.1.6 Only parent, not first line ('pn')

 
if (<ldtag>[3,0] == 10x0) 
    line-opts ::= <next-ofs:2> <prev-ofs:2> 


4.4.1.7 Password needed to enter submenu

 
if (<ldtag>[4] == 1) 
    line-opts ::= ... <passwd-string:n>  

The password is appended to the previous options.


4.4.2 Further comments

a)
The ...-ofs fields count directly from (including) the ldtag-byte.

b)
The <next-ofs:2> field is always present, even in cases where it is not necessary. E.g. if there is only one menu entry or at the last menu line. Should not be inefficient when assuming only a few long menu tables.

c)
Note that uofs and dofs ("OFS") are interpreted as byte distance between menu-entry at toplevel and the submenu wanted. All other offsets "ofs" are interpreted as the byte distance between, e.g. the ldtag and the next ldtag.


4.5 LCTAGs (line component tag, lctag)

 
<lctag:1>[4,0]   data type     mask       range          comment
-----------------------------------------------------------------------
        0x00     uchar          dd        0..99          D = Digit
        0x01     uchar         ddd        0..255
        0x02     char          sdd      -99..+99         S = Sign
        0x03     char          sddd    -128..+127 
        0x04     uint:2        DDD        0..999
        0x05     int:2         SDDD    -999..+999
        0x06     uint:2        DDDD       0..9999
        0x07     uint:2        DDDDD      0..2^16-1
        0x08     uchar           HH       0..FF          Hex 
        0x09     uint:2        HHHH       0..FFFF        Hex
        0x0a     string        "..."      "..."            
        0x0b     <not used>
        0x0c     counter       DD..D      from/to/step
        0x0d     switch        .*..**.    -              max 32 sw
        0x0e     option        "..."      opt1, opt2, ...  
        0x0f     time-long     12:44:13   -
        0x10     time-short    12:44      -
        0x11     float         SII.F      -99.9..+99.9     
        0x12     float         SIII.F    -999.9..+999.9     
        0x13     passwd        "..."      - 
        0x14     date-long     01/01/1997 - 
        0x15     date-short    01/01/97   - 
        0x16     trigger       1 char     -
   0x17-0x1f     not used

 
<lctag:1>[7]  
   0 :   not last component of current line
   1 :   last component of current line

 
<lctag:1>[6]
   0 :   not blink
   1 :   blink

 
<lctag:1>[5]
   0 :   access is read only (better: display only)
   1 :   access is read/write: modifyable via keyboard


4.6 LCOs (Line Component Options, line-comp-opts)

Notes:

1.
In the 'char' and 'uchar' line components below the addr field points to a TWO byte memory location. Only the first byte contains valid data.

2.
The 'Line Component Length' LCL counts the number of bytes used for a specific line-component in the menu binary image. It does *not* include the lctag-byte. All line-component types which have a variable LCL which can not be computed from the line-component data have a leading length byte. This leading length byte does not include the lctag-byte. The LCL is restricted to 256 bytes, which should be enough for most cases. The line-component "string" has a variable length which can be computed from the leading string byte, thus it has not an explicit length byte.

3.
All `<addr:2>' and `<cal_addr:2>' fields below contain the byte offset within a continuous memory region. The start of this region may either be contained in the preprocessor macro `MENU_BASE' (obtained from the menu specification, `org-var') or may be set to an arbitrary allocated memory region in the menu executor.

4.6.1 String  
4.6.2 Integer "dd"  
4.6.3 Integer "ddd"  
4.6.4 Integer "sdd"  
4.6.5 Integer "sddd" (-128..+127)  
4.6.6 Integer "DDD" (0..999)  
4.6.7 Integer "SDDD" (-999..999)  
4.6.8 Integer "DDDD" (0..9999)  
4.6.9 Integer "DDDDD" (0..2^16-1)  
4.6.10 Integer "HH"  
4.6.11 Integer "HHHH"  
4.6.12 Counter  
4.6.13 Switches  
4.6.14 Options  
4.6.15 Time-long  
4.6.16 Time-short  
4.6.17 Float "SII.F"  
4.6.18 Float "SIII.F"  
4.6.19 Password  
4.6.20 Date-long  
4.6.21 Date-short  
4.6.22 Trigger  


4.6.1 String

LCL = variable (explicitly given in the LCO)

 
if (<lctag:1>[4,0] == 0x0a)
    if (<lctag:1>[5] == 0) 
        # constant string   (access=RO)
        <string:n+1>        # n=0..255
    else 
        # variable string   (access=RW)
        <update:1> 
        <string:n+1> 
        <addr:2> 
        <call_addr:2>


4.6.2 Integer "dd"

LCL = 6 (implicitly given in the LCO)

 
if (<lctag:1>[4,0] == 0x00)
    <update:1> 
    <def:1> 
    <addr:2>     
    <call_addr:2>


4.6.3 Integer "ddd"

LCL = 6

 
if (<lctag:1>[4,0] == 0x01)
    <update:1> 
    <def:1> 
    <addr:2>   
    <call_addr:2>


4.6.4 Integer "sdd"

LCL = 6

 
if (<lctag:1>[4,0] == 0x02)
    <update:1> 
    <def:1> 
    <addr:2>  
    <call_addr:2>


4.6.5 Integer "sddd" (-128..+127)

LCL = 6

 
if (<lctag:1>[4,0] == 0x03)
    <update:1> 
    <def:1> 
    <addr:2>   
    <call_addr:2>


4.6.6 Integer "DDD" (0..999)

LCL = 7

 
if (<lctag:1>[4,0] == 0x04)
    <update:1> 
    <def:2> 
    <addr:2>  
    <call_addr:2>


4.6.7 Integer "SDDD" (-999..999)

LCL = 7

 
if (<lctag:1>[4,0] == 0x05)
    <update:1> 
    <def:2> 
    <addr:2>   
    <call_addr:2>


4.6.8 Integer "DDDD" (0..9999)

LCL = 7

 
if (<lctag:1>[4,0] == 0x06)
    <update:1> 
    <def:2> 
    <addr:2> 
    <call_addr:2>


4.6.9 Integer "DDDDD" (0..2^16-1)

LCL = 7

 
if (<lctag:1>[4,0] == 0x07)
    <update:1> 
    <def:2> 
    <addr:2> 
    <call_addr:2>


4.6.10 Integer "HH"

LCL = 6

 
if (<lctag:1>[4,0] == 0x08)
    <update:1> 
    <def:1> 
    <addr:2>  
    <call_addr:2>


4.6.11 Integer "HHHH"

LCL = 7

 
if (<lctag:1>[4,0] == 0x09)
    <update:1> 
    <def:2> 
    <addr:2> 
    <call_addr:2>


4.6.12 Counter

LCL = 14

Note: `from' and `to' are interpreted as signed numbers!

 
if (<lctag:1>[4,0] == 0x0c)
    <upd:1> 
    <field-width:1> 
    <from:2> 
    <to:2> 
    <step:2> 
    <def:2> 
    <addr:2> 
    <call_addr:2>    # always present


4.6.13 Switches

LCL = variable

 
if (<lctag:1>[4,0] == 0x0d)
    <length:1>      
    <upd:1>
    <nswitch:1>     # 1...32 switches  (4 byte)                    
    <on-char:1>        
    <off-char:1>
    <def:4>         # default mask
    <addr:2>        # address of mask 
    <call_addr:2>   # address of RW handler 
    <string:n+1>    # help string
    ...
    <string:n+1>    # help string


4.6.14 Options

LCL = variable

 
  if (<lctag:1>[4,0] == 0x0e)
    <length:1>      
    <upd:1>
    <nopts:1> 
    <width:1> 
    <def:1> 
    <addr:2>
    <call_addr:2>
    <string:n+1>    # list of option strings
    ... 
    <string:n+1>

The current option index is stored in an unsigned char, to which `addr' points. Thus there is a maximum of 256 different options.


4.6.15 Time-long

LCL = 8

 
if (<lctag:1>[4,0] == 0x0f)
    <upd:1> 
    <addr:2> 
    <call_addr:2>
    <def:3>        


4.6.16 Time-short

LCL = 7

 
if (<lctag:1>[4,0] == 0x10)
    <upd:1> 
    <addr:2> 
    <call_addr:2>
    <def:2>    


4.6.17 Float "SII.F"

[changed 2004-05-24]

LCL = 21

 
if (<lctag:1>[4,0] == 0x11)
    <update:1>
    <default:4>
    <min:4>   ; float
    <max:4>   ; float
    <step:4>  ; float
    <addr:2> 
    <call_addr:2>


4.6.18 Float "SIII.F"

LCL = 9

 
if (<lctag:1>[4,0] == 0x12)
    <update:1>
    <default:4>
    <addr:2> 
    <call_addr:2>


4.6.19 Password

LCL = variable

 
if (<lctag:1>[4,0] == 0x13)
    <length:1> 
    <passwd-string:n+1>                 
    <call_addr:2>

Note: Don't mix the password line component with the submenu access key. They have different meanings. The submenu access key is part of the line options following the line descriptor tag.


4.6.20 Date-long

LCL = 9

 
if (<lctag:1>[4,0] == 0x14)
    <update:1> 
    <addr:2> 
    <call_addr:2>
    <def:4>                      


4.6.21 Date-short

LCL = 8

 
if (<lctag:1>[4,0] == 0x15)
    <update:1> 
    <addr:2> 
    <call_addr:2>
    <def:3>                


4.6.22 Trigger

LCL = 2

 
if (<lctag:1>[4,0] == 0x16)
    <call_addr:2>


5. An example menu specification

 
 # -- menu1.m --

 # H. Hoegl, 3.1.1997
 # Menu description example using ML (Menu Language)

 # tests following component types:
 #    integer, string, counter, time, date


 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 # menu structure
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 (menu-descriptor 
    ( menu-id m0)

    ( author      'H. Hoegl' )
    ( date        '3.1.1997' )
    ( ml-version  '0.1'      )

    # Some constants for managing the display (timescale seconds).

    # two minutes and we'll be back at root menu.
    ( delay-reset-all  120)  
                            
    # show as long the passwd entry field after a try to step into a  
    # subdir. Value 0 means 'show always'.                            
    ( delay-passwd 10)                                   
 
    # a help text is displayed for this period of time. Value 0 means 
    # 'show until help key was pressed a 2nd time'. Maybe scrolling should 
    # be allowed. Then help text disappears this time delay after last
    # scrolling action.
    ( delay-help 2)                                      

    # Start address for menu variables. All vars are stored sequentially
    # beginning at the start address.
    ( org-var  0x7000 )

 )



 (menu-struct 
    ( menu-id m0 ) 
    ( menu-parent nil )
    ( menu-title 'MOPS-O-MAT' )
    ( menu-list 
         (menu-id m1 submenu)      
         (menu-id m2 leaf)       
         (menu-id m3 submenu)      
         (menu-id m4 leaf)      
         (menu-id m5 leaf)      
         (menu-id m6 leaf)      
    )
 )




 (menu-struct  
    ( menu-id m1 ) 
    ( menu-parent m0 )
    ( menu-title 'TOP.B' )
    ( menu-list 
         (menu-id m21 leaf)       
    )
 )


 (menu-struct  
    ( menu-id m3 ) 
    ( menu-parent m0 )
    ( menu-title 'TOP.C' )
    ( menu-list 
         (menu-id m31 leaf)       
         (menu-id m32 leaf)      
         (menu-id m33 leaf)      
         (menu-id m34 submenu)      
    )
 )


 (menu-struct  
    ( menu-id m34 ) 
    ( menu-parent m3 )
    ( menu-title 'TOP.C.A' )
    ( menu-list 
         (menu-id m40 leaf)       
    )
 )



 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 # modelling menu lines
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



 (menu-line 
    (menu-id m1 )
    (format
          (string 
           (blink    off)
           (value    't_h2o.... ')
           (access   ro)
           (update   0)
        ) 
          (counter
           (blink    off)
           (from     0)
             (to       12)
             (step     2)
           (default  4)
           (access   rw)
           (update   3)
             (var      'hztemp1')
        )
    )
 )





 (menu-line 
    (menu-id m2 )
    (format 
       (string 
           (blink    off)
           (value    'int: ')
           (access   ro)
             (update   0)
       )
       (integer 
           (blink    off)
           (type     dd)     
             (access   ro)
           (update   10)
           (default  18)
             (var      'hztemp')
       )
    )
 )



 (menu-line 
    (menu-id m3 )
    (format 
       (string 
           (blink    off)
           (value    'line 3... ')
           (access   ro)
             (update   0)
       )
       (counter
           (blink    off)
           (from     -10)
             (to       10)
           (step     2)
           (default  8)
           (access   rw)
           (update   0)
             (var      'hzcounter_0')
       )
    )
 )


 (menu-line 
    (menu-id m4 )
    (format
          (string 
           (blink    off)
           (value    'c1:')
           (access   ro)
             (update   0)
          )
        (counter
              (blink    off)
              (from    -10)
              (to       2000)
              (step     1)
              (default  19)
              (access   rw)
              (update   0)
              (var      'hzcounter_1')
        )
          (string 
           (blink    off)
           (value    ' c2:')
           (access   ro)
             (update   0)
          )
        (counter
              (blink    off)
              (from     40)
              (to       80)
              (step     5)
              (default  40)
              (access   rw)
              (update   0)
              (var      'hzcounter_2')
        )
    )
 )


 (menu-line 
    (menu-id m5 )
    (format
          (string 
           (blink    off)
           (value    'Time: ')
           (access   ro)
           (update   0)
          )
          (time
           (blink    off)
           (type     short)     
           (access   rw)
           (update   3)
           (default  '20:15')
           (var      'timer_b')
        )
    )
 )


 (menu-line 
    (menu-id m6 )
    (format
          (string 
           (blink    off)
           (value    '1: ')
           (access   ro)
             (update   0)
          )
          (date
           (blink    off)
           (type     short)     
             (access   rw)
           (update   3)
           (default  '12/04/61')
             (var      'date_a')
        )
    )
 )


 (menu-line 
    (menu-id m21 )
    (format 
       (string 
           (blink    off)
           (value    'abc...')
           (access   ro)
             (update   0)
       )
    )
 )



 (menu-line 
    (menu-id m31 )
    (format
       (string 
           (blink    off)
           (value    'fubar')
           (access   ro)
             (update   0)
       )
    )
 )


 (menu-line 
    (menu-id m32 )
    (format
       (string 
           (blink    off)
           (value    'foo')
           (access   ro)
             (update   0)
       )
    )
 )


 (menu-line 
    (menu-id m33 )
    (format
          (string 
              (blink    off)
              (value    'string 5')
              (access   ro)
              (update   0)
          ) 
    )
 )



 (menu-line 
    (menu-id m34 )
    (format
          (string 
              (blink    off)
              (value    'string 4')
              (access   ro)
              (update   0)
          ) 
    )
 )


 (menu-line 
    (menu-id m40 )
    (format
          (string 
              (blink    off)
              (value    'core dumped...')
              (access   ro)
              (update   0)
          ) 
    )
 )


[Top] [Contents] [Index] [ ? ]

Table of Contents


[Top] [Contents] [Index] [ ? ]

Short Table of Contents

1. Document History
2. Introduction
3. Elements of ML
4. The Portable-Menu-Format
5. An example menu specification

[Top] [Contents] [Index] [ ? ]

About this document

This document was generated by Hubert Hoegl on May, 24 2004 using texi2html

The buttons in the navigation panels have the following meaning:

Button Name Go to From 1.2.3 go to
[ < ] Back previous section in reading order 1.2.2
[ > ] Forward next section in reading order 1.2.4
[ << ] FastBack previous or up-and-previous section 1.1
[ Up ] Up up section 1.2
[ >> ] FastForward next or up-and-next section 1.3
[Top] Top cover (top) of document  
[Contents] Contents table of contents  
[Index] Index concept index  
[ ? ] About this page  

where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:

This document was generated by Hubert Hoegl on May, 24 2004 using texi2html