TriOS-alt/system/bellatrix/vga-gui/GUIBase.spin

939 lines
64 KiB
Plaintext

CON ''=====< GUI Base >=======================================================
''
'' ===========================================================================
'' VGA High-Res Text UI Elements Base UI Support Functions v1.2
''
'' File: GUIBase.spin
'' Author: Allen Marincak
'' Copyright (c) 2009 Allen MArincak
'' See end of file for terms of use
'' ===========================================================================
CON
'---------------------------------------------------------------------------
' GUI Element Inventory
'---------------------------------------------------------------------------
' User modifies these as required by the GUI application being written.
' These constants describe how many elements of each type are required. Set
' any you do not need to 1. You can't set it to 0 because there is no
' conditional compilation for SPIN so I can't avoid NULL references.
'--------------------------------------------------------------------------
GZ_SPIN = 2 'number of SPIN controls
GZ_CHKB = 4 'number of Check Boxes
GZ_RADB = 6 'number of Radio Buttons
GZ_TBOX = 3 'number of Text Boxes
GZ_MENU = 6 'number of Menu Items
GZ_INPF = 3 'number of Input Fields
GZ_PUSH = 3 'number of pushbuttons
GZ_STAT = 2 'number of Status Lamps
'---------------------------------------------------------------------------
' Do not modify any of the constants below
'---------------------------------------------------------------------------
GZ_TOTAL = GZ_SPIN+GZ_CHKB+GZ_RADB+GZ_TBOX+GZ_MENU+GZ_INPF+GZ_PUSH+GZ_STAT
GID_SPIN = $0100 'types
GID_CHKB = $0200
GID_RADB = $0300
GID_TBOX = $0400
GID_MENU = $0500
GID_INPF = $0600
GID_PUSH = $0700
GID_STAT = $0800
G_INIT = $8000
G_IMSK = $7F00
G_OMSK = $00FF
VGACOLS = SVGA#cols
VGAROWS = SVGA#rows
OBJ
'---------------------------------------------------------------------------
' required driver objects, keep these
'---------------------------------------------------------------------------
SVGA : "vga_hires_text"
MOUS : "mouse"
KEYB : "Keyboard" 'only needed if using the Input Field Object
'---------------------------------------------------------------------------
' UI element objects
'
' You will need to comment out elements for which you set the number to 0,
' the compiler will issue an error for 0 sized arrays.
'
' Note that the SBOX object (Simple Box) is used by several other objects so
' do not comment out that one (it is miniscule anyway)
'---------------------------------------------------------------------------
SPIN[GZ_SPIN] : "SpinBox"
CHKB[GZ_CHKB] : "RadioCheck"
RADB[GZ_RADB] : "RadioCheck"
TBOX[GZ_TBOX] : "TextBox"
MENU[GZ_MENU] : "MenuItem"
INPF[GZ_INPF] : "InputField"
PUSH[GZ_PUSH] : "PushButton"
STAT[GZ_STAT] : "StatusLamp"
SBOX : "SimpleBox"
VAR
long scrn[VGACOLS*VGAROWS/4] 'screen buffer - could be bytes, but longs allow more efficient scrolling
word colors[VGAROWS] 'row colors
long sync 'sync long - written to -1 by VGA driver after each screen refresh
byte cx0,cy0,cm0,cx1,cy1,cm1 'cursor control bytes
long liveINPF 'currently active Input Field (has keyboard focus)
word gz_elem[GZ_TOTAL] 'element management array
byte gz_groups[GZ_RADB] 'radio button group control
CON ''=====< GUI Base Functions >=============================================
'
' <!> NOTE <!> Do not modify anything below unless you wish ot add or
' make changes to the GUI functionality
'-------------------------------------------------------------------------
PUB Init( vgaBasePin, MouseDatPin, MouseClkPin, KeyboardDatPin, KeyboardClkPin ) | idx, gdx
'Initializes the VGA, Mouse and Keyboard Drivers as well as basic GUI parameters
'
' vgaBasePin - start of 8 consecutive pins where the VGA H/W interface is
' MouseDatPin - the pin driving the mouse data line
' MouseClkPin - the pin driving the mouse clock line
' KeyboardDatPin - the pin driving the keyboard data line
' KeyboardClkPin - the pin driving the keyboard clock line
'
'Returns the screen geometry in a WORD
' high byte = number of character rows
' low byte = number of cgaracter columns
'---------------------------------------------------------------------------
' Start VGA, Mouse and Keyboard Drivers
'---------------------------------------------------------------------------
cx1 := 0 'text cursor starting position
cy1 := 3 ' (but hidden at start)
SVGA.start(vgaBasePin,@scrn,@colors,@cx0,@sync) 'start VGA HI RES TEXT driver
MOUS.start(MouseDatPin, MouseClkPin) 'start mouse and set bound parameters
MOUS.bound_limits(0, 0, 0, VGACOLS - 1, VGAROWS - 1, 0)
MOUS.bound_scales(4, -7, 0) 'adjust speed/sensitivity to be a touch slower
MOUS.bound_preset(2, 6, 0) 'mouse starting position
KEYB.start( KeyboardDatPin, KeyboardClkPin ) 'start keyboard driver
cm0 := %001 'set mouse cursor to be a solid block
cm1 := %000 'set text cursor to be off for the moment
ClearScreen( %%020, %%000 ) 'green on black each is %%RGB 4 levels per R-G-B
'---------------------------------------------------------------------------
'Prepare management and control array. This array has an entry for each
'element declared it maintains the status of each element and indices into
'the individual element arrays
'
'WORD format: aabb
'
' where aa = type with msb 0 = free 1 = set (initialized)
' bb = index to element array
'---------------------------------------------------------------------------
gdx := 0
if GZ_SPIN
repeat idx from 0 to GZ_SPIN - 1
gz_elem[gdx] := GID_SPIN + idx
SPIN[idx].set_gzidx( gdx )
gdx++
if GZ_CHKB
repeat idx from 0 to GZ_CHKB - 1
gz_elem[gdx] := GID_CHKB + idx
CHKB[idx].set_gzidx( gdx )
gdx++
if GZ_RADB
repeat idx from 0 to GZ_RADB - 1
gz_elem[gdx] := GID_RADB + idx
RADB[idx].set_gzidx( gdx )
gdx++
if GZ_TBOX
repeat idx from 0 to GZ_TBOX - 1
gz_elem[gdx] := GID_TBOX + idx
TBOX[idx].set_gzidx( gdx )
gdx++
if GZ_MENU
repeat idx from 0 to GZ_MENU - 1
gz_elem[gdx] := GID_MENU + idx
MENU[idx].set_gzidx( gdx )
gdx++
if GZ_INPF
repeat idx from 0 to GZ_INPF - 1
gz_elem[gdx] := GID_INPF + idx
INPF[idx].set_gzidx( gdx )
gdx++
if GZ_PUSH
repeat idx from 0 to GZ_PUSH - 1
gz_elem[gdx] := GID_PUSH + idx
PUSH[idx].set_gzidx( gdx )
gdx++
if GZ_STAT
repeat idx from 0 to GZ_STAT - 1
gz_elem[gdx] := GID_STAT + idx
STAT[idx].set_gzidx( gdx )
gdx++
liveINPF := 0
return ( VGAROWS << 8 ) + VGACOLS
PUB ProcessUI | retVal, gdx_in, odx, idx, tmp
'This function is the UI processing and control funtion. It must be executed
'often, regularly, and quickly. It should be placed in the application main
'loop and be allowed to run as often as possible to ensure a responsive UI
'
'This function will manage the UI and will return the unique id of the GUI
'element that requires an action (i.e. user clicked on an item or pressed
'enter in an Input Field). The value returned ( a GUID ) is the same value
'that was returned when the element was created via "Init" function (i.e.
'from GUI.SPINInit() or GUI.PUSHInit(), etc)
retVal := -1
cx0 := MOUS.bound_x 'get mouse position to set cursor 0 position
cy0 := MOUS.bound_y 'ALWAYS do this first
'---------------------------------------------------------------------------
'check if mouse over a control
'---------------------------------------------------------------------------
gdx_in := IsIn( cx0, cy0 )
'---------------------------------------------------------------------------
'on mouse left click perform UI action for selected element (if any)
'---------------------------------------------------------------------------
if gdx_in <> -1 'if we are in a gui element
if MOUS.button(0) 'if mouse left-click
odx := gz_elem[gdx_in] & G_OMSK 'index to object array
case gz_elem[gdx_in] & G_IMSK
GID_SPIN: 'in Spin Control
if SPIN[odx].Clicked(cx0,cy0)<>-1 ' - execute click on spin
retVal := gdx_in
GID_CHKB: 'in Check Box
CHKB[odx].Select( -1 ) ' - toggle checkbox
retVal := gdx_in
GID_RADB: 'in Radio Button
idx := 0
repeat GZ_RADB 'for each radio button
if odx == idx
RADB[idx].Select( 1 ) ' - toggle ON the selected one
RADB[idx].DrawText( 1 )
else
if gz_groups[odx] == gz_groups[idx]
RADB[idx].Select( 0 ) ' - toggle OFF the others in this group
RADB[idx].DrawText( 0 )
idx++
retVal := gdx_in
GID_TBOX: 'in Text Box
retVal := gdx_in
GID_MENU: 'in Menu Item
retVal := gdx_in
GID_INPF: 'in Input Field
idx := 0
repeat GZ_INPF 'for each input field
if idx == odx
INPF[idx].Select(1,@cx1,@cy1)
liveINPF := idx
cm1 := %111 'turn text cursor on, underscore slow blink
else
INPF[idx].Select(0,@cx1,@cy1)
idx++
'note no return for selecting INPF
GID_PUSH: 'in Push Button
retVal := gdx_in
GID_STAT: 'in Status Lamp
retVal := gdx_in
repeat while MOUS.button(0) ' - wait for mouse release
'---------------------------------------------------------------------------
'Handle Keyboard input
'---------------------------------------------------------------------------
if KEYB.gotkey
idx := INPF[liveINPF].get_gzidx
if gz_elem[idx] & G_INIT == G_INIT 'is it set
tmp := INPF[liveINPF].Handler(KEYB.key)
if tmp & $80000000
retVal := INPF[liveINPF].get_gzidx 'if enter was pressed
return retVal
PUB GetMouseXY
'Returns the mouse location in a WORD
' high byte = x location
' low byte = y location
return ( cx0 << 8 ) + cy0
PRI IsIn( cx, cy ) | idx, gdx, retVal
'returns -1 if not in an element else a gui token (gz_elem[] array index)
retVal := -1
if GZ_SPIN
repeat idx from 0 to GZ_SPIN - 1
gdx := SPIN[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if SPIN[idx].IsIn( cx, cy )
retVal := SPIN[idx].get_gzidx
if GZ_CHKB
repeat idx from 0 to GZ_CHKB - 1
gdx := CHKB[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if CHKB[idx].IsIn( cx, cy )
retVal := CHKB[idx].get_gzidx
CHKB[idx].DrawText( 1 )
else
CHKB[idx].DrawText( 0 )
if GZ_RADB
repeat idx from 0 to GZ_RADB - 1
gdx := RADB[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if RADB[idx].IsIn( cx, cy )
retVal := RADB[idx].get_gzidx
RADB[idx].DrawText( 1 )
else
RADB[idx].DrawText( 0 )
if GZ_TBOX
repeat idx from 0 to GZ_TBOX - 1
gdx := TBOX[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if TBOX[idx].IsIn( cx, cy )
retVal := TBOX[idx].get_gzidx
if GZ_MENU
repeat idx from 0 to GZ_MENU - 1
gdx := MENU[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if MENU[idx].IsIn( cx, cy )
retVal := MENU[idx].get_gzidx
MENU[idx].DrawText( 1 )
else
MENU[idx].DrawText( 0 )
if GZ_INPF
repeat idx from 0 to GZ_INPF - 1
gdx := INPF[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if INPF[idx].IsIn( cx, cy )
retVal := INPF[idx].get_gzidx
if GZ_PUSH
repeat idx from 0 to GZ_PUSH - 1
gdx := PUSH[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if PUSH[idx].IsIn( cx, cy )
retVal := PUSH[idx].get_gzidx
PUSH[idx].DrawText( 1 )
else
PUSH[idx].DrawText( 0 )
if GZ_STAT
repeat idx from 0 to GZ_STAT - 1
gdx := STAT[idx].get_gzidx
if gz_elem[gdx] & G_INIT == G_INIT 'is it set
if STAT[idx].IsIn( cx, cy )
retVal := STAT[idx].get_gzidx
return retVal
CON ''=====< SIMPLE BOX INTERFACE FUNCTIONS >=================================
PUB SBOXInit( pRow, pCol, pWidth, pHeight, pTitlePtr )
'Creates box with specified width and text. Something like:
' -------------
' | | - title area ( non-existant if no title supplied)
' -------------
' | |
' | | - text area with optional scolling print capability
' | |
' -------------
'
' pRow = row upper location
' pCol = col left location
' pWidth = width
' pHeight = height
' pTitlePtr = title text (text must be 2 less than width)
'
' NOTE: Columns must be LONG aligned to take advantage of the most efficient
' scrolling (via LONGMOVE). The start column must be on a long boundary
' (multiple of 4) and the width must be a multiple of 4. If print scrolling
' is not required this restriction can be ignored.
'
' NOTE: There is NO RETURN value from this call. Simple Boxes are not tracked,
' they are viaual element but are not active elements
SBOX.DrawBox( pRow, pCol, pWidth, pHeight, pTitlePtr, @scrn, VGACOLS )
CON ''=====< SPIN BOX INTERFACE FUNCTIONS >===================================
PUB SPINInit( pRow, pCol, pWidth, pType, pNum, pDataPtr ) | idx, gdx, retVal
'Creates a spin button box with specified width and text. Something like:
' ---------------------
' | spin text |↑|↓|
' ---------------------
'
' pRow = row upper location
' pCol = col left location
' pWidth = width of the control in columns
' pType = 0 = text 1 = numeric
' pNum = number of data elements
' pDataPtr = pointer to data for spin control
'
' The Data for the spin control is stored in a DAT section. For text type
' the section will be a number of byte aligned strings, each with a null
' terminator. For numeric type the section will be a number of long aligned
' longs.
'
'Returns -1 if there are no more free elements in the SPIN object array
' guid on success which is unique and used to identify the specific
' instance of the control.
retVal := -1
repeat idx from 0 to GZ_TBOX - 1
gdx := SPIN[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
SPIN[idx].Init( pRow, pCol, pWidth, pType, pNum, pDataPtr, @scrn, VGACOLS )
quit
return retVal
PUB SPINIsIn( guid ) | odx
' returns true if the mouse is inside the spin control
' false otherwise
odx := gz_elem[guid] & G_OMSK
return SPIN[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB SPINClicked( guid ) | odx
'checks where the mouse click ocurred and returns -1 if not on an UP or DOWN
'arrow otherwise it returns the zero based data index of the currently
'displayed data
odx := gz_elem[guid] & G_OMSK
return SPIN[odx].Clicked( MOUS.bound_x, MOUS.bound_y )
PUB SPINGetDataIndex( guid ) | odx
'returns the zero based index of the currently displayed data item
odx := gz_elem[guid] & G_OMSK
return SPIN[odx].GetDataIndex
CON ''=====< CHECK BOX INTERFACE FUNCTIONS >==================================
PUB CHKBInit( pRow, pCol, pTextWidth, pTextPtr ) | idx, gdx, retVal
'Creates a checkbox box at the specified location.
'Something like:
'
' X Text here
'
' where X is a check box symbol
'
' pRow = row upper location
' pCol = col left location
' pTextWidth = width of button text (MAX 15 characters)
' pTextPtr = checkbox text (MAX 15 characters)
'
'Returns -1 if there are no more free elements in the CHKB object array
' guid on success which is unique and used to identify the specific
' instance of the control.
retVal := -1
repeat idx from 0 to GZ_CHKB - 1
gdx := CHKB[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
CHKB[idx].Init( pRow, pCol, pTextWidth, 0, pTextPtr, @scrn, VGACOLS )
quit
return retVal
PUB CHKBIsIn( guid ) | odx
' returns true if the mouse is inside the check box
' false otherwise
odx := gz_elem[guid] & G_OMSK
return CHKB[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB CHKBDrawText( guid, pMode ) | odx
' pMode 0 = 0 for normal
' = 1 for inverted
odx := gz_elem[guid] & G_OMSK
CHKB[odx].DrawText( pMode )
PUB CHKBSelect( guid, pSel ) | odx
'sel = 1 to select 0 to deselect -1 to toggle it
odx := gz_elem[guid] & G_OMSK
CHKB[odx].Select( pSel )
PUB CHKBIsSet( guid ) | odx
'returns the status of the button (set=true not set=false)
odx := gz_elem[guid] & G_OMSK
return CHKB[odx].isSet
CON ''=====< RADIO BUTTON INTERFACE FUNCTIONS >===============================
PUB RADBInit( pRow, pCol, pTextWidth, pTextPtr, pGroupID ) | idx, gdx, retVal
'Creates a radio button at the specified location.
'Something like:
'
' X Text here
'
' where X is a radio button symbol
'
' pRow = row upper location
' pCol = col left location
' pTextWidth = width of button text (MAX 15 characters)
' pTextPtr = checkbox text (MAX 15 characters)
' pGroupID = the id of the radio button group that this button belongs to
'
'Returns -1 if there are no more free elements in the RADB object array
' guid on success which is unique and used to identify the specific
' instance of the control.
retVal := -1
repeat idx from 0 to GZ_RADB - 1
gdx := RADB[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
RADB[idx].Init( pRow, pCol, pTextWidth, 1, pTextPtr, @scrn, VGACOLS )
gz_groups[idx] := pGroupID 'remember group button belongs to RB_GRP
quit
return retVal
PUB RADBIsIn( guid ) | odx
' returns true if the mouse inside the radio button
' false otherwise
odx := gz_elem[guid] & G_OMSK
return RADB[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB RADBDrawText( guid, pMode ) | odx
' pMode 0 = 0 for normal
' = 1 for inverted
odx := gz_elem[guid] & G_OMSK
RADB[odx].DrawText( pMode )
PUB RADBSelect( guid, pSel ) | odx
'sel = 1 to select 0 to deselect -1 to toggle it
odx := gz_elem[guid] & G_OMSK
RADB[odx].Select( pSel )
PUB RADBIsSet( guid ) | odx
'returns the status of the button (set=true not set=false)
odx := gz_elem[guid] & G_OMSK
return RADB[odx].isSet
CON ''=====< PUSH BUTTON INTERFACE FUNCTIONS >================================
PUB PUSHInit( pRow, pCol, pTextPtr ) | idx, gdx, retVal
'Creates a pushbutton at the specified location.
'Something like:
' ---------------
' |ttttttttttttttt|
' ---------------
'
' where t = button text (MAX 15 characters)
'
' pRow = row upper location
' pCol = col left location
' pTextPtr = push button text (MAX 15 characters + null terminator)
'
'Returns -1 if there are no more free elements in the PUSH object array
' guid on success which is unique and used to identify the specific
' instance of the control.
retVal := -1
repeat idx from 0 to GZ_PUSH - 1
gdx := PUSH[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
PUSH[idx].Init( pRow, pCol, pTextPtr, @scrn, VGACOLS )
quit
return retVal
PUB PUSHIsIn( guid ) | odx
' returns true if the mouse is inside the push button
' false otherwise
odx := gz_elem[guid] & G_OMSK
return PUSH[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB PUSHDrawText( guid, pMode ) | odx
'draws the pusbutton text in normal or inverted video.
' mode bit 0 = 0 for normal
' = 1 for inverted
odx := gz_elem[guid] & G_OMSK
PUSH[odx].DrawText( pMode )
PUB PUSHSetText( guid, pPtr ) | odx
'sets new text for the pushbutton
' pPtr points to the text, it MUST be the same size (or less) as the text
' it is replacing
odx := gz_elem[guid] & G_OMSK
PUSH[odx].SetText( pPtr )
CON ''=====< TEXT BOX INTERFACE FUNCTIONS >===================================
PUB TBOXInit( pRow, pCol, pWidth, pHeight, pWrap, pTitlePtr ) | idx, gdx, retVal
'Creates a box with specified width and text. Something like:
' -------------
' | | - title area ( non-existant if no title supplied)
' -------------
' | |
' | | - text area with optional scolling print capability
' | |
' -------------
'
' pRow = row upper location
' pCol = col left location
' pWidth = width
' pHeight = height
' pWrap = 0 = truncate 1 = wrap lines
' pTitlePtr = title text text (text must be 2 less than width ore 32 MAX)
'
'Returns -1 if there are no more free elements in the TBOX object array
' guid on success which is unique and used to identify the specific
' instance of the control.
'
' NOTE: Columns must be LONG aligned to take advantage of the most efficient
' scrolling (via LONGMOVE). The start column must be on a long boundary
' (multiple of 4) and the width must be a multiple of 4. If print scrolling
' is not required this restriction can be ignored.
retVal := -1
repeat idx from 0 to GZ_TBOX - 1
gdx := TBOX[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
TBOX[idx].Init( pRow, pCol, pWidth, pHeight, pWrap, pTitlePtr, @scrn, VGACOLS )
quit
return retVal
PUB TBOXIsIn( guid ) | odx
' returns true if the mouse is inside the text box text area
' (i.e. excluding title area if there is one)
' false otherwise
odx := gz_elem[guid] & G_OMSK
return TBOX[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB TBOXClear( guid ) | odx
'clears the text box.
odx := gz_elem[guid] & G_OMSK
TBOX[odx].Clear
PUB TBOXPrint( guid, pTxtPtr, pSize ) | odx
'Prints a line of text. Iif already at the last row the existing text is
'scrolled up one line first and the top line is removed. Inverted text is
'written with the high bit of each character set. If line wrap is enabled the
'lines that are wrapped are marked with a preceding inverted right arrow
'character (non-printable Ascii). Leading and trailing CRLF characters are
'stripped out. Any intra line CRLFs are ignored and will display as 'funny'
'characters.
'
' pTxtPtr = pointer to null terminated string
' size = 0 for null terminated strings
' = the string length for non-null terminated strings
odx := gz_elem[guid] & G_OMSK
TBOX[odx].Print( pTxtPtr, pSize )
PUB TBOXScroll( guid ) | odx
'scroll the test area up one line
odx := gz_elem[guid] & G_OMSK
TBOX[odx].Scroll
PUB TBOXTitle( guid, pTxtPtr ) | strIdx, vgaIdx, odx
'replace the original titlebar caption with new text. If no title was declared
'on initialization then this method will do nothing
'
' pTxtPtr = pointer to text to place in titlebar
odx := gz_elem[guid] & G_OMSK
TBOX[odx].Title( pTxtPtr )
CON ''=====< MENU ITEM INTERFACE FUNCTIONS >==================================
PUB MENUInit( pRow, pCol, pTextPtr ) | idx, gdx, retVal
'Creates a menu item at the specified location.
'Something like:
' StttttttttttttttS
'
' where S = space character
' t = character position (MAX 15 characters)
'
' pRow = row upper location
' pCol = col left location
' pTextPtr = menu item text (MAX 15 characters + null terminator)
'
'Returns -1 if there are no more free elements in the MENU object array
' guid on success which is unique and used to identify the specific
' instance of the control.
retVal := -1
repeat idx from 0 to GZ_MENU - 1
gdx := MENU[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
MENU[idx].Init( pRow, pCol, pTextPtr, @scrn, VGACOLS )
quit
return retVal
PUB MENUIsIn( guid ) | odx
' returns true if the mouse is inside the menu item
' false otherwise
odx := gz_elem[guid] & G_OMSK
return MENU[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB MENUDrawText( guid, pMode ) | odx
'draws the menu item text in normal or inverted video.
' mode bit 0 = 0 for normal
' = 1 for inverted
odx := gz_elem[guid] & G_OMSK
MENU[odx].DrawText( pMode )
PUB MENUSetText( guid, pPtr ) | odx
'Place new text on the menu item.
' pPtr points to the text, it MUST be the same size (or less) as the text
' it is replacing
odx := gz_elem[guid] & G_OMSK
MENU[odx].SetText( pPtr )
PUB MENUSetStatus( guid, pStat ) | odx
'set a user defined status BYTE (any value fro 0 to 255)
odx := gz_elem[guid] & G_OMSK
MENU[odx].SetStatus( pStat )
PUB MENUGetStatus( guid ) | odx
'get the use defined status
odx := gz_elem[guid] & G_OMSK
return MENU[odx].GetStatus
CON ''=====< INPUT FIELD INTERFACE FUNCTIONS >================================
PUB INPFInit(pRow, pCol, pWidth, pType, pTitlePtr ) | idx, gdx, retVal
'Creates an input field box with specified width and text. Something like:
' -----------------------
' |Title| input field |
' -----------------------
'
' pRow = row upper location
' pCol = col left location
' pWidth = width of the control in columns
' pType = 0 = standalone 1=tacked on to above
' pHeight = height of the control in rows
' pTitlePtr = title text ( remainder is used for the input field )
'
'Returns -1 if there are no more free elements in the SPIN object array
' guid on success which is unique and used to identify the specific
' instance of the control.
retVal := -1
repeat idx from 0 to GZ_INPF - 1
gdx := INPF[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
INPF[idx].Init( pRow, pCol, pWidth, pType, pTitlePtr, @scrn, VGACOLS )
quit
return retVal
PUB INPFIsIn( guid ) | odx
' returns true if the mouse is inside the input field
' false otherwise
odx := gz_elem[guid] & G_OMSK
return INPF[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB INPFClear( guid ) | odx
'clear the input field
odx := gz_elem[guid] & G_OMSK
INPF[odx].clear
PUB INPFSelect( guid, pSel ) | odx
'pSel = 1 to select 0 to deselect -1 to toggle it
odx := gz_elem[guid] & G_OMSK
INPF[odx].Select( pSel, @cx1, @cy1 )
liveINPF := odx
cm1 := %111 'turn text cursor on, underscore slow blink
PUB INPFGetString( guid, pBuf ) | odx, tmp, str, len
'places the string in the input field into the buffer provided then clears
'the input field.
odx := gz_elem[guid] & G_OMSK
tmp := INPF[odx].GetStringCode
str := ( tmp & $1FFF0000 ) >> 16
len := tmp & $000000FF
bytemove( pBuf, @scrn.byte[str], len )
byte[pBuf][len] := 0
INPFClear( guid )
CON ''=====< STATUS LAMP INTERFACE FUNCTIONS >================================
PUB STATInit( pRow, pCol, pWidth, pTitlePtr ) | idx, gdx, retVal
'Creates a status lamp with specified width and text. Something like:
'
' Title : XXXX
'
' where XXXX is user supplied condition status
'
' pRow = row upper location
' pCol = col left location
' pWidth = width of the control in columns
' pHeight = height of the control in rows
' pTitlePtr = title text text (text must be 7 less than width )
'
'Returns -1 if there are no more free elements in the SPIN object array
' guid on success which is unique and used to identify the specific
' instance of the control.
retVal := -1
repeat idx from 0 to GZ_STAT - 1
gdx := STAT[idx].get_gzidx
if gz_elem[gdx] & G_INIT == 0 'is it free
retVal := gdx
gz_elem[gdx] |= G_INIT 'mark it used
STAT[idx].Init( pRow, pCol, pWidth, pTitlePtr, @scrn, VGACOLS )
quit
return retVal
PUB STATIsIn( guid ) | odx
' returns true if the mouse is inside the menu item
' false otherwise
odx := gz_elem[guid] & G_OMSK
return STAT[odx].IsIn( MOUS.bound_x, MOUS.bound_y )
PUB STATSet( guid, pSet, pStrPtr ) | odx
'pSet = 0 = off mode (uses normal video)
' 1 = on mode (uses inverted video)
'pStr = pointer to status string (4 chars max)
odx := gz_elem[guid] & G_OMSK
STAT[odx].Set( pSet, pStrPtr )
PUB STATGetStatus( guid ) | odx
'returns the current status of the object (1=on 0=off)
odx := gz_elem[guid] & G_OMSK
return STAT[odx].GetStatus
CON ''===== START OF VGA HIGH RES TEXT SCREEN FUNCTIONS ======================
PUB PrintStr( prRow, prCol, strPtr, inv ) | strLen, vgaIdx, idx
'this places text anywhere on the screen and can overwrite UI elements
'
' prRow = row
' prCol = column
' strPtr = pointer to null terminated string
' inv = 0 for normal 1 for inverted video
if ( prRow < VGAROWS ) AND ( prCol < VGACOLS )
strLen := strsize( strPtr )
vgaIdx := prRow * VGACOLS + prCol
bytemove( @scrn.byte[vgaIdx], strPtr, strLen )
if inv
repeat idx from 1 to strLen
byte[@scrn][vgaIdx] += 128
vgaIdx++
PUB ClearScreen( ForeClr, BackClr ) | wdClr
' This clears the whole screen and sets all rows to the given colours
' ForeClr and BackClr are best represented as quaternary numbers (base 4)
' - these are represented as %%RGB where there are 4 levels for each ( R, G, B)
' - thus entering %%003 is brightest Green
wdClr := BackClr << 10 + ForeClr << 2
LONGFILL( @scrn, $20202020, VGACOLS*VGAROWS/4 ) '4 space characters in long
WORDFILL( @colors, wdClr, VGAROWS )
PUB SetLineColor( line, ForeClr, BackClr ) | wdClr
' This sets a single row to the given colours
' ForeClr and BackClr are best represented as quaternary numbers (base 4)
' - these are represented as %%RGB where there are 4 levels for each ( R, G, B)
' - thus entering %%003 is brightest Green
if line < VGAROWS
wdClr := BackClr << 10 + ForeClr << 2
colors[line] := wdClr
{{
┌────────────────────────────────────────────────────────────────────────────┐
│ TERMS OF USE: MIT License │
├────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy│
│of this software and associated documentation files (the "Software"), to │
│deal in the Software without restriction, including without limitation the │
│rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │
│sell copies of the Software, and to permit persons to whom the Software is │
│furnished to do so, subject to the following conditions: │
│ │
│The above copyright notice and this permission notice shall be included in │
│all copies or substantial portions of the Software. │
│ │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │
│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │
│FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │
│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │
│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │
│FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS│
│IN THE SOFTWARE. │
└────────────────────────────────────────────────────────────────────────────┘
}}