Slide 9.3: Menu demonstrations (cont.)
  Slide 9.5: Line-by-line anatomy of Menu.c
  Home


Menu.c


The following C program is for the application on the previous slides.

 Menu.c 

#include  <PalmOS.h>
#include  <PalmCompatibility.h>
#include  "Menu.h"

// This application requires PalmOS 2.0 or later.
#define  ROM_VERSION_REQUIRED  0x02000000	

// Nb or recs in DB
#define  MAX_REC  5

struct  dbase {
  char	*firstName;
  char	*lastName;
  char	*instrument;
}  db[ ] = 
{
  {"Keith", "Jarrett"    , "Piano"},
  {"Gary" , "Peacock"    , "Bass"},
  {"Jack" , "De Johnette", "Drums"},
  {"Jacky", "Terrasson"  , "Piano"},
  {"Jaco" , "Pastorius"  , "Electric bass"}
};

UInt16  curRec = 0;


/***********************************************************************
*                                                                      *
*                This function sets a field value.                     *
*                                                                      *
***********************************************************************/

static FieldPtr  SetField( UInt16 formID, UInt16 fieldID, MemPtr str ) {
  FormPtr   frm;
  FieldPtr  fld;
  UInt16    obj;
  CharPtr   p;
  VoidHand  h;
  
  frm = FrmGetFormPtr( formID );
  obj = FrmGetObjectIndex( frm, fieldID );
  fld = (FieldPtr) FrmGetObjectPtr( frm, obj );
  h   = (VoidHand) FldGetTextHandle( fld );

  if ( h == NULL ) {
    h = MemHandleNew( FldGetMaxChars( fld ) + 1 );
    ErrFatalDisplayIf( !h, "No Memory" );
  }
  p = (CharPtr) MemHandleLock( h );
  StrCopy( p, str );
  MemHandleUnlock( h );
  FldSetTextHandle( fld, (Handle) h );
}


/***********************************************************************
*                                                                      *
*                This function sets a record value.                    *
*                                                                      *
***********************************************************************/

static void  SelectRecord( UInt16 id ) {
  char cursor[20];
  
  StrPrintF  ( cursor, "%2d/%-2d", curRec+1, MAX_REC );
  SetField   ( MainForm, MainFirstName , db[id].firstName );
  SetField   ( MainForm, MainLastName  , db[id].lastName );
  SetField   ( MainForm, MainInstrument, db[id].instrument );
  SetField   ( MainForm, MainCursor    , cursor );
  FrmDrawForm( FrmGetFormPtr( MainForm ) );
}


/***********************************************************************
*                                                                      *
*            This function gets the focus object pointer.              *
*                                                                      *
***********************************************************************/

static FieldPtr  GetFocusObjectPtr( void ) {
  FormPtr         frm;
  UInt16          focus;
  FormObjectKind  objType;
  
  frm   = FrmGetActiveForm( );
  focus = FrmGetFocus( frm );
  if ( focus == noFocus )   return( NULL );
  objType = FrmGetObjectType( frm, focus );
  
  if ( objType == frmFieldObj )
    return( FrmGetObjectPtr( frm, focus ) );
  else if ( objType == frmTableObj )
    return( TblGetCurrentField( FrmGetObjectPtr( frm, focus ) ) );
    
  return ( NULL );
}


/***********************************************************************
*                                                                      *
*                This function processes the events.                   *
*                                                                      *
***********************************************************************/

