PowerView Embedded GUI system

The PowerView embedded GUI system in the Examples\PowerView directory is derived from several years work with industrial displays. The code is designed to be a reasonable compromise between code space, RAM space and facilities. It is not intended as a replacement for a desktop windowing system.

Drivers are provided for several CPU and LCD panel combinations:

The supplied example code in this manual is for the MPE ARM Development Kit, which uses a Sharp LH77790B ARM with an on-chip LCD controller. To compile the code, set up the text macro GuiDir to point to the PowerView folder, and compile the following files:


include %GuiDir%\FontDefs             \ font structs and data
include %GuiDir%\Font\Font12x8x2      \ 12x8 font
include %GuiDir%\Font\Font16x12x2     \ 16x12 font
include %GuiDir%\Font\Font16x16x2     \ 16x16 font
include %GuiDir%\Drivers\LcdQvgaMono5 \ hardware specific driver
include %GuiDir%\GUI                  \ GUI kernel
include %GuiDir%\DemoMono2            \ GUI demo

Configuration

The configuration equates below are only used if they have not already been defined, e.g. in your control file.

1 equ GUIdiags? \ -- n
Set this non-zero to compile some diagnostics.

Tools

: c+!           \ n c-addr --
Add n to the byte at c-addr.

: addchar       \ char string --
Add the character to the end of the counted string.

: append        \ c-addr u $dest --
Add the string described by C-ADDR U to the counted string at $DEST. The strings must not overlap.

: -leading      \ caddr len -- caddr' len'
Ignore leading spaces.

: split         \ addr len char -- laddr llen raddr rlen
Extract a substring at the start of addr/len, returning the string remaining after char and the substring addr/sslen which does not include char. If the string does not contain the character, raddr is addr+len and rlen=0.

Unpacking rectangles

In the GUI system, much use is made of rectangles stored in /Rect structures.

struct /Rect    \ -- size
Rectangle structure.

  int r.x               \ x,y position
  int r.y
  int r.w               \ width
  int r.h               \ height
end-struct

: r>coords      \ rect -- x y w h
Return the coordinates of the given rectangle.

Buttons

: centred       \ rect len -- xleft ytop
Given the length of a string and a rectangle in which to display it, form the x/y start point at which the string should be displayed.

: button        \ caddr len rect --
Display a button - a rectangle with centred text.

: 3D-Button     \ caddr len rect --
Display a 3D effect button. This is achieved by varying the colour of the borders, and so is specific to the display hardware.

Text formatting

: nInter        \ c-addr u -- n
Gets number of interword spaces in a string by counting the number of spaces in the string.

#40 buffer: jText       \ -- addr
Temporary buffer that holds justified text.

: AddNext       \ caddr len -- caddr' len'
Extract the leftmost string (delimited by a space), and add it to the justified text buffer, returning the string to the right of the first space.

: AddSpaces     \ n --
Add n spaces to the justified text buffer.

: FindLine      \ caddr1 len1 n -- caddr2 len2
Return a line of maximum length n containing complete words of text.

: BuildJustified        \ caddr len w -- caddr' w
Build a justified line of text of size w in a buffer, and return the buffer address and length.

: ShowJLines    \ x y caddr len w --
Display a block of justified text starting at pixel position x,y in a width of w pixels. The text must contain single spaces as word separators. N.B. No word may be longer than w/fontwidth-1 characters, otherwise the display may hang.

Drawing the GUI

The drawing routines for the GUI are all given the item's data structure.

struct /GUIdef  \ -- len
All elements of the GUI are controlled by this data structure which is usually built at compile time.

\ -- Chains
  int pNext             \ points to next child
  int pParent           \ points to parent
  int pChild            \ points to first child
\ -- Processing
  int idSel             \ user specified identifier
  int xtDraw            \ holds xt of routine that draws this
  int xtAction          \ holds xt of associated action, e.g. when pressed
\ -- Rectangle, text and font
  /Rect field Grect     \ holds X Y W H
  int ppFont            \ points to a pointer to the required font
  int pText             \ Points to counted string text for buttons etc
\ -- Type specific data
  0 field Gprivate      \ Item specific data follows.
\ MENU only
  int ppMenuFont        \ points to pointer to the font for the MENU
  4 -
end-struct

The following two words are compiled if the equate GUIdiags? is non-zero.

: .GuiItem      \ item --
Display the data structure for a GUI element.

