Welcome Guest, you are in: Login

Fruit Of The Shed

Navigation (MMBasic)






Search the wiki

»


Page History: A Simple GUI pack

Compare Page Revisions



« Older Revision - Back to Page History - Newer Revision »


Page Revision: 2021/03/23 13:38


A Simple GUI pack

This is a work in progress in my spare time. This document has lots of improvements required - and I'll do them... just need a bit more time.
Still to come: Sliders, Lists, Drop-down Lists. As it is now, it provides a lot of useful functionality. Still have to add the bits that detail how alignment and frames work, so a few missing tables.

Enjoy

A Universal, Simple GUI pack

The larger MicroMites and ARMMites have a built –in GUI that allows your code to have an interactive LCD panel with all the usual gadgets (buttons, check boxes etc.) that we have become used to in the last 20 years. The MicroMite Mk2 is constrained in that there simply isn’t room in flash to add such luxuries to the firmware for these small but powerful microcontrollers. The following is a pure MMBasic solution so it can be easily deployed on any ‘Mite platform and means code using the GUI becomes platform independent.

Image

Conventions

Throughout this article, things that get put on the screen using this GUI pack are called "Gadgets" (I was an Amiga boy – sue me). In the GUI software pack, anywhere you see "Obj" (short for object) it is the same as a gadget in this article – the two terms are interchangeable here.


Variable and Constant name considerations


  • Starting with a capital are global (defined in the main body of the program).
  • Constants start with upper case.
  • Local variable names start with lower case (defined inside a Sub or Function).
  • All arrays must start at 0.


Background

Many of my own projects use the small Mk2 and have been, in the past, console only due to the pain of making a good interactive screen (on an LCD panel). In later projects I have been building my own GUIs based very strongly around a WindowsCE/95 look-a-like. I just happen to think the nice clean lines of the GUI with its default grey background and relief style buttons etc is so much nicer that the modern "Metro" or flat look of Windows 10.

Not having a GUI subsystem, any such project that has buttons etc. Had to be built from the ground up each time and were specifically managed with fixed co-ordinates and code to handle the presses of each button. It was a very inflexible solution. Modifications were a nightmare because the co-ordinates where specifically tested for presses etc.

It had been on the back-burner of my mind to build (in MMBasic) a complete subsystem that got rid of that and just let me design the GUI then concentrate on the application code and not have to worry about managing the screen a-fresh each time. Other people had shown an interest in the displays on some projects and it was a bit embarrassing to reveal it was bespoke each time. The following is the fruits of my labours. It is currently about 12K in size – which might come across as a lot of space at first glance, but when you consider I would often have 5 or 6K of very inflexible code to handle a few buttons, it isn’t that much of a sacrifice. You could trim it down to get rid of the bits you don’t want if size becomes a problem - as you will see it provides quite an array of gadgets. Even drop-down lists (eventually)!

A problem with driving LCD panels from MMBasic on smaller beasts is the one-directional nature of the communication with the LCD panel... you can throw stuff on them, but it is hard work (and slow in Basic) to pull back what is on the screen and buffer it so you can repair "damage". In my approach here (and confession: I have stolen a few ideas from my years as a VB programmer) is structured items in known places that can be quickly re-drawn when scribbled over. An example here is the text box. At first thought you might wonder why you would use it instead of simply throwing text on the panel. If you now think of a drop down menu drawing all over the screen contents, unless you know what it has damaged, how do you repair your lovely GUI? With simple Text, that isn’t possible. With a structured text box, the list or pop-up can tell which items it has drawn over and so when it goes away, it can easily initiate re-drawing just those items.


Approach

Two shared arrays hold the attributes of each gadget; its type, its place on the screen, the colours, its properties etc. Each item has a numerical "name" that can be whatever you like – you can apply structure to your gadgets... you could even have several "layers" of them and simply switch them on and off as you see fit making context sensitive "screens" a breeze. The limit to the number of gadgets is available RAM. The values stored here are then used to draw the gadgets using the in-built primitives of MMBasic (Box, Line, Text etc...)

Internally, all objects are identified by a pointer, so where you see "n" that is usually it - you never need to concern yourself with it. The identifier for the object is defined by your code - I call it "the numeric name". This is a number you decide in your code and is entirely defined by you. The code will translate your ID to a pointer as needed. Whenever you want to talk to one of your gadgets, you use the ID you gave it, never the internal pointer. You can use the ID to group your gadgets and I have an idea to allow pages of gadgets which would give a multi-screen effect simply by hiding everything not in a certain range and perhaps tabs along the top to select between the pages. Perhaps this doesn't belong in the pack but we'll see. There are lots of areas for improvement - speed-wise I could provide a short-cut sub for drawing an object in places where we already have its internal index, but that's two Subs and the size starts to creep up just like that... stuff like that with associated trade-offs.

