contacts.c
来自「CD_《Palm OS编程实践》」· C语言 代码 · 共 1,566 行 · 第 1/3 页
C
1,566 行
// CH.2 The super-include for the Palm OS
#include <Pilot.h>
// CH.5 Added for the call to GrfSetState()
#include <Graffiti.h>
// CH.3 Our resource file
#include "Contacts_res.h"
// CH.4 Prototypes for our event handler functions
static Boolean contactDetailHandleEvent( EventPtr event );
static Boolean aboutHandleEvent( EventPtr event );
static Boolean enterTimeHandleEvent( EventPtr event );
static Boolean contactListHandleEvent( EventPtr event );
static Boolean menuEventHandler( EventPtr event );
// CH.4 Constants for ROM revision
#define ROM_VERSION_2 0x02003000
#define ROM_VERSION_MIN ROM_VERSION_2
// CH.5 Prototypes for utility functions
static void newRecord( void );
static VoidPtr getObject( FormPtr, Word );
static void setFields( void );
static void getFields( void );
static void setText( FieldPtr, CharPtr );
static void getText( FieldPtr, VoidPtr, Word );
static void setDateTrigger( void );
static void setTimeTrigger( void );
static void setTimeControls( void );
static Int sortFunc( CharPtr, CharPtr, Int );
static void drawTable( void );
static void drawCell( VoidPtr table, Word row, Word column,
RectanglePtr bounds );
// CH.5 Our open database reference
static DmOpenRef contactsDB;
static ULong numRecords;
static UInt cursor;
static Boolean isDirty;
static VoidHand hrecord;
// CH.5 Constants that define the database record
#define DB_ID_START 0
#define DB_ID_SIZE (sizeof( ULong ))
#define DB_DATE_TIME_START (DB_ID_START +\
DB_ID_SIZE)
#define DB_DATE_TIME_SIZE (sizeof( DateTimeType ))
#define DB_FIRST_NAME_START (DB_DATE_TIME_START +\
DB_DATE_TIME_SIZE)
#define DB_FIRST_NAME_SIZE 16
#define DB_LAST_NAME_START (DB_FIRST_NAME_START +\
DB_FIRST_NAME_SIZE)
#define DB_LAST_NAME_SIZE 16
#define DB_PHONE_NUMBER_START (DB_LAST_NAME_START +\
DB_LAST_NAME_SIZE)
#define DB_PHONE_NUMBER_SIZE 16
#define DB_RECORD_SIZE (DB_PHONE_NUMBER_START +\
DB_PHONE_NUMBER_SIZE)
// CH.6 Storage for the record's date and time in expanded form
static DateTimeType dateTime;
static Word timeSelect;
#define NO_DATE 0
#define NO_TIME 0x7fff
// CH.7 The error exit macro
#define errorExit(alert) { ErrThrow( alert ); }
// CH.7 The sort order variable and constants
static Int sortBy;
// CH.7 NOTE: These items match the popup list entries!
#define SORTBY_DATE_TIME 0
#define SORTBY_FIRST_NAME 1
#define SORTBY_LAST_NAME 2
// CH.8 Table constants
#define TABLE_NUM_COLUMNS 3
#define TABLE_NUM_ROWS 11
#define TABLE_COLUMN_DATE 0
#define TABLE_COLUMN_TIME 1
#define TABLE_COLUMN_NAME 2
#define BLACK_UP_ARROW "\x01"
#define BLACK_DOWN_ARROW "\x02"
#define GRAY_UP_ARROW "\x03"
#define GRAY_DOWN_ARROW "\x04"
// CH.2 The main entry point
DWord PilotMain( Word cmd, Ptr, Word )
{
DWord romVersion; // CH.4 ROM version
FormPtr form; // CH.2 A pointer to our form structure
EventType event; // CH.2 Our event structure
Word error; // CH.3 Error word
// CH.4 Get the ROM version
romVersion = 0;
FtrGet( sysFtrCreator, sysFtrNumROMVersion, &romVersion );
// CH.4 If we are below our minimum acceptable ROM revision
if( romVersion < ROM_VERSION_MIN )
{
// CH.4 Display the alert
FrmAlert( LowROMVersionErrorAlert );
// CH.4 PalmOS 1.0 will continuously re-launch this app
// unless we switch to another safe one
if( romVersion < ROM_VERSION_2 )
{
AppLaunchWithCommand( sysFileCDefaultApp,
sysAppLaunchCmdNormalLaunch, NULL );
}
return( 0 );
}
// CH.2 If this is not a normal launch, don't launch
if( cmd != sysAppLaunchCmdNormalLaunch )
return( 0 );
// CH.5 Create a new database in case there isn't one
if( ((error = DmCreateDatabase( 0, "ContactsDB-PPGU", 'PPGU', 'ctct',
false )) != dmErrAlreadyExists) && (error != 0) )
{
// CH.5 Handle db creation error
FrmAlert( DBCreationErrorAlert );
return( 0 );
}
// CH.5 Open the database
contactsDB = DmOpenDatabaseByTypeCreator( 'ctct', 'PPGU',
dmModeReadWrite );
// CH.5 Get the number of records in the database
numRecords = DmNumRecords( contactsDB );
// CH.5 Initialize the record number
cursor = 0;
// CH.7 Choose our starting page
// CH.5 If there are no records, create one
if( numRecords == 0 )
{
newRecord();
FrmGotoForm( ContactDetailForm );
}
else
FrmGotoForm( ContactListForm );
// CH.7 Begin the try block
ErrTry {
// CH.2 Our event loop
do
{
// CH.2 Get the next event
EvtGetEvent( &event, -1 );
// CH.2 Handle system events
if( SysHandleEvent( &event ) )
continue;
// CH.3 Handle menu events
if( MenuHandleEvent( NULL, &event, &error ) )
continue;
// CH.4 Handle form load events
if( event.eType == frmLoadEvent )
{
// CH.4 Initialize our form
switch( event.data.frmLoad.formID )
{
// CH.4 Contact Detail form
case ContactDetailForm:
form = FrmInitForm( ContactDetailForm );
FrmSetEventHandler( form, contactDetailHandleEvent );
break;
// CH.4 About form
case AboutForm:
form = FrmInitForm( AboutForm );
FrmSetEventHandler( form, aboutHandleEvent );
break;
// CH.6 Enter Time form
case EnterTimeForm:
form = FrmInitForm( EnterTimeForm );
FrmSetEventHandler( form, enterTimeHandleEvent );
break;
// CH.7 Contact List form
case ContactListForm:
form = FrmInitForm( ContactListForm );
FrmSetEventHandler( form, contactListHandleEvent );
break;
}
FrmSetActiveForm( form );
}
// CH.2 Handle form events
FrmDispatchEvent( &event );
// CH.2 If it's a stop event, exit
} while( event.eType != appStopEvent );
// CH.7 End the try block and do the catch block
}
ErrCatch( errorAlert )
{
// CH.7 Display the appropriate alert
FrmAlert( errorAlert );
} ErrEndCatch
// CH.5 Close all open forms
FrmCloseAllForms();
// CH.5 Close the database
DmCloseDatabase( contactsDB );
// CH.2 We're done
return( 0 );
}
// CH.4 Our Contact Detail form handler function
static Boolean contactDetailHandleEvent( EventPtr event )
{
FormPtr form; // CH.3 A pointer to our form structure
VoidPtr precord; // CH.6 Points to a database record
// CH.3 Get our form pointer
form = FrmGetActiveForm();
// CH.4 Parse events
switch( event->eType )
{
// CH.4 Form open event
case frmOpenEvent:
{
// CH.2 Draw the form
FrmDrawForm( form );
// CH.5 Draw the database fields
setFields();
}
break;
// CH.5 Form close event
case frmCloseEvent:
{
// CH.5 Store away any modified fields
getFields();
}
break;
// CH.5 Parse the button events
case ctlSelectEvent:
{
// CH.5 Store any field changes
getFields();
switch( event->data.ctlSelect.controlID )
{
// CH.5 First button
case ContactDetailFirstButton:
{
// CH.5 Set the cursor to the first record
if( cursor > 0 )
cursor = 0;
}
break;
// CH.5 Previous button
case ContactDetailPrevButton:
{
// CH.5 Move the cursor back one record
if( cursor > 0 )
cursor--;
}
break;
// CH.5 Next button
case ContactDetailNextButton:
{
// CH.5 Move the cursor up one record
if( cursor < (numRecords - 1) )
cursor++;
}
break;
// CH.5 Last button
case ContactDetailLastButton:
{
// CH.5 Move the cursor to the last record
if( cursor < (numRecords - 1) )
cursor = numRecords - 1;
}
break;
// CH.5 Delete button
case ContactDetailDeleteButton:
{
// CH.5 Remove the record from the database
DmRemoveRecord( contactsDB, cursor );
// CH.5 Decrease the number of records
numRecords--;
// CH.5 Place the cursor at the first record
cursor = 0;
// CH.5 If there are no records left, create one
if( numRecords == 0 )
newRecord();
}
break;
// CH.5 New button
case ContactDetailNewButton:
{
// CH.5 Create a new record
newRecord();
}
break;
// CH.7 Done button
case ContactDetailDoneButton:
{
// CH.7 Load the contact list
FrmGotoForm( ContactListForm );
}
break;
// CH.6 Date selector trigger
case ContactDetailDateSelTrigger:
{
// CH.6 Initialize the date if necessary
if( dateTime.year == NO_DATE )
{
DateTimeType currentDate;
// CH.6 Get the current date
TimSecondsToDateTime( TimGetSeconds(),
¤tDate );
// CH.6 Copy it
dateTime.year = currentDate.year;
dateTime.month = currentDate.month;
dateTime.day = currentDate.day;
}
// CH.6 Pop up the system date selection form
SelectDay( selectDayByDay, &(dateTime.month),
&(dateTime.day), &(dateTime.year),
"Enter Date" );
// CH.6 Get the record
hrecord = DmQueryRecord( contactsDB, cursor );
// CH.6 Lock it down
precord = MemHandleLock( hrecord );
// CH.6 Write the date time field
DmWrite( precord, DB_DATE_TIME_START, &dateTime,
sizeof( DateTimeType ) );
// CH.6 Unlock the record
MemHandleUnlock( hrecord );
// CH.6 Mark the record dirty
isDirty = true;
}
break;
// CH.6 Time selector trigger
case ContactDetailTimeSelTrigger:
{
// CH.6 Pop up our selection form
FrmPopupForm( EnterTimeForm );
}
break;
}
// CH.5 Sync the current record to the fields
setFields();
}
break;
// CH.5 Respond to field tap
case fldEnterEvent:
isDirty = true;
break;
// CH.3 Parse menu events
case menuEvent:
return( menuEventHandler( event ) );
break;
}
// CH.2 We're done
return( false );
}
// CH.4 Our About form event handler function
static Boolean aboutHandleEvent( EventPtr event )
{
FormPtr form; // CH.4 A pointer to our form structure
// CH.4 Get our form pointer
form = FrmGetActiveForm();
// CH.4 Respond to the Open event
if( event->eType == frmOpenEvent )
{
// CH.4 Draw the form
FrmDrawForm( form );
}
// CH.4 Return to the calling form
if( event->eType == ctlSelectEvent )
{
FrmReturnToForm( 0 );
// CH.4 Always return true in this case
return( true );
}
// CH.4 We're done
return( false );
}
// CH.6 Our Enter Time form event handler function
static Boolean enterTimeHandleEvent( EventPtr event )
{
FormPtr form; // CH.6 A form structure pointer
static DateTimeType oldTime; // CH.6 The original time
// CH.6 Get our form pointer
form = FrmGetActiveForm();
// CH.6 Switch on the event
switch( event->eType )
{
// CH.6 Initialize the form
case frmOpenEvent:
{
// CH.6 Store the time value
oldTime = dateTime;
// CH.6 Draw it
FrmDrawForm( form );
// CH.6 Set the time controls
setTimeControls();
}
break;
// CH.6 If a button was repeated
case ctlRepeatEvent:
// CH.6 If a button was pushed
case ctlSelectEvent:
{
Word buttonID; // CH.6 The ID of the button
// CH.6 Set the ID
buttonID = event->data.ctlSelect.controlID;
// CH.6 Switch on button ID
switch( buttonID )
{
// CH.6 Hours button
case EnterTimeHoursPushButton:
// CH.6 Minute Tens button
case EnterTimeMinuteTensPushButton:
// CH.6 Minute Ones button
case EnterTimeMinuteOnesPushButton:
{
// CH.6 If no time was set
if( dateTime.hour == NO_TIME )
{
// CH.6 Set the time to 12 PM
dateTime.hour = 12;
dateTime.minute = 0;
// CH.6 Set the controls
setTimeControls();
}
// CH.6 Clear the old selection if any
if( timeSelect )
CtlSetValue( getObject( form, timeSelect ),
false );
// CH.6 Set the new selection
CtlSetValue( getObject( form, buttonID ), true );
timeSelect = buttonID;
}
break;
// CH.6 Up button
case EnterTimeTimeUpRepeating:
{
// CH.6 If there's no time, do nothing
if( dateTime.hour == NO_TIME )
break;
// CH.6 Based on what push button is selected
switch( timeSelect )
{
// CH.6 Increase hours
case EnterTimeHoursPushButton:
{
// CH.6 Increment hours
dateTime.hour++;
// CH.6 If it was 11 AM, make it 12 AM
if( dateTime.hour == 12 )
dateTime.hour = 0;
// CH.6 If it was 11 PM, make it 12 PM
if( dateTime.hour == 24 )
dateTime.hour = 12;
}
break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?