: .GuiChain     \ item --
Display the chain of data structures for a compund GUI structure such as a menu.

: SetItemFont   \ item -- font
Return the current font and set the font for this item.

: DrawButton    \ item --
Draw a 3D button with centred text.

: DrawCtext     \ item --
Draw text centred in the rectangle.

: DrawLtext     \ item --
Draw text left justified in the rectangle.

: DrawRtext     \ item --
Draw text right justified in the rectangle.

: DrawJText     \ item --
Draw justified text in the rectangular area.

: DrawBox       \ item --
Draw a box (rectangle).

: DrawTextBox   \ item --
Draw a box filled with justified text.

: DrawImage     \ item --
Display an image. The image data follows the item.

: DrawPicture   \ item --
Display an image. The address of the image data follows the item.

: DrawMenuFrame \ item --
Draw the menu frame and caption.

: DrawMenu      \ item --
Draw a menu and its first level children.

Defer ActOnMenu \ id item --
Perform the action specified by ID (usually a GUI item structure or an x,y pair from a touch screen) for the given menu. The default action is 2DROP. Define your own action for this word. It should walk the menu chain, select which item if any that ID refers to, and execute the selected action word in the item data structure.

Defining a GUI

variable LastItem       \ -- addr
Holds the address of the last item defined

variable CurrItem       \ -- addr
Holds the address of the item being defined

variable ParentItem     \ -- addr
Holds the address of the item's parent

create Null$  0 ,       \ -- addr
A null string which may be used as a counted string or a zero-terminated string.

Please note that the following words are only available during cross-compilation. If you need them on the target, just make copies outside the INTERPRETER ... TARGET structure.

: pNext,        \ -- ; lay next pointer
INTERPRETER: lay the pointer to the next item. The list is anchored at the parent's pChild field.

: parent,       \ -- ; lay pointer to parent
INTERPRETER: Lay the pointer to the parent item.

: child,        \ -- ; lay pointer to children
INTERPRETER: Lay a pointer to any children.

: +ParX         \ x -- x'
INTERPRETER: Add the parent's x offset.

: +ParY         \ y -- y'
INTERPRETER: Add the parent's Y offset.

: ident,        \ --
Lay default user identifier.

: Rect,         \ x y w h -- ; lay rectangle
INTERPRETER: Add the parent's x offset.

: GuiDef,       \ x y w h xt --
INTERPRETER: Lay down the basic /GuiDef structure using the given rectangle data and the xt of the word that draws the item.

: text",        \ -- ; followed by delimited text
INTERPRETER: Lay down the following text string and set the pText field in the current item being defined.

GUI application words

These words are used to generate menus which can contain buttons, text, boxes and graphics. The menu is displayed by the word DrawMenu ( menu -- ) and actions can be performed by the user-defined action of ActOnMenu ( x menu -- ).

With the exception of MENU the application words construct data structures without names. If you want to refer to a specific item, use

create <name>

before the item. The data structures are held in linked lists, so having additional code and data between items is permitted.

: MENU          \ x y w h "<name>" -- par last ; -- addr
INTERPRETER: Use in the form:

 x y w h MENU <name>

to start a MENU ... END-MENU definition. When data structure. The positions of the internal elements are relative to the top left hand corner of the menu. A title bar is generated only if a caption is defined (see below).

: CAPTION"      \ -- ; followed by delimited text
INTERPRETER: Use in the form:

 CAPTION" <text>"

to add a caption and title bar to a menu.

: MENUFONT      \ fonttable --
INTERPRETER: Use in the form:

 <fonttable> MENUFONT

to define the default font used by all items within a menu. If no font is set, the current font will be used.

: FONT          \ fonttable --
INTERPRETER: Use in the form:

 <fonttable> FONT

to define the font used by an item. The defined font will only apply to that item. If no font is set, the current font will be used.

INTERPRETER: Ends a MENU ... END-MENU definition.

: SetID         \ x --
Give the current item an identifier that can be used to select the item. This may be a character or any other unique identifier for this menu.

: BUTTON"       \ x y w h <"text"> --
INTERPRETER: Use in the form below to create a button:

 x y w h BUTTON" <text>"

: RUNS          \  -- ; name follows inline
INTERPRETER: Use in the form:

 RUNS <name>

to set the xtAction field of the item being defined.