Stuff you need to know (in no particular order)


  • Not all of this is working yet. Gadgets that have yet to be finished are clearly shown.
  • There are nine different gadget types – we’ll discuss them
    all in detail further on:
    • Button, Radio, CheckBox, Slider, TextBox, List Static, List DropDown, Progress Bar, Frame
  • Every gadget has a set of attributes which are defined in the preamble of your code – actually that is just a convenient place to put them; you can actually define and redefine all aspects of a gadget at anytime. A function, GUIObjDef will format them and correctly fill the O() array to keep track without any further intervention by your own program.
  • Every gadget has properties that you can read and write really easily to influence its operation and find out what happened with it.
  • After gadgets are defined and properties set, nothing happens on screen until you issue a Draw command for a gadget (an exception to this is animations when you touch certain types of gadget).
  • All gadgets are touchable and you can find out which really easily. Even gadgets that don’t generally do anything when touched (like Progress Bars) will report back their number if you touch them. It’s entirely down to you how you "run" your GUI.
  • Multiple fonts are not directly supported; if you set the font when you define affected gadgets and when you draw them, it may work. It will come but I just need to get it all working first.


Actually doing it – Getting usable Gadgets on the screen

There is some unavoidable setup required in the preamble of your program besides simply placing the GUI pack in your program. The following fragment of code should be placed near the start and executed before your program gets underway with its main tasks.

Preamble

'{mandatory config
     Option Base 0
     Const CGy=&hdddddd'Pale grey screen background
     Dim Integer Objs=20,P=0,Xt,Yt
     Dim Integer O(Objs,10)'GUI object settings
     Dim String Ot(Objs) Length 64'GUI object text
     Colour 0,CGy:Cls
'}


  • A constant is defined for the background colour.
  • Some global variables are defined:

    • Objs is the total number of gadgets usable, increase or decrease as your application requires.
    • P is the pointer to the next available gadget number – this is an internal number and points to a position in the array – it is not your object ID.
    • Xt & Yt are the co-ordinates of touches detected on the LCD panel
    • O() is a two-dimensional array that holds the specific properties of each gadget e.g. its type, its place on the screen and is state etc.
    • Ot() is a single dimensioned string array which holds any text associated with a gadget. Not all gadgets have a text property.

  • Finally we clear the panel to the default state of black text of the grey background

All objects are described to the GUI system using the GUIObjectDef() function. This handles all types of gadget.


Key Functions and Subs

Functions return interesting values and are signified by a preceding =

=GUIObjDef(a,b,c,d,e,f,g,h,i,j,k)

Has 11 arguments, some of which are optional and others which are redundant (meaningless in the context).

Returns -1 if there is no space to store the gadget attributes (increase Objs in the preamble). Other values can be ignored.

Argument Attribute Definition
aIDThe numeric name your program wants to use for this gadget. You define this, if you provide the same ID to multiple gadgets, the definition will be over-written. The ID allows you to group your gadgets sensibly. This is not the internal reference for the gadget.
bTypeThe type number of the gadget - see Gadgets and their Attributes below.
cXThe X & Y co-ordinates of the top left corner of the gadget on screen. These are given in "native" LCD panel co-ordinates i.e. 0,0 is the top left corner of the screen and 219,239 (for example) is the bottom right corner.
dY 
fWThe width and height of the gadget in pixels which go on to define the bottom right corner of the gadget. Remember these are relative values to the X & Y – they are not physical co-ordinates themselves.
gH 
hTextAny text which should be displayed with the gadget. This might be the word inside a button, the text in a textbox etc... Not all types of gadgets will use this attribute.
iType SpecificOptional. This value is interpreted depending on the type of gadget. Consult the relevant section for the gadget type below
jType SpecificOptional. This value is interpreted depending on the type of gadget. Consult the relevant section for the gadget type below
kType SpecificOptional. This value is interpreted depending on the type of gadget. Consult the relevant section for the gadget type below

Each of the arguments is mapped generally onto the O(n,1 to 10) elements, with some processing where required.

Examples:

A simple Save button
=GUIObjDef(21,1,10,10,80,30,"Save";,,,1)

Red RadioButton in group 4800
=GUIObjDef(40,2,170,100,0,0,"Red",4800,&hff0000)

