GLCDMenu

Porting to GLCD from original source LCD Menu where you will find also the tools to edit and create the user menu definition module including the documentation on the use of the module.

Now you can move the menu using the Initialize routine :


Sub Initialise(pItemActionEvent As TEvent, 
               XMnuPos As Byte = 20, 
               YMnuPos As Byte = 10, 
               YMnuStep As Byte = 10, 
               XMnuCurs As Byte = 10 )

where you can set the distance between the lines of the menu by the variable YMnuStep and the x position of the cursor by XMnuCurs.

The module is suitable for use with GLCD with higher resolution like 320x240 as the S1D13700 where is used the layer 1 by default.

{
********************************************************************************
*  Name    : GLCDMenu                                                          *
*  Author  : AndyO,                                                            *
*  Notice  : Copyright (c) AndyO, xva3rjy                                      *
*  Date    : 13/07/2008                                                        *
*          : 14/11/2014 Porting to GLCD                                        *
*  Version : 1.0                                                               *
*  Notes   : See doc "LCD Menu Module.pdf"                                     *
*          : Menu data stored in Const arrays which are declared in seperate   *
*          : module indicated by #define MenuDataModule = "filename.BAS" in    *
*          : main program                                                      *
*          : Porting in GLCD version from original source by Andy0             *
*                                                                              *  
* Original LCD source:                                                         * 
* http://www.sfcompiler.co.uk/wiki/pmwiki.php?n=SwordfishUser.LCDMenuModule    *
********************************************************************************
}

Module GLCDMenu 
Include "GLCD.bas"

#ifdef MenuDataModule
    Include MenuDataModule
#else
    #error "No MenuDataModule defined in main program"
#endif

#option Menu_LCDLines = 4                   'Number of lines on LCD display
#option Menu_ShowMenuTitle = True           'Display Menu Name at top of screen?
#option Menu_ShowScrollIndicators = True    'Show up and down scroll indicators?
#option Menu_ScrollWrapping = False         'Scroll wraps from top to bottom?
#option Menu_PointerCharacter = 126         'Character used as pointer


#if Menu_LCDLines = 1 And Menu_ShowMenuTitle = True
    #error "Cannot show menu titles on 1 line LCD"
#endif

Type TEvent = Event()

Private Const
    LCDLines As Byte            = Menu_LCDLines,
    PointerCharacter As Byte    = Menu_PointerCharacter


#If Menu_ShowScrollIndicators = True
    'Character definitions for Up Arrow and Down Arrow scroll indicators
    Private Const ScrollIndicators(16) As Byte=($04,$0E,$1F,$00,$00,$00,$00,$00,
                                                $00,$00,$00,$00,$00,$1F,$0E,$04)

    Private Const UpArrow = 0
    Private Const DownArrow = 1
#EndIf


Private Dim FItemActionEvent As TEvent  'Holds pointer to event code in main
                                        'program which is run when an "action"
                                        'menu item is selected

Private Dim PointerPosition As Byte     'Position of pointer character (0 = 1st) 
Private Dim PointerLine As Byte         'Actual LCD line of pointer        
Private Dim ScrollPosition As Byte      'Number of lines the menu is scrolled by

Private Dim CurrentMenu As Byte         'Index number of current menu
Private Dim ParentID As Byte            'Index number of parent of current menu
Private Dim FirstItemNumber As Byte     'First item number for current menu
Private Dim LastItemNumber As Byte      'Last item number for current menu

Public Dim SelectedMenuItem As Byte     'Index number of selected menu item

'===============================================================================
'Name:      DrawMenu(pMenuNumber as byte)      
'Purpose:   Draws current menu, scrolled by ScrollPosition amount
'                 
Private Dim 
    xPos As Byte, 
    yPos As Byte, 
    yStep As Byte,
    xCurs As Byte 

Dim LineNumber As Byte              'Line number of LCD to write at

Private Function GetYPos(p As Byte = 0) As Byte
    If p<>0 Then 
        result = yPos  + (p - 1) * yStep
    Else
        result = yPos  + (LineNumber - 1) * yStep
    End If
End Function

Private Sub DrawMenu()
    Dim ItemNumber As Byte              'Index of menu item number to write

#If Menu_ScrollWrapping = True           
    Dim ItemsDrawn As Byte                  
    ItemsDrawn = 0                          
#EndIf


#if GLCD_MODEL = S1D13700
    GLCD.Cls(1)
#else    
    GLCD.Cls()