: CTEXT"        \ x y w h <"text"> --
INTERPRETER: Use in the form:

 x y w h CTEXT" <text>"

to produce text centred in the given rectangle.

: LTEXT"        \ x y w h <"text"> --
INTERPRETER: Use in the form:

 x y w h LTEXT" <text>"

to produce text left justified in the given rectangle.

: RTEXT"        \ x y w h <"text"> --
INTERPRETER: Use in the form:

 x y w h RTEXT" <text>"

to produce text right justified in the given rectangle.

: BOX           \ x y w h --
INTERPRETER: Use in the form:

 x y w h BOX

to produce a rectangular outline.

: JTEXT"        \ x y w h <"text"> --
INTERPRETER: Use in the form:

 x y w h JTEXT" <lots of text on one source line>"

to produce fully justfied text that may spread over several lines. Note that there should be only one space between each word for best results.

: JTEXTBOX"     \ x y w h <"text"> --
INTERPRETER: Use in the form:

 x y w h JTEXTBOX" <lots of text on one source line>"

to produce a rectangular outline filled with justfied text. Like JTEXT" but with a box around it.

: GRAPHIC       \ x y w h --
INTERPRETER: Use in the form:

 x y w h GRAPHIC <filename>

to produce an image loaded with the top left hand corner at x,y. The width and height are at present unused. The image file is loaded into the dictionary at compile time.

: PICTURE       \ x y w h --
INTERPRETER: Use in the form:

 x y w h addr PICTURE

to produce an image loaded with the top left hand corner at x,y. The width and height are at present unused. The image data is at addr.

: Image:        \ -- ; -- addr
INTERPRETER: Create a dictionary entry and load a graphics file to the current section, e.g.

 Image: demo1 %GuiDir%\Pics\demo1.bin

The image can be displayed using code of the for:

 x y demo1 load-image

Image Conversion

Before use, images created on a PC must be converted to the format required by the particular LCD panel. The The conversion tools are now part of the AIDE compiler front-end.

Although it is possible to convert standard graphics formats "on the fly" for display, it usually requires considerably more image storage space, is usually slower, and requires a more complicated (larger and slower) image display routine. If your display system is running at 8 or 16 bits per pixel, and/or images are frequently changed, it may well be worthwhile to consider this approach.

AIDE

The tool in the AIDE front end is the current version. Source code for AIDE is available on request. In AIDE, select Utilities -> BMP to LCD converter. There are options to flip the image vertically, generate little or big-endian data, and to add the header needed by PowerView to display the image.

Legacy code

The older tool for the QVGA 2-bit mono is in the folder Examples\PowerView\BMPcnv folder, together with full source code to compile on VFX Forth for Windows.

When generating images for use with a 2 bit LCD panel, ensure that the image width is a multiple of four bits. Save the image as 4 bits per pixel grayscale if this is available, or as a 16-colour image, e.g. in MS Paint (file mspaint.exe} the selection of output file type is "16 Colour Bitmap".

BMPcnv.exe is a Windows-32 tool for converting 16 colour (4-bit) images to the four-level (2-bit) grayscale format required by the GiantPlus GPG3224TWE3 and equivalent panels for which we have provided a driver. It is assumed that the bitmap being converted is a .BMP file with a 4 bit Windows standard pallette (preferably grayscale) and has been flipped vertically prior to conversion. To convert a file:

Using different hardware

If you are not using a panel with the same RAM layout as one of the supplied example drivers, or you are not using one of the example LCD controllers, you will have to modify the files:

Fontxxxx.fth

contains the font used for text display.

LCDxxxx.fth

contains the LCD driver and graphics primitives.

GUI.fth

contains the high level code.

If your hardware requires an LCD layout that is not currently supported, you will need to add a new output format to AIDE's BmpCnv utility. Source code for AIDE is available on request. If the panel operates at 8 or 16 bits per pixel, you may find it more convenient to modify LOAD-IMAGE in the video driver to operate with BMP file images.

Example code

The example code in PowerView\GUIdemo.fth may be compiled as an example or to test changes you may have made.

2 equ GUIexamples?      \ -- n
Set this non-zero to compile some examples. If set greater than one, an example with several graphics images will be compiled. The full set of graphics requires 100+ kb of memory in the current CDATA section. This equate is only used if it has not already been defined, e.g. in your control file.

The following examples define two menus and their actions. The menu position is given in absolute pixel coordinates. The positions of the internal elements are relative to the top left hand corner of the menu. A title bar is generated only if a caption is defined.