Blue progress bar ranged 0-5000
=GUIObjDef(61,8,10,210,300,20,"",0,5000,&h0000ff02)


GUIObjPSet(a,b)

Sets the Properties of the gadget (these are values that are useful to the functions of your program).

Has two arguments:

Argument Attribute Definition
aIDThe numeric name your program wants to use for this gadget. You define this, if you provide the same ID to multiple gadgets, the definition will be over-written. The ID allows you to group your gadgets sensibly. This is not the internal reference for the gadget.
bstatus byteValue to set in the status. This is a bit-significant value. The meaning of each bit is as follows

The Properties of the gadget (these are values that are useful to the running of your code) are stored on O(n,0). This status byte is a bit-field. Important: Some the properties require GUIObjDraw() to see.

Status bit meanings (when set)

Bit 7 6 5 4 3 2 1 0
 ReservedCleanUp Set TouchedVisibleEnabledReservedReserved

Note: All reserved bits should be set to zero


  • 2: Enable. Says whether the gadget is active or "ghosted". Disabled (bit 2=0) gadgets are visible on the screen (if bit 3=1) but do not respond to touches. When touched the touch processor will continue to return -1 as if the gadget were not there.
  • 3: Visible. The gadget is displayed. If bit 3=0 the gadget will have a grey box drawn over it to erase it from the screen
  • 4: The object has been touched. If the object is not enabled or not visible (bits 2 or 3=0), this bit is not set by the touch processor. This bit must be cleared by your code. Use of this bit can be avoided if you are polling for touched by regular calls to the touch process Sub, i.e. in the main loop of your program. If however you are using interrupts (maybe your code spends long periods away from the main loop), this bit records touches for later use(Warning: the order in which touches occurred cannot be determined).
  • 5: Records the value of a gadget if applicable. Mainly used for Checkboxes and RadioButtons e.g. the state of a checkbox is: checked=1, not checked=0.
  • 6: Indicates the gadget may have been damaged by other gadgets and should be re-drawn. For drop-down lists, any gadgets displayed below the top line of the list will be over-written when the menu drops over them. Such gadgets will have bit 6 set in their status. The menu close sub will largely take care of this automatically.

Examples:

Our save Button from above is visible and enabled
=GUIObjPSet(21,&b00001100)

Our red RadioButton is disabled
=GUIObjPSet(40,&b00001000)

For flipping individual bits, here are two examples using a combination of GUIObjPGet and GUIObjPSet...

... to enable a gadget
Result=GUIObjPSet(myObj,GUIObjPGet(myObj) OR &b00000100)

... to disable a gadget
Result=GUIObjPSet(myObj,GUIObjPGet(myObj) AND&b11111011)



=GUIObjPGet(ID)

Returns the Properties of the gadget. See above for the meaning of each bit. The single argument is the numeric name ID assigned to the gadget by your program. The meaning of the bits in the returned value are as shown in GUIObjPSet() above.

Example:

Has our save button been touched?
=GUIObjPGet(21) AND &b00010000

A non-zero result says yes, otherwise no. As an aside, there are two approaches for detecting touches which are discussed in the section "Interrupt or not?" below


The Gadgets and their Attributes

We have discussed the functions to get gadgets on the screen, what their properties mean and how to manipulate them. There now follows a detailed discussion of each gadget type.



Buttons


Image

Buttons are the "traditional" command button. Rectangular, bordered areas (it is there even if you don’t show it) of the screen. The entire area is active, i.e. it causes an action if you click anywhere inside it. Usually there is some text which is displayed centrally both horizontally and vertically. It is usual for the border to have a raised appearance and to be animated to a depressed appearance when clicked, returning to its former when released.
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type1
XLocation co-ordinates on screen X,Y
Y 
<null>Argument is ignored
<null>Argument is ignored
TextButton text
<null>Argument is ignored
<null>Argument is ignored
Border TypeUsually 1, consult the section on border types for options

Buttons do not have numeric values that can be altered.

GUIObjValue  
IDThe numeric name your program will use for this object
aArgument is ignored
bArgument is ignored
cArgument is ignored

To change the text of a Frame, set the Ot(n) value directly

Example:
Ot(GUIFindObj(id))="New Text"
GUIObjDraw id



RadioButtons


Image