#endif    

    LineNumber = 1
    ItemNumber = FirstItemNumber + ScrollPosition

    #If Menu_ShowMenuTitle = True               
        GLCD.WriteStr(xPos, GetYPos() , mnuMenuName(CurrentMenu))
        LineNumber = 2        
    #Endif

    Repeat
        GLCD.WriteStr(xPos, GetYPos() , mnuItemName(ItemNumber))
        Inc(LineNumber)
        Inc(ItemNumber)
    #If Menu_ScrollWrapping = True
        Inc(ItemsDrawn)
        If ItemNumber > LastItemNumber Then 
            ItemNumber = FirstItemNumber    
        EndIf                               

    Until LineNumber > LCDLines Or ItemsDrawn > LastItemNumber - FirstItemNumber

    #Else

    Until LineNumber > LCDLines Or ItemNumber > LastItemNumber

    #EndIf


    #If Menu_ShowScrollIndicators = True
        #If Menu_ScrollWrapping = True
            #If Menu_ShowMenuTitle = True
                If LastItemNumber - FirstItemNumber > LCDLines - 1 Then
                    GLCD.WriteAt(xCurs, GetYPos(LCDLines) , DownArrow)
                    GLCD.WriteAt(xCurs, GetYPos(2) , UpArrow)
            #Else
                If LastItemNumber - FirstItemNumber > LCDLines Then                
                    GLCD.WriteAt(xCurs, GetYPos(LCDLines) , DownArrow)
                    GLCD.WriteAt(xCurs, GetYPos(1) , UpArrow)                    
            #EndIf
                EndIf
        #Else
            If ItemNumber - 1 < LastItemNumber Then
                GLCD.WriteAt(xCurs, GetYPos(LCDLines) , DownArrow)
            EndIf
            If ScrollPosition > 0 Then
                #If Menu_ShowMenuTitle = True
                    GLCD.WriteAt(xCurs, GetYPos(2) , UpArrow)
                #Else
                    GLCD.WriteAt(xCurs, GetYPos(1) , UpArrow)
                #EndIf
            EndIf
        #EndIf
    #EndIf
End Sub



'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name:      DrawPointer(pOldPosition as byte)      
'Purpose:   Deletes pointer at pOldPosition and draws pointer at PointerPosition
'Notes:     When pointer is at first menu item on screen, PointerPosition = 0
'           Pointer character determined by option "Menu_PointerCharacter",
'           default = 126 (right arrow)

Private Sub DrawPointer(pOldPosition As Byte)
    'Actual LCD line which pointer is drawn on depends on whether
    'Menu_ShowMenuTitle is enabled or not 
    #If Menu_ShowMenuTitle Then
        PointerLine = PointerPosition + 2
        GLCD.WriteAt(xCurs, GetYPos(pOldPosition + 2) , " ")
        GLCD.WriteAt(xCurs, GetYPos(PointerLine) , PointerCharacter)
    #Else
        PointerLine = PointerPosition + 1
        GLCD.WriteAt(xCurs, GetYPos(pOldPosition + 1) , " ")
        GLCD.WriteAt(xCurs, GetYPos(PointerLine) , PointerCharacter)
    #EndIf
End Sub



'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name:      ShowMenu(pMenuNumber as byte = 0)      
'Purpose:   Display specified menu on LCD

Public Sub ShowMenu(pMenuNumber As Byte = 0)
    'Reset scroll and pointer positions
    ScrollPosition = 0
    PointerPosition = 0
    CurrentMenu = pMenuNumber
    ParentID = mnuParentMenuID(CurrentMenu)
    FirstItemNumber = mnuMenuItemStart(CurrentMenu)
    LastItemNumber = mnuMenuItemEnd(CurrentMenu)
    DrawMenu
    DrawPointer(0)
End Sub



'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name:      MoveDown()      
'Purpose:   Move pointer to next menu item, scrolling the menu if necessary

Public Sub MoveDown()
    Dim CanScroll As Boolean
    'First, determine if the menu can be scrolled down and set CanScroll -
    '
    '   If Scroll Wrapping Not Enabled: Menu may only be scrolled down if the
    '   number of menu items left to display won't fit on the number of
    '   available LCD lines
    '
    '   Note: Number of available lines depends on whether Menu_ShowMenuTitle is
    '   enabled or not
    '
    '   If Scroll Wrapping Enabled: Can always scroll down

    #If Menu_ScrollWrapping = False
        CanScroll = False
        #If Menu_ShowMenuTitle = True Then
            If FirstItemNumber + ScrollPosition + LCDLines - 2 < LastItemNumber Then
                CanScroll = True
            EndIf
        #Else
            If FirstItemNumber + ScrollPosition + LCDLines - 1 < LastItemNumber Then
                CanScroll = True
            EndIf
        #EndIf
    #Else
        CanScroll = True
    #EndIf


    'Scroll the menu if the following conditions exist -
    '
    '   Menu can be scrolled down and pointer is on or below the second last
    '   line of the display
    '   OR
    '   Menu can be scrolled down and pointer is on the last menu item - this
    '   allows scroll wrapping

    If (PointerLine >= LCDLines - 1 Or PointerPosition = LastItemNumber - FirstItemNumber) And CanScroll = True Then
        Inc(ScrollPosition)
        #If Menu_ScrollWrapping = True
            'If scroll wrapping and we've scrolled to the bottom then start again at
            'the top
            If ScrollPosition > (LastItemNumber - FirstItemNumber) Then
                ScrollPosition = 0
            EndIf
        #EndIf
        DrawMenu()
        DrawPointer(PointerPosition)

    'If not scrolling the menu then move the pointer down if the following
    'conditions exist -
    '
    '   Pointer is not on the last line of the display
    '   AND
    '   Pointer isn't on the last menu item

    ElseIf PointerLine < LCDLines And PointerPosition + FirstItemNumber + ScrollPosition < LastItemNumber Then
        Inc(PointerPosition)
        'Fix to ensure Up Arrow scroll indicator is shown on smaller displays
        'when pointer moves down from top line 
        #If (Menu_LCDLines < 4 Or Menu_ScrollWrapping = True) And Menu_ShowScrollIndicators = True
            DrawMenu()
            DrawPointer(PointerPosition)
        #Else
            DrawPointer(PointerPosition - 1)
        #EndIf
    End If    