static Boolean  MainFormHandleEvent( EventPtr event ) {
  Boolean   handled = false;
  FieldPtr  fld;

  switch (event->eType) {

    // if the form is opened
    case  frmOpenEvent:
      if ( event->data.frmOpen.formID == MainForm )
        SelectRecord( curRec );
      handled = true;
      break;

    // if the menu is used  
    case  menuEvent:
      MenuEraseStatus( NULL );
      switch ( event->data.menu.itemID ) {
        case  MainRecord1Cmd:
        case  MainRecord2Cmd:
        case  MainRecord3Cmd:
        case  MainRecord4Cmd:
        case  MainRecord5Cmd:
          SelectRecord( curRec = event->data.menu.itemID-MainRecord1Cmd );
          handled = true;
	  break;
	      
        case  MainEditClearCmd:
          if ( fld = GetFocusObjectPtr( ) )
	    FldDelete( fld, 0, FldGetTextLength( fld ) );
          handled = true;
          break;

        case  MainEditCopyCmd:
          if ( fld = GetFocusObjectPtr( ) )   FldCopy( fld );
          handled = true;
          break;

        case  MainEditCutCmd:
	  if ( fld = GetFocusObjectPtr( ) )   FldCut( fld );
	  handled = true;
          break;

	case  MainEditPasteCmd:
          if ( fld = GetFocusObjectPtr( ) )   FldPaste( fld );
	  handled = true;
	  break;

	case  MainEditSelectAllCmd:
          if ( fld = GetFocusObjectPtr( ) )
	    FldSetSelection( fld, 0, FldGetTextLength( fld ) );
	  handled = true;
	  break;

	case  MainOptionsHelpCmd:
          (void) FrmAlert( HelpAlert );
	  handled = true;
	  break;
	          
	case  MainOptionsAboutCmd:
	  (void) FrmAlert( AboutAlert );
	  handled = true;
	  break;
			    
	default:
	  break;
      }
    break;

    // if one of the four buttons is clicked on    
    case  ctlSelectEvent:
      switch ( event->data.ctlSelect.controlID ) {
        case  MainFirstRec:
	  SelectRecord( curRec = 0 );
	  handled = true;
	  break;

        case  MainPrevRec:
          if ( curRec > 0 )   SelectRecord( --curRec );
	  handled = true;
	  break;

        case  MainNextRec:
          if ( curRec < MAX_REC-1 )   SelectRecord( ++curRec );
	  handled = true;
	  break;

        case  MainLastRec:
          SelectRecord( curRec = MAX_REC-1 );
	  handled = true;
	  break;

        default:
          break;
      }
      break;
      
    // if Graffiti is used to process the Record menu
    case  keyDownEvent:
      switch ( event->data.keyDown.chr ) {
        case  vchrPageDown:
	  if ( curRec > 0 )   SelectRecord( --curRec );
          handled = true;
	  break;

        case  vchrPageUp:
          if ( curRec < MAX_REC-1 )   SelectRecord( ++curRec );
	  handled = true;
	  break;

        default:
          break;
      }
      break;
      
    case  penDownEvent:
      break;
      
    case  penUpEvent:
      break;
      
    case  frmCloseEvent:
      break;
      
    case  nilEvent:
      break;
      
    default:
      break;
  }
  return ( handled );
}


static Boolean  AppHandleEvent( EventPtr event ) {
  FormPtr  frm;
  Int      formId;
  Boolean  handled;

  handled = false;
  if ( event->eType == frmLoadEvent ) {
    formId = event->data.frmLoad.formID;
    frm    = FrmInitForm( formId );
    FrmSetActiveForm( frm );

    switch ( formId ) {
      case  MainForm:
        FrmSetEventHandler( frm, MainFormHandleEvent );
        handled = true;
        break;
      
      default:
        break;
    }
  }
  return( handled );
}


static void  AppStart( ) {
  FrmGotoForm( MainForm );
}


static void  AppEventLoop( void ) {
  EventType  event;
  short      error;

  do {
    EvtGetEvent( &event, 100 );
    if ( SysHandleEvent( &event ) )
      continue;
    if ( MenuHandleEvent( ( void *) 0, &event, &error ) )
      continue;
    if ( AppHandleEvent( &event ) )
      continue;
    FrmDispatchEvent( &event );
  }
  while ( event.eType != appStopEvent );
}


static void  AppStop( ) {
  FrmCloseAllForms( );
}


UInt32  PilotMain( UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags ) {
  UInt32 romVersion;

  FtrGet( sysFtrCreator, sysFtrNumROMVersion, &romVersion );
  // Minimal ROM version requirement
  if ( romVersion < ROM_VERSION_REQUIRED ) {
    FrmAlert( RomIncompatibleAlert );
    return  ( sysErrRomIncompatible );
  }

  if ( cmd == sysAppLaunchCmdNormalLaunch ) {
    // Normal launch
    AppStart( );
    AppEventLoop( );
    AppStop( );
  }
  return ( 0 );
}