RadioButtons are an option button. A circular area bounded by a circular border in relief. Once activated, they can only be de-activated by touching another RadioButton in the same group. Its state can be set or unset by program control manipulating the SET bit in the gadget’s properties. Usually there is some text which is displayed to the right of the RadioButton. The entire area is active – including the text, i.e. it causes an action if you click anywhere on the button or its label. This makes it easier to activate on smaller displays as precise touch is not so critical. An activated RadioButton has a depressed circular appearance. A de-activated RadioButton has a raised circular appearance. Any change is animated when touched or under program control.

The Height of a RadioButton is fixed at 11 pixels, Width is determined by the length of the text+15 pixels.
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type2
XLocation co-ordinates on screen X,Y
Y 
<null>Argument is ignored
<null>Argument is ignored
TextRadioButton text
GroupThe group to which this button belongs. Buttons in the same group are affected by the operation of their members e.g. activating a button will deactivate all others in the group
ColourThe colour for the central "dot" of the button as &hRRGGBB
<null>Argument is ignored

RadioButtons do not have numeric values that can be altered.

GUIObjValue  
IDThe numeric name your program will use for this object
aArgument is ignored
bArgument is ignored
cArgument is ignored

To change the text of a Frame, set the Ot(n) value directly

Example:
Ot(GUIFindObj(id))="New Text"
GUIObjDraw(id)


CheckBoxes


Image

Checkboxes are a toggling option button. A small area bounded by a square border in relief. Once activated, they can be de-activated by touching again and vice versa. Its state can be set or unset by program control manipulating the SET bit in the gadget’s properties. Usually there is some text which is displayed to the right of the Checkbox. The entire area is active – including the text, i.e. it causes an action if you click anywhere on the Checkboxes or its label. This makes it easier to activate on smaller displays as precise touch is not so critical. An activated Checkbox has a depressed circular appearance. A de-activated Checkbox has a raised circular appearance. Any change is animated when touched or under program control.

The Height of a Checkbox is fixed at 11 pixels, Width is determined by the length of the text+15 pixels.
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type3
XLocation co-ordinates on screen X,Y
Y 
<null>Argument is ignored
<null>Argument is ignored
TextCheckbox text
<null>Argument is ignored
<null>Argument is ignored
<null>Argument is ignored

CheckBoxes do not have numeric values that can be altered.

GUIObjValue  
IDThe numeric name your program will use for this object
aArgument is ignored
bArgument is ignored
cArgument is ignored

To change the text of a Frame, set the Ot(n) value directly

Example:
Ot(GUIFindObj(id))="New Text"
GUIObjDraw id


Frames


Image

A simple rectangular box with a text label. Used for grouping related gadgets more for aesthetics than functionality. Beware defining Frames before the gadgets they contain. They can prevent gadgets from being identified when touched in favour of the enclosing frame. Best to places gadgets on the screen then place Frames last of all.

Unlike desktop GUIs, disabling a frame will not automatically disable all items within it.
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type9
XLocation co-ordinates on screen X,Y
Y 
WDimensions Width and Height
H 
TextFrame text
<null>Argument is ignored
<null>Argument is ignored
Border Type Usually 5, consult the section on border types for options

Frames do not have numeric values that can be altered.

GUIObjValue  
IDThe numeric name your program will use for this object
aArgument is ignored
bArgument is ignored
cArgument is ignored

To change the text of a Frame, set the Ot(n) value directly

Example:
Ot(GUIFindObj(id))="New Text"
GUIObjDraw id


TextBoxes


Image

A rectangular area in which text is written. May have any style of border
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type5
XLocation co-ordinates on screen X,Y
Y 
WDimensions Width and Height
H 
TextText value of the text field
Background colour (paper)Background colour as &hRRGGBB
Foreground colour (pen)Foreground colour as &hRRGGBB
Border Type and AlignmentBorder type and Alignment are stuffed in a single byte. Consult the section on border types for options

TextBoxes do not have numeric values that can be altered.

GUIObjValue  
IDThe numeric name your program will use for this object
aArgument is ignored
bArgument is ignored
cArgument is ignored


To change the text of a TextBoxes, set the Ot(n) value directly

Example:
Ot(GUIFindObj(id))="New Text"
GUIObjDraw id


Progress bars


Image

A progress bar is a rectangular area with increasing/decreasing coverage depending on the current set value. The minimum and maximum extremes of the range are settable to any value and the physical size of the bar on the screen will be scaled accordingly. The border of the bar may be set to any frame style although the depressed button appearance is most usual.

Progress bars may be horizontal or vertical. They always progress low to high as left to right or bottom to top respectively
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type8
XLocation co-ordinates on screen X,Y
Y 
WDimensions Width and Height
H 
<null>Progress bars do not have a text attribute, Set to ""
Bottom of rangeAny numeric value < top of range
Top of rangeAny numeric value > bottom of range
Colour, Border Type and AlignmentBorder type and Alignment are stuffed in a single byte. Consult the section on border types for options