End Sub



'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name:      MoveUp()      
'Purpose:   Move pointer to previous menu item, scrolling menu if necessary

Public Sub MoveUp()

    'Routine decides whether to scroll the menu up or just move the pointer up
    'depending on the current state:
    '
    'If there is a free LCD line above the pointer (i.e. one that doesn't have
    'the menu title or a scroll indicator in it then move the pointer up;
    '
    'Otherwise, if the menu can be scrolled (either because scroll wrapping is
    'on or because the current scroll position > 0) then scroll the menu up;
    '
    'If the menu can't be scrolled then move the pointer up, overwriting any
    'scroll-up indicator.  (If necessary, re-draw the scroll-down indicator).

    #If Menu_ShowMenuTitle = True
        #If Menu_ShowScrollIndicators = True
            If PointerLine > 3 Then
        #Else
            If PointerLine > 2 Then
        #EndIf
                Dec(PointerPosition)
                DrawPointer(PointerPosition + 1)
        #If Menu_ScrollWrapping = True
            Else
                If ScrollPosition > 0 Then
                    Dec(ScrollPosition)
                Else
                    ScrollPosition = LastItemNumber - FirstItemNumber
                EndIf
                DrawMenu()
                DrawPointer(PointerPosition)
            EndIf
        #Else                
            ElseIf ScrollPosition > 0 Then
                Dec(ScrollPosition)
                DrawMenu()
                DrawPointer(PointerPosition)
            ElseIf PointerLine > 2 Then
                Dec(PointerPosition)
                #If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
                    DrawMenu()
                    DrawPointer(PointerPosition)
                #Else
                    DrawPointer(PointerPosition + 1)
                #EndIf
            EndIf
        #EndIf
    #Else
        #If Menu_ShowScrollIndicators = True
            If PointerLine > 2 Then
        #Else
            If PointerLine > 1 Then
        #EndIf
                Dec(PointerPosition)
                DrawPointer(PointerPosition + 1)


        #If Menu_ScrollWrapping = True
            Else
                If ScrollPosition > 0 Then
                    Dec(ScrollPosition)
                Else
                    ScrollPosition = LastItemNumber - FirstItemNumber
                EndIf
                DrawMenu()
                DrawPointer(PointerPosition)
            EndIf
        #Else                        
            ElseIf ScrollPosition > 0 Then
                Dec(ScrollPosition)
                DrawMenu()
                DrawPointer(PointerPosition)
            ElseIf PointerLine > 1 Then
                Dec(PointerPosition)
                #If Menu_LCDLines < 4 And Menu_ShowScrollIndicators = True
                    DrawMenu()
                    DrawPointer(PointerPosition)
                #Else
                    DrawPointer(PointerPosition + 1)
                #EndIf
            EndIf
        #EndIf
    #EndIf
End Sub



'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name:      Back()      
'Purpose:   Show parent of current menu

Public Sub Back()
    ShowMenu(ParentID)
End Sub



'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name:      SelectItem()      
'Purpose:   Carries out action of selected menu item.  If menu item opens
'           another menu then that menu is drawn.  If menu item is an 'action'
'           item then the event in the main program which handles the action is
'           called

Public Sub SelectItem()
    Dim ItemAction As Byte
    SelectedMenuItem = FirstItemNumber + ScrollPosition + PointerPosition
    #If Menu_ScrollWrapping = True
        If SelectedMenuItem > LastItemNumber Then
            SelectedMenuItem = SelectedMenuItem - (LastItemNumber - FirstItemNumber) - 1
        EndIf
    #EndIf
    ItemAction = mnuItemAction(SelectedMenuItem)
    If ItemAction = 255 Then
        ParentID = CurrentMenu 'Means 'back' command will return to correct menu
        FItemActionEvent()     'Call event handler in main program
    Else
        ShowMenu(ItemAction)    
    EndIf
End Sub



'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Name:      Initialise(pItemActionEvent as TEvent)      
'Purpose:   Sets name of main program event handler and loads custom scroll
'           characters into LCD

Public Sub Initialise(pItemActionEvent As TEvent, 
                      XMnuPos As Byte = 20, 
                      YMnuPos As Byte = 10, 
                      YMnuStep As Byte = 10, 
                      XMnuCurs As Byte = 10 )
    xPos = XMnuPos
    yPos = YMnuPos 
    yStep = YMnuStep
    xCurs = XMnuCurs

    FItemActionEvent = pItemActionEvent
End Sub