Menu examples

: test1         ( -- )  cr ." ONE"  ;
: test2         ( -- )  cr ." TWO"  ;
: test3         ( -- )  cr ." THREE"  ;
: test4         ( -- )  cr ." FOUR"  ;

40 0 240 230 MENU MainMenu  Font16x12x2 MENUFONT
  CAPTION" MPE PowerView"  Font16x16x2 FONT
  40  36 160 32 BUTTON" Button 1"  RUNS test1
  40  76 160 32 BUTTON" Button 2"  RUNS test2
  40 116 160 32 BUTTON" Button 3"  RUNS test3
  40 156 160 32 BUTTON" Button 4"  RUNS test4
  0  196 240 32 CTEXT" Try me!"  Font16x16x2 FONT
END-MENU

0 0 320 240 MENU JustMenu
  CAPTION" MPE Embedded GUI"  Font16x12x2 FONT
    0  16 80 32 LTEXT" TLHC"  RUNS test1
  240  16 80 32 RTEXT" TRHC"  RUNS test2
    0 208 80 32 LTEXT" BLHC"  RUNS test3
  240 208 80 32 RTEXT" BRHC"  RUNS test4
create mpe
   88  24 160 80 GRAPHIC %GuiDir%\Pics\mpe.bin
   48 128 224 80 JTEXTBOX" This box is filled and justified with several lines of text"
END-MENU

: tt            \ --
Draw the menu MainMenu.

: uu            \ --
Draw the menu JustMenu.

Mixed text and graphics

The next example is of a slide presentation run as a separate task.

: Image:        \ -- ; -- addr
INTERPRETER: Create a dictionary entry and load a graphics file to the current section, e.g.

Image: demo1 %GuiDir%\Pics\demo1.bin

: demo          \ -- ; graphics demo
The action of the demonstration task.

task DemoTask   \ -- addr
Task that runs the demonstration.

: StartDemo     \ --
Start the demonstration task.

: StopDemo      \ --
Stop the demonstration task.

Example Monochrome LCD driver

The file LcdQvgaMono5.fth is a driver for a 320*240*2 bits monochrome QVGA panel for the Sharp LH77790B CPU with an on-chip LCD controller.

Low level driver

variable Fcolor \ -- addr
Holds the colour used for display - the foreground colour.

variable Bcolor \ -- addr
Holds the colour used for the background.

variable TColor \ -- addr
Holds the colour used for text. For displays that have more than one pixel per byte, TColor holds a cell-width colour mask.

: setFColor      \ colour --
Set the foreground colour.

: SetBColor  \ colour --
Set the background colour.

: setTColor     \ colour --
Set the text drawing colour.

: clear-lcd     \ --
Clear the LCD screen.

: init-lcd      \ --
Initialise the LCD hardware. Performed at power-up.

: PutPixel      \ x y --
Set the pixel to the current drawing (line) colour.

: PutByte      \ x y --
Set a byte (4 pixels) to the current drawing (line) colour.

: PutCell       \ x y --
Set a cell (16 pixels) to the current drawing (line) colour.

: h-line        \ x y len --
Draw a horizontal line of length len pixels starting at x,y.

: v-line        \ x y len --
Draw a vertical line of length len pixels starting at x,y.

: absRect          \ x y w h --
Draw a rectangle at x,y with width and height w,h.

: absFilledRect \ x y w h --
Draw a filled rectangle at x,y with width and height w,h.

Font display

: DrawChar      \ char vbuff bytes/row --
Draw the character at the given video buffer address or offset. The number of bytes or pixels per video row is also given. Note that DrawChar just calls the routine given in the current font table.

: .fchar        \ px py char --
Write a character at the given pixel address, which is stepped to the nearest byte boundary.

: sout          \ px py caddr len --
Write a string at the given pixel address, which is stepped to the nearest byte boundary.

Image handling

Before use, images created on a PC must be converted to the format required by the particular LCD panel. There are tools to do this in the Tools\BMPcnv folder.

: load-image    \ x y imageaddr --
Display a graphics image in memory at imageaddr at pixel position x,y. If part of the image is off the screen, the displayed image is clipped to the screen size.

Font handling

Each font requires a word that draws a character from the font.

[defined] Font12x8x2 [if]
Words for a 12x8 font.