ProgressBar numeric values that can be altered.

GUIObjValue  
IDThe numeric name your program will use for this object
aMin value
bMax Value
cCurrent value

Note: the current value is constrained when set


Sliders


Image

A moving button that can be slid up and down a scale to indicate a value. The minimum and maximum extremes of the range are settable to any value and the physical size of the slider on the screen scales accordingly.
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type4
XLocation co-ordinates on screen X,Y
Y 
<null>Argument is ignored
<null>Argument is ignored
<null>Sliders do not have a text attribute, Set to ""
Bottom of rangeAny numeric value < top of range
Top of rangeAny numeric value > bottom of range
Colour, Border Type and AlignmentBorder type and Alignment are stuffed in a single byte. Consult the section on border types for options

Slider numeric values that can be altered.

GUIObjValue  
IDThe numeric name your program will use for this object
aMin value
bMax Value
cCurrent value

Note: the current value is constrained B=>v<=T when set



List Static

Similar in appearance to the text box, the Static list has direction arrows at each end and the list can be navigated through with the current selected item displaying in the text area.
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type7
XLocation co-ordinates on screen X,Y
Y 
WDimensions Width and Height
H 
TextFrame text
Background colour (paper)Background colour as &hRRGGBB
Foreground colour (pen)Foreground colour as &hRRGGBB
Border Type and AlignmentBorder type and Alignment are stuffed in a single byte. Consult the section on border types for options



List Drop-Down

Similar in appearance to the text box, the Drop-down list displays a rectangular area containing lines of text when touched. An item may be selected by touching it. If more items exist than the box can contain, the up and down arrows on the right of the drop-down can be used to navigate through the list. When an item is selected, the drop-down box is erased, the text is set to the selected item and any damaged items (where the drop-down obliterated them) are set for cleanup.
GUIObjDef Attributes  
IDThe numeric name your program will use for this object
Type7
XLocation co-ordinates on screen X,Y
Y 
WDimensions Width and Height
H 
TextFrame text
Background colour (paper)Background colour as &hRRGGBB
Foreground colour (pen)Foreground colour as &hRRGGBB
Border Type and AlignmentBorder type and Alignment are stuffed in a single byte. Consult the section on border types for options


Border Types and alignment

Not all gadgets support a border type but for those that do, the value contains several indicators in a single integer.

Alignment ValueByte 3Byte 2Byte 1 Byte 0
 Red for stuffed colourGreen for stuffed colourBlue for stuffed colourBorder Style and Alignment

The rightmost byte is further interpreted by it's two nibbles thus:

Bit 7-4Bits 3-0 Description
x0No Border
x1Button style raised
x2Button style depressed
x3White
x4Black
x5Grey (disabled)
0xAlign Left/Horizontal
1xAlign Centre/Vertical
2xAlign Right

Example:

Image

Due to redundancy, not all border/alignment combinations are applicable to any given gadget



The Code

'{mandatory GUI config
	Option Base 0
	Const cGy=&hdddddd'Pale grey screen background
	Colour 0,cGy:Cls
	Dim Integer Objs=20,P=0,Flags,Xt,Yt
	Dim Integer O(Objs,10)'GUI object settings
	Dim String Ot(Objs)'GUI object text
'}

	'Backlight 80' 100 is off

MainInit:

	Dim Integer res

'Buttons
	res= GUIObjDef(21,1,10,10,80,30,"Save",,,1)
	res= GUIObjDef(23,1,10,50,80,30,"Exit",,,1)
'Checkboxes
	res= GUIObjDef(25,3,10,100,,,"Checked")
	res= GUIObjDef(27,3,10,120,,,"Disabled")
	res= GUIObjDef(29,3,10,140,,,"Not Checked")
'Radio boxes (in a frame)
	res= GUIObjDef(40,2,170,100,,,"Red",1,&hff0000)
	res= GUIObjDef(41,2,170,120,,,"Green",1,&hff00)
	res= GUIObjDef(42,2,170,140,,,"Blue",1,&hff)
	res= GUIObjDef(39,9,165,90,80,65,"Colours",,,&h05)
'text boxes
	res= GUIObjDef(50,5,160,10,150,15,"L Text black frame",&h00aa00,&hffff00,&h04)
	res= GUIObjDef(51,5,160,35,150,15,"C Text no frame",cGy,0,&h10)
	res= GUIObjDef(52,5,160,60,150,15,"",&hffffff,0,&h22)
