Chapter 6 Controls In this chapter, we will continue to study the Contact Detail program, allowing it to display and set the date and time. We have to add a form to set the time. This time and date is optional for the next contact. To implement this feature, we will use new resources: Select the trigger (Select Buttons), and repeat the button (Repeating Buttons). Contains along with the previous buttons, they are all Palm OS controls. They have similar properties and have the same event when triggered. They can have their own labels, they are all clicked triggered. After clicking, their shapes have changed, but there is only an instant change to recover. Save your project When you modify the project, it is best to make a copy of its copy. When there is a problem, you can start the copy of the project. The steps are as follows: 1. Open Windows Explorer; 2. Find the folder where the project is located; 3. Select the project, press CTRL C copy folder; 4. Select the folder you want to save; 5. Press CTRL V to save; 6. Rename the project so that you can clearly remember. I named it as Contacts Ch.5. Add this section of the content of ContatCS.RSRC file We add date and time control to Contact Detail. We will also create a form for changing time. For change dates, we will call the standard dialog of Palm OS. Adding Date Time Select Trigger Control Add two tags to the Contact Detail form (selector Triggers). We will use the selection trigger to display the date and time to call this Contact next time. Selecting a trigger control to handle events and buttons is very similar, but the shape is very different. It is surrounded by a pointful rectangle. Compared with the button, this rectangle has an additional space of a pixel in the width and height, which is considered when placing this control. See Table 6-1 for the properties of Selector Triggers. The Object Identifier constructor is used to represent the resource ID of the resource header ID to select the resource ID of the trigger control; the Left Origin horizontal direction is the leftmost position of the control; the top ORIGIN vertically in the vertical direction of the control; the maximum width of the Width control. This property is rarely used because the right boundary of the control changes as the length of the label text changes; the height of the Height control; USABLE determines if the second control is visible. If not selected, it can also be visible through function calls; Anchor Left determines whether or not the left or right side of the control is made accordingly when the text length changes; the font label used by the Font label; the default text of the Label label; The following is the step of adding a control: 1. Open the resource constructor; 2. Open the file Contacts.RSRC. It is in the SRC folder; 3. Double click on the Contacts Detail form; 4. Select Window | Catalog to generate control templates; 5. Drag a label onto the form. Set the label text for Next Call Date. Place it under the Phone Number label.
Set the Left Origin 0, Top ORIGIN is 60, text font is bold; 6. Drag a selection trigger (selector trigger) onto the form. Set Object Identifier for Date, Left Origin is 81, top origin is 60, Width is 78. Enter 10 spaces to the label, which ensures that in the default, there is sufficient space when pressed by the Finger; 7. Drag a label on the form. Set the label text to Next Call Time. Place it under the Next Call Date label. Set the Left Origin 12, TOP Origin is 80, the text font is bold; 8. Drag a selection trigger (selector triggers) on the form. Set Object Identifier as Time, Left Origin 81, Top Origin is 80, Width is 78. 10 spaces are also entered towards the label. 9. The form after adding controls is shown in Figure 6-1. Press the X button in the upper right corner to close the form. Figure 6-1: Contact Detail Form Creating a new setting time window Creating a form: 1. Click on the Forms option in the resource (resource) option, press Ctrl-K to create a new form 2. Click the name box and rename Enter Time; 3. Double-click Open Form to edit; 4. Set the form attribute first. Check the properties modal and save behind. We appear as a dialog as a dialog; this form is the first form that we have touched is not a full screen display; we modify its width (width) to 156, which height is 53; 5. For implementation of the Modal border, we need to leave two pixels in the form and screen boundary. Therefore, the width is set to 156, and the left start boundaries should be 2, the top initial boundary should be 105, which guarantees the rating of two pixels; 6. Modify the form of the form (Name) attribute Enter Time. The Push Buttons Switch button (PUSH Buttons) is different from the usual light background, but black background, but black background. We use the switch button (Push Buttons) to display hours, minutes, and morning / afternoon (AM / PM). When placing a switch button (PUSH Buttons), we must consider the width of a pixel occupied by its boundary. The attribute of the switch button (PUSH Buttons) is shown in Table 6-2: The Object Identifier resource constructor is used to represent the resource header ID of the constant Push Button ID switch button (PUSH Buttons) resource ID LEFT Origin horizontal direction button's leftmost Location; Top Origin vertical direction button The top of the button; the Width button's width Height button is high usable to define if the control is visible and available, and if not, it can also be invoked to implement its visible group ID indicate when the group Whether it is highlighted when pressing. If this number is 0, the button is pressed to switch between "Press" and "No Press". When this number is not 0, the button is pressed to keep the original state.
The group ID used in each group should be unique, because in the later code, a group ID FONT tag will be used to display the text of the font label tag itself of the text: 1. Put a switch button (PUSH Buttons Drag on the Enter Time form; 2. Since this button shows time, you can set the Object Identifier to Hours. Setting attribute: left origin = 5, top origin = 17, width is 18, Group ID is 1. The font property is BOLD, clear the text within the tag; 3. Copy the HOURS Switch button (Push Buttons). After the HOURS switch button (PUSH Buttons) is selected, press CTRL-D to copy. Modify Object Identifier for MinuteStens. Setting attribute: left origin = 34, top origin = 17, width is 12 because it only contains a number; 4. Copy the MinuteStens button. Once the minutestens button is selected, press CTRL-D to copy. Modify Object Identifier Setting to Minutesones. Setting Properties: Left Origin = 50, TOP Origin = 17; 5. Drag a switch button (Push Buttons) to the form. Modify Object Identifier Set to AM. Setting attribute: left origin = 109, top origin = 17, Width is 20, Group ID is 2. Set the text in the tag to AM; 6. Copy the AM switch button (Push Buttons). Modify Object Identifier as PM. Setting Properties: Left Origin = 130, Top Origin = 17, Note The AM button and PM button overlap is to make only there is only one pixel interval, which is how the relevant switch button is classified as a group. . Set the text within the tag to PM; name Description Object Identifier constructor is used to represent the constant of the resource header ID. Push Button ID Switch button (PUSH Buttons) flag. Left ORIGIN Switch button (PUSH Buttons) horizontal starting position. The vertical starting position of the top edge of the Top ORIGIN Switch button (PUSH Buttons). Width switch button (PUSH Buttons) width. Height switch button (Push Buttons). Usable This parameter defines whether the control is visible and activated. If this parameter is not selected, you can call the control vision and activation through a function. Group ID This parameter affects the switch button (PUSH Buttons) is still highlighted. If this parameter is 0, the switch button (PUSH Buttons) is pressed, and its state is switched between "ON" and "OFF". If you want to use the group number in the program, the group number should be unique. Font Tag Display Text Font Label Tags The text of the text to the Setting time form Add a repetition button (REPEATING button) If you enter the time over half a second on the REPEATING button, the button will continue to send the CTLRepeArtEvent event. After the first half, the CTLRepeaTevent event was sent once every one in seconds. We use the repeat button (REPEANG button to construct the UP and Down arrows to adjust the time. As with a general button, the repeat button (REPEATING button can have one side.
In our case, these buttons do not use the border, so they are arranged like labels and text boxes. The properties of the repeat button (REPEATING button are as follows: Name Description Object Identifier constructor is used to represent the constant of the resource header file ID. Button ID Duplicate button (REPEATING button) flag number. The horizontal starting position of the left edge of the Left Origin button. The vertical start position of the top edge of the Top Origin button. Width button width. Height button height. Usable This parameter defines whether the control is visible and activated. If this parameter is not selected, you can call the control vision and activation through a function. Anchor LEFT is selected, and the button is reset to the right to the right. Frame is selected, and the button will have a box. Non-Bold Frame is selected, and the button border is 1 pixel. Font Tag Display Text Font Label Tags The text of the text to the Setting time form 1. Drag and drop a REPEATING button to the set time form. Change Object Identifier to Timeup. The reference location is Left Origion = 109, TOP Origion = 17. The reference size is width = 20, Height = 8. Do not choose Frame feature. 2. Select the font to Symble 7, select HEX Box on Label. Type 01. This way, you see a blank tag on the Form, and the upward arrow will be displayed after running the code. Don't be confused by HEX 21. When you run the code, HEX 21 is displayed as a check box. 3. Copy the button by selecting the REPEATING button and pressing CTL-D. Object Identifier will change to Timedown. This button should be left Origion = 69, Top Origion = 25. Set the Label to HEX 02, then display a downward arrow when the program is running. Add a check box to the setting time form The left end of the check box has a small box to indicate some things. In setup time forms, the small box allows users to choose not to enter. The check box does not have a border, so their alignment is like a domain. The properties of the check box are shown in the table below: Name Description Object Identifier resource constructor is used to represent the constant of the resource header file ID. Checkbox ID check box flag number. Left Origin check box horizontal starting position. The vertical start position of the top edge of the top origin check box. Width check box width. Height check box height. Usable This parameter defines whether the control is visible and activated. If this parameter is not selected, you can call the control videos and activated through a function call. SELECTED is selected, then the checkbox is selected by the default. Group ID This parameter affects whether the check box is selected when it remains high. If this parameter is 0, the check box is pressed, and its status is switched between selected and unselected. If you want to use the group number in the program, the group number should be unique. Font label shows the font of the text. Label tag itself The text is now adding a check box to the setting time form: 1. Drag and drop a checkbox from the Catalog window to the set time form. 2. Set the Object Identifier property to Notime. The reference position is Left Origion = 53, Top Origion = 37. Width is 50. Select SELECTED. It is 0 because it is not a group. Set Label for Notime. Perfect Setting Time Form Now let us add some familiar controls: 1. Hours and minutes from the colon. Drag and drop a Label control from the Catalog Form to the Set Time Form.
The location is Left Origion = 27, TOP Origion = 17. The font is bold. Add a colon. 2. Each dialog requires an OK button. Drag and drop a Button control from the Catalog Form to the Set Time Form. Location is Left Origion = 5, TOP Origion = 37. Note that Left Origion is set to 5 to align the button on the PUSH button and leave 4 pixels in the left edge. 3. There is a Cancel button will be fine. Drag and drop a Button control into the form. Change Object Identifier as Cancel. Its position is Left Origion = 115, TOP Origion = 37. Change Label for Cancel. 4. Enable the Cancel button to the default button of this form. Make a note of the Button ID of the Cancel button. Click any property table that displays the setting time form on the form background. Set the ID of the Fact Fact button to the Cancel button button's Button ID. You have completed the construction of the setting time form. Your form should be shown below. Click x in the upper right corner to close the window. Select File | Save to save your changes. Add code to Contacts.c Now, in order to support date and time in new forms we have added, we add code to Contacts.c. In the database, you need some variables and constants definitions to save and define dates and time in the internal and database. // ch.6 Storage for the Record's DateTIMETYPETED FORM Static DateTimetyPE DateTime; static word timeselect; #define no_date 0 #define no_time 0x7fff variable datetime Save the date and time of the record currently being processed. Setting the time form Use the TimeSelect variable to complete the same functionality. Constant NO_TIME and NO_DATAE also use DataTime to indicate no date or no time or both. In the newrecord () function, the initial state of Date and TIME is not available and there is no time. // CH.6 Initialize the date and time MemSet (& dateTime, sizeof (dateTime), 0); dateTime.year = NO_DATE; dateTime.hour = NO_TIME; DmWrite (precord, DB_DATE_TIME_START, & dateTime, sizeof (DateTimeType)); Note that we Use MEMSET () to clear the entire record. If we don't do this, the domain in the record will have garbage and the domain feature will crash because we don't send a string of zero-bounded strings as you want to hope. Then, we initialize the record DateTime as a temporary variable. Figure 6-2: Entertime Forms In the setFields () function, load the value of the DateTime variable from the record. // ch.6 Initialize the date and time variable precord = memHandLock (HRECORD); Memmove (& DateTime, PRecord DB_DATE_TIME_START DB_DATE_TIME_START, SIZEOF (DATETIME)); and set the appearance of the date and time (Selector Triggers). We will study these features in detail when discussing the choice of triggers.
// ch.6 Initialize the date control setdatetrigger (); // ch.6 Initialize the time control settrigger (); support date and time selection button to join the first line of code should be the Contact Detail Form Event Handle, dates The selection button is selected, and then add the event processing process to the process of processing the normal button. // 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 (), & currentDate); // 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.Mont), & (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; if the time is not filled in time, the time is set to the current time. Gets the current time is to convert its output into a date by calling the function timgetseconds () and via the function TIMSeconStodateTime (). These functions are part of the time processor that has a detailed description in the Reference.pdf file of the Palm OS. After the initialization is complete, we call the function selectDay () to generate a PALM OS built-in control to select the date. When the time is selected, we lock the current record of the database and write the new time value. Select time is somewhat different. Because there is no direct selection of time in the Palm OS, then we pops up the Enter Time form to interact with the user. // ch.6 Time SelectorSeltrigger: {// ch.6 POP UP UPUR Selection form fRMPopupForm (Entertainment form);} Break; what we do during the Contact Detail event process is to call up the Enter Time form. Modifying the work of the database is handled by the latter.
Function setDatetrigger () Update the appearance of the date selection button, the code is as follows: // ch.6 set the contact details select selector trigger static void setdatetrigger (void) {FormPtr form; // ch.5 the contact detail form //CH .6 get the contact detail form Pointer form = frMgetActiveform (); // ch.6 if there is no date if (datetime.year == no_date) {CTLSetLabel (GetObject (Form, ContactDetAildateSeltrigger), "");} else / / cH.6 If there is a date {Char dateString [dateStringLength]; // cH.6 Get the date string DateToAscii (dateTime.month, dateTime.day, dateTime.year, (DateFormatType) PrefGetPreference (prefDateFormat), dateString); // ch.6 set the selector trigger label CTLSetLabel (GetObject (form, contactDetAildateSeltrigger), DateString;} // ch.6 We're done return;} If there is no time, we write 10 spaces in our control. Since the selection trigger button can automatically resize according to the label, you can guarantee that the trigger button is large enough to select your finger. Remember to ensure that the text size in the control tab (including the trigger button) should not exceed the quantity defined in the constructor. If you have time, then we return time. The priority within the system will determine what format we use to display time. We call the function predePreference () with parameter predateformat to obtain the priority of the date. The reason why we choose Type DateFormat is that preientPReference () can return many different priorities, and we choose the most common. Function DateToascii () is used to convert date variables to our defined short-time format, which is obtained from the system. When we get time, we write it into the trigger button tag. Function setTimeTrigger () is used to set the time trigger button. It is very similar to setDatetrigger (), except for its own corresponding functions. The support switch button (PUSH Buttons) is like the contact details, we will also create a Switch statement to handle CTLSELECTEVENT. The CASE statement is built on a different Button ID value, which can be represented by a true control ID.
Hours and minutes are handled first switch button (push buttons): // 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 (time ") CTLSetValue (GetObject (Form, TimeSelect), False; // Ch.6 Set The New Selection CTLSetValue (GetObject (Form, ButtonID), TRUE TimeSelect = ButtonId;} Break; button will display its respective values on their labels. Which value is associated with the upper or lower arrows is based on which one is selected. If the button is selected but no time display, 12pm will be set and displayed. If a button has been selected, then we first clear this selection, then select the button we just click on. In the function setTimeControl (), we see how it sets the label text. In fact, it is the same as any other control to handle the label. // ch.6 Update the Hour Hour = DateTime.Hour% 12; if (Hour == 0) Hour = 12; CTLSetLabel (Hourbutton, Stritoa (Labelstring, Hour); // Ch.6 Update The Minute Tens CTLSetLabel MinuteTensButton, Stritoa (Labelstring, DateTime.minute / 10)); // Ch.6 Update The Minute Ons CTLSetLabel (Labelstring, DateTime.minute% 10); Time is displayed in 24-hour format, we put it Convert to 12 hours format and display it on the button. There are also two PUSH buttons in the function entertainment () to perform AM / PM settings.
They are as follows: // ch.6 am Button case entertimeampushbutton: {// ch.6 if no time WAS set if (datetime.Hour == no_time) {// ch.6 set the time to 12 am DateTime. Hour = 0; DateTime.minute = 0; // ch.6 set the controls setTimeControls ();} // ch.6 if IT IS PM if (DateTime.Hour> 11) {// ch.6 Change to am DateTime. Hour - = 12; // ch.6 set the controls setTimeControls ();}} Break; in the am Case statement, if there is no time, then we set the time is 12 am; if time is PM, then we are formatted from 24 hours format The 12 is subtracted to become AM. PM button processing and AM are almost. In setTimeControls () Display AM and PM, the code is as follows: // ch.6 Update am CTLSetValue (Ambutton, (DateTime.Hour <12)); // ch.6 Update PM CTLSetValue (Pmbutton, (DateTime. Hour> 11); // ch.6 Update PM CTLSetValue )); Where the Boolean value is required, it is a very interesting thing according to its logic. Support repeated button (REPEATING button) The REPEATING button allows time to increase or decrease. In order to make it effective, we must handle CTLRePeaTevent as handling CTLSelectEvent. In the function entertainment () we must return false from the event handle, otherwise the REPEATING event cannot be generated.
// ch.6 Up button entertimetimeuprepeating: {// ch.6 if there is no time, do nothingiff (datetime.Hour == no_time) Break; // ch.6 based on what putton is selected Switch (TimeSelect) {// ch.6 Increase Hours Case EntertimeHourspushbutton: {// ch.6 Increment Hours DateTime.Hour ; // Ch.6 IT WAS 11 AM, Make It 12 amix (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; // Ch.6 Increase Tens of Minutes Case EntertainmentTimeTenspushButton: {/ / Ch.6 increment minutes datetime.minute = 10; // ch.6 if IT WAS 5X, Roll Over if (DateTime.minute> 59) DateTime.minute - = 60;} Break; // ch.6 Increase Minutes Case EntertimeMinuteOnSpushButton: {// ch.6 increment minutes datetime.minute ; // ch.6 if it is zero, Subtract Ten IF ((DateTime.minute% 10) == 0) DateTime.minute - = 10;} Break; } // Revise the controls setTimeControls ();} Break; if there is no time display, the up and down arrows do not do anything. When there is a time display, according to the selected switch button (Push Buttons), the repeat button will increase the ten, minutes of the minute. It also handles the necessary cyclic situations. Reduce the button and the increase button is basically similar. Support check box check box is the same as other buttons. When triggered, a CTLSELECTEVENT is generated.
// ch.6 no time checkbox case entertimenotimeCheckbox: {// ch.6 if we are unchecking the box 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 (); timeSelect = EnterTimeHoursPushButton // cH.6 Set the new selection; CtlSetValue (getObject (form, timeSelect), true);} else // cH.6 IF we are checking the box datetime.Hour = no_time; // ch.6 set the controls setTimeControls ();} Break; for convenience, if you don't choose the check box, we will select the hourly push button, then other things SetTimeControl () is processed. All control content will be emptied when the selection check box is selected. End ENTER TIME forms There are also some other window handling events that require discussion. Process frmopnevent in entertimeHandleevent (). // ch.6 Initialize the form, frmopenevent: {//ch.6 store the time value oldtime = datetime; // ch.6 draw it frmdrawform (form); // ch.6 set the time control settimecontrols (); } Break; When the form is turned on, we initialize the form with a function setTimeControls (). We also saved the current time in order to press Cancel to recover. // ch.6 Cancel Button: {// ch.6 restore time datetime = Oldtime; // ch.6 return to calling form frmreturntoform (0);} // ch.6 always return true return (TRUE); The Cancel button event stores the old time and returns to the Contact Detail form. OK button is somewhat complicated. We must update the database and the Contact Detail form according to the new time. There are several points here. This code block indicates why Variable HRecord is public in a function. Here, because HRecord is effective, all we use it to write new time values into the database. Note that setTimeTrigger () after function frmreturntoform (), which is used to trigger the Time to trigger the trigger button for the Contact Details form. The reason why the trigger to be triggered is because the FRMRTURNTOFORM () is executed, the active form changes to the Contact Details form. This allows the data of the pop-up form to be passed smoothly to the calling form. Typically, Returning True after calling frmreturntoform () because the old form structure has disappeared after calling. However, if false is returned, Palm OS tries to access the button structure to do more materials. Since the window is already not there, this will crash. Debugging First, you should ensure that database records can be created and modified correctly. If it is smooth, the display function you add can display the result of the result.
Your existing records are behaved as No Date, 12 AM is displayed on the interface, but not dangerous. Next, manipulate the date trigger button on the Contact Detail form to see if you can work properly by the design. This should be relatively easy to built-in control of the date. For time control, you need to debug the Enter Time form. Carefully debug all controls until you can work reliably. When the form can run smoothly, you can verify that the database record and time selection trigger button is modified correctly. Next step Next, we will add a list box form to the Contacts application. Then modify the code allows us to sort according to First Name, Last Name, Date, and Time. Listing is the full contacts.c program list below.
// ch.2 the super-incrude for the palm OS #include
/ 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.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 // ch.4 Go To Our Starting Page Frmgotoform (ContactDetailform); // Ch.2 Our Event Loop DO {// Ch.2 Get The next Event EvtgetEvent (& Event, -1); // Ch.2 Handle System Events IF (Syshandleevent) Continue; // Ch.3 Handle Menu Events if (MenuHandleevent (Null, & Event, & Error)) Continue; // Ch.4 Handle Form Load Events if (Event.Type == 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;} FrmSetActiveForm (FORM);} // ch.2 Handle Form Events frMdispatchevent (& Event); // ch.2 if it's a stop event, exit} while (event.type! = appstope VENT); // 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 frmopnevent: {// ch.2 draw the form frmdrawform (form); // ch.5 Draw the database fields setfields (); // 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.control) {// ch.5 First Button Case ContactDetailfirstButton: {// ch.5 set the cursor to the first recordiffiffiffness f (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 Nu MRecords -; // ch.5 Place The Cursor at The First Record Cursor = 0; // Ch.5 if There no records left, crete one f (NumRecords == 0) newrecord ();} Break; // cH.5 New button case ContactDetailNewButton: {// cH.5 Create a new record newRecord ();} 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 (), & currentDate); // 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.Mont), & (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 (Entertainment;} // ch.5 sync the current record to the fields setfields ();} Break; // ch.5 respond to Field Tap Case Fldenterevent: Isdirty = true; Break; //C .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) {form Ptr form; // ch.4 a Pointer to out our form Pointer form = frMgetActiveform (); // ch.4 respond to the open event if (event-> eType == frmopnevent) { // ch.4 Draw the form frmdrawform (form);} // ch.4 return to the calling form if (event-> eType == CTLSELECTEVENT) {frmreturntoform (0); // ch.4 always returnim 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 formTRUCTURE 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 code frmopnevent: {// 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 OLDELECTION IF ANY IF (TimeSelect ) CTLSetValue (getObject (form, timeselect), false); // C H.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 IT WAS 11 PM, Make IT 12 PM IF (DateTime.Hour = = 24) DateTime.Hour = 12;} Break; // ch.6 increable tens of minutes case entertimeMinuteTenspushbutton: {// ch.6 increment minutes datetime.minute = 10; // ch.6 if IT WAS 5X, Roll Over if (DateTime.minute> 59) DateTime.minute - = 60;} Break; // ch.6 Increase minutes case entertime.minutenespushbutton: {// ch.6 increment minutes datetime.minute ; // ch.6 if it is zero, Subtract Tenix ((DateTime.minute% 10) == 0) DateTime.minute - = 10;} Break;} // Revise the controls setTimeControls ();} Break; // ch.6 Down Button Case EntertimedownRepeating: {// ch.6 f t's no time, do nothing if (dateTime.hour == NO_TIME) break; // cH.6 Based on what push button is selected switch (timeSelect) {// cH.6 Decrease hours case EnterTimeHoursPushButton: {// cH.6 Decrement hours dateTime.hour- -; // ch.6 if IT WAS 12 AM, Make IT 11 AM IF (DateTime.Hour == -1) DateTime.Hour = 11; // CH.6 IT WAS 12 PM, Make IT 11 PM IF ( DateTime.Hour == 11) DateTime.Hour = 23;} Break; // Ch.6 Decrease Tens of Minutes Case EntertainmentMi NuteTenspushbutton: {// ch.6 Decrement Minutes DateTime.minute - = 10; // Ch.6 if IT WAS 0X, Roll Over (DateTime.minute <0) DateTime.minute = 60;} Break; // CH .6 Decrease Minutes Case EntertimeMinuteOnSpushbutton: {// Ch.6 Decrement Minutes DateTime.minute--; // Ch.6 IF IT IS 9, Add Ten IF ((DateTime.minute% 10) == 9) DateTime.minute = 10; // ch.6 if Less Than Zero, Make IT 9 IF (DateTime.minute <0) DateTime.minute = 9;} Break;} // ch.6 Revise The Controls SetTimeControls ();} Break; / / Ch.6 am Button case entertimeampushbutton: {// ch.6 if no time WAS set if (datetime.hip == NO_TIME) {// ch.6 set the time to 12 am DateTime.Hour = 0; datetime.minute = 0; // ch.6 set the controls setTimeControls ();} // ch.6 if IT IS PM IF ( DateTime.Hour> 11) {// ch.6 change to am DateTime.Hour - = 12; // ch.6 set the controls settimeControls ();}} Break; // ch.6 PM Button Case EntertimePmpushbutton: {/ / 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 if IT IS am if (DateTime.Hour <12) {// ch.6 change to PM DateTime.Hour = 12; // ch.6 set the controls setTimeControls (); }}}} Break; // Ch.6 No Time Checkbox Case EntertainmentTimeCheckbox: {// ch.6 ife wE all unchecking the box if (datetime.hip == no_time) {// ch.6 set the time to 12 PM DateTime. Hour = 12; datetime.minute = 0; // ch.6 set the new selection timeselect = entertimehourspushbutton; ctlsetValue (getObject (Form, TimeSelect), TRUE );} else // ch.6 if we are checking the box datetime.Hour = no_time; // ch.6 set the controls settimeControls ();} Break; // ch.6 Cancel Button Case EntertimecancelButton: {//CH .6 restore time datetime = OldTime; // ch.6 return to calling form frmreturntoform (0);} // ch.6 always return {voidptr precord; // cH.6 Points to the record // 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; // ch.6 return to the contact details form frmreturntoform (0); // ch.6 Update the field setTimetrigger ();} // ch.6 always return true return;}} Break; / Ch.6 we're done return (false);} // ch.3 Handle Menu Events static boolean menueventhandler (eventptr av; // ch.3 a Pointer to Our Form Structure Word Index; //C .3 A general purpose control index FieldPtr field; // cH.3 Used for manipulating fields // cH.3 Get our form pointer form = FrmGetActiveForm (); // cH.3 Erase the menu status from the display MenuEraseStatus (NULL) ; // ch. cH.3 Handle graffiti help if (event-> data.menu.itemID == EditGraffitiHelp) {// cH.3 Pop up the graffiti reference based on // the graffiti state SysGraffitiReferenceDialog (referenceDefault); return (true);} / / Ch.3 get the index of outful DEX = frMgetfocus (form); // ch.3 if there is no field successd, we're done if (index == nofocus) return (false); // ch.3 get the pointer of outfide = frMgetObjectPtr Form, index); // ch.3 do the Edit Command Switch (Event-> Data.Menu.Itemid) {// ch.3 undo Case Editundo: Fldundo (Field); Break; // Ch.3 Cut Case Editcut : Fldcut (Field); Break; // Ch.3 Copy Case EditCopy: FldCopy; Break; // Ch.3 Paste Case EditPaste: Fldpaste (Field); Break; // Ch.3 Select All Case EditsElectrall: {// ch.3 get the length of the string in the field word length = fldgetTextLength (field); // ch.3 Sound an error if appropriate if (length == 0) {SndPlaySystemSound (sndError); return (false);} // CH.3 Select the whole string FldSetSelection (field, 0, length);} break; // CH.3 Bring up the keyboard tool case EditKeyboard: SysKeyboardDialogV10 ( Break;} // ch.3 We're Done Return (TRUE);} // ch.5 this function creates and initializes a new record static void newrecord (void) {voidptr precord; // ch.5 Pointer To the record // cH.5 Create the database record and get a handle to it hrecord = DmNewRecord (contactsDB, & cursor, DB_RECORD_SIZE); // cH.5 Lock down the record to modify it precord = MemHandleLock (hrecord); // CH .5 Clear The Record DMSET (Precord, 0, DB_Record_size, 0); // Ch.6 Initialize The Date and Time Memset (DateTime), 0); DateTime.Year = NO_DATE; DATETIME.HOUR = NO_TIME; DmWrite (precord, DB_DATE_TIME_START, & dateTime, sizeof (DateTimeType)); // cH.5 Unlock the record MemHandleUnlock (hrecord); // cH.5 Clear the busy bit and set the dirty bit DmReleaseRecord (contactsDB, cu RSOR, TRUE); // Ch.5 Increment The Total Record Count NumRecords ; // Ch.5 set the dirty bit isdioty = true; // ch.5 we're done return;} // ch.5 a time saver : Gets object pointers based on their ID static VoidPtr getObject (FormPtr form, Word objectID) {Word index; // cH.5 The object index // cH.5 Get the index index = FrmGetObjectIndex (form, objectID); // CH .5 return the Pointer Return (FRMGETOBJECTPTR (FORM, INDEX));} // ch.5 Gets The Current Database Record and Displays It // in The Detail Fields Static Void SetFields (Void) {Formptr Form; // Ch.5 The Contact Detail Form Charptr Prot; // Ch.5 A Record Pointer Word Index; // ch.5 the Object index // ch.5 get the contact detil form Pointer form = frMgetActiveform (); // ch.5 get the current record hrecord = DMQueryRecord (ContactSDB, CURSOR); // ch.6 Initialize the date and time variable precord = MemHandleLock (hrecord); memMove (& dateTime, precord DB_DATE_TIME_START, sizeof (dateTime)); // cH.6 Initialize the date control setDateTrigger (); // cH.6 Initialize the time control setTimeTrigger () ; // cH.5 Set the text for the First Name field setText (getObject (form, ContactDetailFirstNameField), precord DB_FIRST_NAME_START); // cH.5 Set the text for the Last Name field setText (getObject (form, ContactDetailLastNameField), precord DB_LAST_NAME_START); // cH.5 Set the text for the Phone Number field setText (getObject (form, ContactDetailPhoneNumberField), precord DB_PHONE_NUMBER_START); MemHandleUnlock (hrecord); // cH.5 If the record is already dirty, it's New, SO SET FOCUS IF (Isdirty) {// ch.3 get the index of out @ = frm GetObjectIndex (form, ContactDetailFirstNameField); // CH.3 Set the focus to the First Name field FrmSetFocus (form, index); // CH.5 Set upper shift on GrfSetState (false, false, true);} // CH. 5 We're done return;} // ch.5 Puts any field change, {formptr form; // ch.5 The Contact Detail Form //Ch.5 Get The Contact Detail Form Pointer Form = FrMgetActiveform (); // ch.5 Turn Off Focus frMsetfocus (form, -1); // ch.5 if the record HAS been modified if (isdirty) {charptr precord; // ch.5 Points to the db record // ch.5 Lock The record code = memhandLock (HRECORD) // CH.5 Get the text for the First Name field getText (getObject (form, ContactDetailFirstNameField), precord, DB_FIRST_NAME_START); // CH.5 Get the text for the Last Name field getText (getObject (form, ContactDetailLastNameField), precord , DB_LAST_NAME_START); // cH.5 Get the text for the Phone Number field getText (getObject (form, ContactDetailPhoneNumberField), precord, DB_PHONE_NUMBER_START); // cH.5 Unlock the record MemHandleUnlock (hrecord);} // cH.5 Reset the dirty bit isdirty = false; // ch.5 We're done return;} // ch.5 set the text in a field static void settext (fieldptr fit, charptr text) {voidhand hfield; // ch.5 Handle of Field Text Charptr Pfield; // Ch.5 Pointer To Field Text // Ch.5 Get The Current Field Handle Hfield = FLDGETTEXTHANDLE (Field); // Ch.5 IF We Have a Handle IF (Hfield! = NULL) {// ch.5 Resize it MemHndleresize (Hfield, Strlen (Text) 1);} else // ch.5 allocate a Handle for the string hfield = MemHandleNew (Strlen (Text) 1); // Ch.5 Lock IT Pfield = MemHandLock (Hfield); // Ch.5 Copy The String Strcopy (Pfield, Text); // Ch.5 Unlock It MemHenlock (Hfield); // Ch.5 Give It to the Field FldsetTextHandle (Field, Hfield); // Ch.5 draw the field flddrawfield (field); // ch.5 we're done return;} // ch.5 get the text from a field static void gettext (Fieldptr Field, Voidptr Precord, Word Offset; // Ch.5 PFIELD; // Ch.5 PFIELD TEXT //CH.5 Get The Text Point Pfield = FldgetTextptr (Field); // Ch.5 Copy IT DMWRITE (PRCORD, OFFSET, PFIELD, STRLEN (pfield); // ch.5 We're done return;} // ch.6 set the contact detail date selector trigger static void setdatetrigger (void) {FormPtr form; // ch.5 the Contact Detail form //Ch.6 get the contact detail form Pointer form = frMgetactiveform (); // ch.6 if there is no date if (datetime.year == no_date) {ctlsetLabel (getObject FORM, ContactDetAildateSeltrigger, "");} else // ch.6 if there is a date {char datestring [datestRingLength]; // ch.6 get the date string datetoascii (datetime.month, datetime.day, datetime.year , (DateFormatType) PrefGetPreference (prefDateFormat), dateString); // cH.6 Set the selector trigger label CtlSetLabel (getObject (form, ContactDetailDateSelTrigger), dateString);} // cH.6 We're done return;} // CH .6 set the contact detail time selectrigger (void) {Formptr form; // ch.5 the contact detail form // ch.6 get the contact detail form Pointer form = frMgetActiveform (); // ch.6 If there is no time if (DateTime.Hour == NO_TIME) {CTLSetLabel (GetObject (Form, ContactDetailTimeSeltrigger), "" ";} else // ch.6 if there is a time {char TimeString [TimeStringle ngth]; // CH.6 Get the time string TimeToAscii (dateTime.hour, dateTime.minute, (TimeFormatType) PrefGetPreference (prefTimeFormat), timeString); // CH.6 Set the selector trigger label CtlSetLabel (getObject (form, ContactDetailTimeSelTrigger ), timeString);} // cH.6 We're done return;} // cH.6 Set the controls in the Enter Time form based on dateTime static void setTimeControls (void) {FormPtr form; ControlPtr hourButton; ControlPtr minuteTensButton; ControlPtr minuteOnesButton; ControlPtr amButton; ControlPtr pmButton; ControlPtr noTimeCheckbox; Char labelString [3]; SWord hour; // cH.6 Get the form form = FrmGetActiveForm (); // cH.6 Get the control pointers hourButton =