: v@            \ addr -- 24bit
COMPILER: Unaligned 16 bit fetch.

: v!            \ 24bit addr --
COMPILER: Unaligned 16 bit store.

: !fontrow      \ 32b vaddr --
Write one row/line of the font map into video memory

: Draw12x8x2    \ char vbuff bytes/row --
Write a character at the given video address, given the number of bytes per video row.

[defined] Font16x12x2 [if]
Words for a 16x12 font.

: v@            \ addr -- 24bit
COMPILER: Unaligned 24 bit fetch.

: v!            \ 24bit addr --
COMPILER: Unaligned 24 bit store.

: !fontrow      \ 32b vaddr --
Write one row/line of the font map into video memory

: Draw16x12x2   \ char vbuff bytes/row --
Write a character at the given video address, given the number of bytes per video row.

[defined] Font16x16x2 [if]
Words for a 16x16 font.

: v@            \ addr -- 32bit
COMPILER: Unaligned 32 bit fetch.

: v!            \ 32bit addr --
COMPILER: Unaligned 32 bit store.

: !fontrow      \ 32b vaddr --
Write one row/line of the font map into video memory

: Draw16x16x2   \ char vbuff bytes/row --
Write a character at the given video address, given the number of bytes per video row.

Font managment

The file %GuiDir%\FontDefs.fth contains the structure definition for font tables. It must be compiled before any font tables are compiled. Six example font table files are provided:

Font12x8x1.fth

12x8 font, 1 bit per pixel

Font16x12x1.fth

16x12 font, 1 bit per pixel

Font16x16x1.fth

16x16 font, 1 bit per pixel

Font12x8x2.fth

12x8 font, 2 bit gray scale

Font16x12x2.fth

16x12 font, 2 bit gray scale

Font16x16x2.fth

16x16 font, 2 bit gray scale

Each font table structure includes the xt of the word that draws a character into video RAM. In the example fonts, this word is in the font file after the table. The word must have the stack effect:

 char vbuff bytes/row --

where char is the ASCII code of the character to be displayed, vbuff is the address of the first location in the video buffer and bytes/row is the number of bytes in each row of pixels in the video buffer. It is assumed that the rows are contiguous in video memory, that video RAM is byte addressable and that video rows are displayed horizontally. Characters are always set on byte boundaries. This means that for displays with more than one pixel per byte, character placement will be restricted in the X (horizontal) axis.

struct /Font    \ -- len
The font table data structure

  int f.link            \ link to previous font
  int f.height          \ height of character in pixels
  int f.width           \ width of character in pixels
  int f.mwidth          \ width of character in bytes/row
  int f.first           \ ASCII code of first character
  int f.end             \ ASCII code of last+1 character
  int f.charsize        \ size of character in bytes
  int f.xtDrawChar      \ xt of character drawing routine
                        \ char vbuff bytes/row --
  0 field f.map         \ start of character table
end-struct

variable CurrFont       \ -- addr
Holds the current font.

variable FontLink       \ -- addr
Anchor for list of fonts.

: char>map      \ char font -- map
Convert a character number into the address of the bitmap in the current font table.

: drawChar      \ char sys --
Draw the character at the given video buffer address or offset. The sys parameter(s) are implementation dependent. Note that DrawChar just calls the routine given in the current font table. See the hardware driver for the parameter details.

: /fwidth       \ -- pw
Return the current character width in pixels.

: /fheight      \ -- ph
Return the current character height in pixels.

A basic font

The file Fonts/Font16x12x2 contains a simple 16x12 font for use with 2 bit grayscale panels. It supports the standard ASCII characters with codes from 32 to 126. Each font requires a drawing word as defined by the /Font structure in FontDefs.fth.

struct /Font    \ -- len
The font table data structure from FontDefs.fth

  int f.link            \ link to previous font
  int f.height          \ height of character in pixels
  int f.width           \ width of character in pixels
  int f.mwidth          \ width of character in bytes/row
  int f.first           \ ASCII code of first character
  int f.end             \ ASCII code of last+1 character
  int f.charsize        \ size of character in bytes
  int f.xtDrawChar      \ xt of character drawing routine
                        \ char vbuff bytes/row --
  0 field f.map         \ start of character table
end-struct

create Font16x12x2      \ -- addr
Font table starting at char 32. Each character is defined as 16 24-bit items, each defining 12 bits as 2 bits per pixel for a 16x12 character.