'progress bar
	res= GUIObjDef(61,8,10,210,300,20,"",0,500,&h0000ff02)
	res= GUIObjDef(62,8,270,90,40,65,"",0,500,&hff000012)
'Slider

Main:
'set the properties of the object, visibility, enabled etc...
	res=GUIObjPSet(21,&b00001100)
	res=GUIObjPSet(23,&b00001000)
	res=GUIObjPSet(25,&b00101100)
	res=GUIObjPSet(27,&b00101000)
	res=GUIObjPSet(29,&b00001100)
	res=GUIObjPSet(39,&b00001100)
	res=GUIObjPSet(40,&b00101100)
	res=GUIObjPSet(41,&b00001100)
	res=GUIObjPSet(42,&b00001100)
	res=GUIObjPSet(50,&b00001100)
	res=GUIObjPSet(51,&b00001100)
	res=GUIObjPSet(52,&b00001100)
	res=GUIObjPSet(61,&b00001100)
	res=GUIObjPSet(62,&b00001100)

'nothing appears on the screen until you draw the object
'this allows multiple updates at once and you control when it happend
	GUIObjDraw 21
	GUIObjDraw 23
	GUIObjDraw 25
	GUIObjDraw 27
	GUIObjDraw 29
	GUIObjDraw 39
	GUIObjDraw 40
	GUIObjDraw 41
	GUIObjDraw 42
	GUIObjDraw 50
	GUIObjDraw 51
	GUIObjDraw 52
	GUIObjDraw 61
	GUIObjDraw 62

'a little example code
	q=1000
	If res <>-1 Then
		timer=0
'draw the progress bars for increasing value
		For n=1 To q step 50
				GUIObjValue(61,0,q,n)
				GUIObjDraw 61
				GUIObjValue(62,0,q,n)
				GUIObjDraw 62
		Next
'set the contents of a text box
		Ot(GUIFindObj(52))="R "+Str$(timer/n)+"mS"
		GUIObjDraw 52
	EndIf

'go round in a loop printing (to the console) the ID (numeric name) of
'any touched objects and how long it was touched for
	Do
		Timer=0
		q=ProcessTouch()
		If q<>-1 Then ? "Obj ";q,,"Dwell";Timer;"mS"
		Pause 100
	Loop

	End


'------------------ The GUI pack
'Main touch processor. Regular calls here will get the numeric name of
'screen objects that are touched, return -1 if no object is touched
'animates and manages status etc
	Function ProcessTouch() As Integer
		ProcessTouch=-1
		Xt=Touch(x):
		Yt=Touch(y)
		If Xt=-1 Or Yt=-1 Then Exit Function
		Local Integer n,m
		For n=0 To P
			If Xt>=O(n,3) Then
				If Yt>=O(n,4) Then
					If Xt<=O(n,5) Then
						If Yt<=O(n,6) Then
							If O(n,2) And 8 Then
								If O(n,2) And 4 Then
									ProcessTouch=O(n,0)
									O(n,2)=O(n,2) Or &b00010000'touched
									Select Case O(n,1)'click animation
										Case 1
											O(n,9)=2
											GUIObjDraw O(n,0)
										Case 2
											For m=0 To P
												If O(n,0)<>O(m,0) Then
													If O(m,1)=2 Then
														If O(m,7)=O(n,7) Then
															O(m,2)=O(m,2) And &b11011111
															GUIObjDraw O(m,0)
														EndIf
													EndIf
												EndIf
											Next
											O(n,2)=O(n,2) Or &h20
											GUIObjDraw O(n,0)
										Case 3
											If O(n,2) And &b00100000 Then
												O(n,2)=O(n,2) And &b11011111
											Else
												O(n,2)=O(n,2) Or &b00100000
											EndIf
											GUIObjDraw O(n,0)
										Case 4
										Case 6
										Case 7
									End Select
									WaitNoTouch
									Select Case O(n,1)'release animation
										Case 1
											O(n,9)=1
											GUIObjDraw O(n,0)
										Case 6
										Case 7
									End Select
									Exit Function
								EndIf
							EndIf
						EndIf
					EndIf
				EndIf
			EndIf
		Next
	End Function

'waits for the stylus to be lifted off the panel
	Sub WaitNoTouch
		Do
			'Watchdog here if you want it
			Pause 10
		Loop Until Touch(x)=-1
	End Sub

'Sub will draw any object in it's current state
	Sub GuiObjDraw(id As Integer)'n is the object id
		Local Integer n,m,x,y,z,w,h
		Local Float nn
		Local a$
		n=GUIFindObj(id)
		If n>-1 Then
			GUIObjCleanup n
			x=O(n,3):y=O(n,4)
			w=O(n,5)-x:h=O(n,6)-y
			Select Case O(n,1)
				Case 1'button
					If O(n,2) And 8 Then'visible
						GUIFrame n,0
						If O(n,2) And 4 Then'Enabled
							Colour 0
						Else'ghosted
							Colour &h999999
						EndIf
						Text w/2+x-MM.FONTWIDTH*Len(Ot(n))/2,h/2+y-MM.FONTHEIGHT/2,Ot(n)
					Else'disappear
						GUIObjCleanup n,1
					EndIf
				Case 2'radio
					If O(n,2) And 8 Then'visible
						Circle x+5,y+5,4,,,O(n,8),O(n,8)
						x=x+5:y=y+5
						If O(n,2) And 4 Then'Enabled
							If O(n,2) And 32 Then'set
								Colour 0
								For nn=2.34 To 5.5 Step 0.2'45 to 225
									Pixel x+6*Sin(nn),y+6*Cos(nn)
								Next
								Colour &hffffff
								For nn=5.5 To 8.64 Step 0.2	'225 to 45
									Pixel x+6*Sin(nn),y+6*Cos(nn)
								Next
							Else
								Colour &hffffff
								For nn=2.34 To 5.5 Step 0.2'45 to 225
									Pixel x+6*Sin(nn),y+6*Cos(nn)
								Next
								Colour 0
								For nn=5.5 To 8.64 Step 0.2	'225 to 45
									Pixel x+6*Sin(nn),y+6*Cos(nn)
								Next
							EndIf
							Colour 0
						Else
							Colour &h999999
							For nn=0 To 6.4 Step 0.2
								Pixel x+6*Sin(nn),y+6*Cos(nn)
							Next
						EndIf
						Text x+15,y+(h/2)-MM.FONTHEIGHT+2,Ot(n)
					Else'disappear
						GUIObjCleanup n,1
					EndIf
				Case 3'checkbox
					If O(n,2) And 8 Then'visible
						Colour 0
						Line x,y,x,y+11'|
						Line x,y,x+11,y'-
						Colour &hffffff
						Line x+11,y,x+11,y+11'|
						Line x,y+11,x,y+11'_
						If O(n,2) And 4 Then'Enabled
							Colour 0
						Else'ghosted
							Colour &h999999
						EndIf
						If O(n,2) And 32 Then'checked
							Gui Bitmap x+2,y+2,&h18386C6CC6020301
						Else
							Gui Bitmap x+2,y+2,0
						EndIf
						Text x+15,y+(h/2)-(MM.FONTHEIGHT/2),Ot(n)
					Else'disappear
						GUIObjCleanup n,1
					EndIf
				Case 4'slider

				Case 5'textbox
					If O(n,2) And 8 Then'visible
						Box x,y,w+1,h+1,,O(n,7),O(n,7)
						GUIFrame n,1
						Select Case O(n,9)>>4
							Case 0'L
								Text x,y,Ot(n),,,,O(n,8),O(n,7)
							Case 1'C
								Text w/2+x-MM.FONTWIDTH*Len(Ot(n))/2,h/2+y-MM.FONTHEIGHT/2,Ot(n),,,,O(n,8),O(n,7)
							Case 2'R
								Text O(n,5)-(MM.FONTWIDTH*Len(Ot(n))),h/2+y-MM.FONTHEIGHT/2,Ot(n),,,,O(n,8),O(n,7)
						End Select
					Else'disappear
						GUIObjCleanup n,1
					EndIf
				Case 6'list static
				Case 7'list dropdown
				Case 8'progress bar
					If O(n,2) And 8 Then'visible
						GUIFrame n,1
						If O(n,9) And &h10 Then'vert
							z=(h/(O(n,8)-O(n,7)))*O(n,10)'pixels per increment*value = width of bar to draw in pixels
							Box x,y,w,h-z,,cGy,cGy
							Box x,(y+h)-z,w,z,,O(n,9)>>8,O(n,9)>>8'extreme right of bar
						Else'hoz
							z=(w/(O(n,8)-O(n,7)))*O(n,10)'pixels per increment*value = width of bar to draw in pixels
							Box x+z,y,w-z,h,,cGy,cGy
							Box x,y,z,h,,O(n,9)>>8,O(n,9)>>8'extreme right of bar
						EndIf
					Else'disappear
						GUIObjCleanup n,1
					EndIf
				Case 9'frame
					GUIFrame n,0
					Colour 0,cGy
					Text x+5,y-MM.FONTHEIGHT/2,Ot(n)
			End Select
		EndIf
	End Sub

'set values of gadget by its numeric name
	Sub GUIObjValue(id As Integer,mn As Integer,mx As Integer,cv As Integer)
		Local Integer n
		n=GUIFindObj(id)
		If n>-1 Then
			Select Case O(n,1)
				Case 4,8'slider & progress bar Min, Max, Current
					O(n,7)=mn
					O(n,8)=mx
					O(n,10)=Constrain(cv,mn,mx)
			End Select
		EndIf
	End Sub

'draws any type of border around an object
	Sub GUIFrame(n As Integer,os As Integer)
		Local Integer c1,c2
		Select Case O(n,9) And &h0F
			Case 0'none
				c1=cGy:c2=cGy
			Case 1'button style raised
				c1=&hffffff:c2=0
			Case 2'button style depressed
				c1=0:c2=&hffffff
			Case 3'white
				c1=&hffffff:c2=&hffffff
			Case 4'black
				c1=0:c2=0
			Case 5'grey (disabled)
				c1=&h999999:c2=	&h999999
		End Select
		Colour c1
		Line O(n,3)-os,O(n,4)-os,O(n,3)-os,O(n,6)+os'|
		Line O(n,3)-os,O(n,4)-os,O(n,5)+os,O(n,4)-os'-
		Colour c2
		Line O(n,5)+os,O(n,4)-os,O(n,5)+os,O(n,6)+os'|
		Line O(n,3)-os,O(n,6)+os,O(n,5)+os,O(n,6)+os'_
	End Sub

'defines an object but doesn't draw anything. returns 0 if all OK.
	Function GUIObjDef(id As Integer,tp As Integer,x As Integer,y As Integer,w As Integer,h As Integer,t$,g As Integer,c As Integer,d As Integer) As Integer
		Local Integer n
		If P>Objs Then GUIObjDef=1:Exit Function'too many objects
		n=GUIFindObj(id)
		If n=-1 Then n=P:P=P+1'define or redefine. P always points to the next free "slot"
		O(n,0)=id
		O(n,1)=tp
		O(n,2)=0
		O(n,3)=x
		O(n,4)=y
		O(n,7)=g
		O(n,8)=c
		O(n,9)=d
		O(n,10)=g
		Ot(n)=t$
		Select Case tp
			Case 1,5,8,9'button,textbox,progress bar,frame
				O(n,5)=x+w
				O(n,6)=y+h
			Case 2,3'Radio,checkbox
				O(n,5)=x+15+MM.FONTWIDTH*Len(t$)
				O(n,6)=y+MM.FONTHEIGHT
			Case 4'Slider
			Case 6'List Static
			Case 7'List DropDown
		End Select
	End Function

'removes an object from the screen by its internal reference
	Sub GUIObjCleanup(n,f)
		If f Or (O(n,2) And 64) Then
			Box O(n,3)-1,O(n,4)-1,O(n,5)-O(n,3)+1,O(n,6)-O(n,4)+1,,cGy,cGy
		EndIf
		O(n,2)=O(n,2) And &hBF'clear cleanup flag
	End Sub

'Sets the properties of an object
'Returns -1 if not found
	Function GUIObjPSet(id As Integer,b As Integer) As Integer'id,enabled,visible,touched,Set,cleanup
		Local Integer n
		n=GUIFindObj(id)
		If n>-1 Then
			O(n,2)=b:Exit Function
		EndIf
		GUIObjPSet=-1'object not found
	End Function

'Returns the properties of an object by its numeric name
'Returns the properties or -1 if not found
	Function GUIObjPGet(id As Integer) As Integer
		Local Integer n
		n=GUIFindObj(id)
		If n>-1 Then
			GUIObjPGet=O(n,2):Exit Function
		EndIf
		GUIObjPGet=-1'object not found
	End Function

'Finds the internal reference for an object from its numeric name
'Returns the object number or -1 if not found
	Function GUIFindObj(id)
		Local Integer n
		For n=0 To P-1
			If O(n,0)=id Then GUIFindObj=n:Exit Function'object exists
		Next
		GUIFindObj=-1
	End Function

'force a value within boundaries
	Function Constrain(v As Integer,l As Integer,u As Integer) As Integer
		Constrain=Min(Max(v,l),u)
	End Function