Esempio n. 1
0
/* Setup transliteration popup on search form */
void SetupXlitPopup( void )
{
    ListType*           list;

    list      = GetObjectPtr( frmSearchXlitList );

    LstSetListChoices( list, xlitNames, numXlits + 1 );
    LstSetHeight( list, numXlits + 1 );
}
Esempio n. 2
0
static void DrawList()
{
	FormPtr form = FrmGetActiveForm();
	if (FormIsNot(form, FormReply)) return;
	ListPtr list = (ListPtr) GetObjectPtr(form, ListGroups);
	LstSetListChoices(list, NULL, g_PhoneGroups.size() + 1);
	
	UInt16 maxVisible = 8;
	if (g_PhoneGroups.size() < maxVisible - 1) 
		maxVisible = g_PhoneGroups.size() + 1;
	
	LstSetHeight(list, maxVisible);
	LstSetDrawFunction(list, ListDrawDataFunc);
	LstDrawList(list);
}
Esempio n. 3
0
/*
** Popup the transfer details list.
*/
static void DoXferList(void) {
  const Int16 num_plugs = PlugIndex(NULL, true);

  if (!d.xfer.pluglistH || !num_plugs) {
    FrmAlert(NoPluginInstalled);
  } else {
    RectangleType rect;
    Int16 list_selection = -1;
    FormType* frm = FrmGetActiveForm();
    ListPtr list = GetObjectPointer(frm, XferList);

    /* Set up plugin list control */
    LstSetDrawFunction(list, XferListDrawFunc);
    LstSetListChoices(list, NULL, num_plugs);
    LstSetHeight(list, Min(num_plugs, 10));
    FrmGetObjectBounds(frm, FrmGetObjectIndex(frm, XferList), &rect);
    rect.topLeft.x = 16;
    rect.topLeft.y = 144 - rect.extent.y;
    rect.extent.x = d.xfer.plug_menu_width;
    FrmSetObjectBounds(frm, FrmGetObjectIndex(frm, XferList), &rect);

    /* Pop up the list */
    LstSetSelection(list, GetCurrentXferAppListIndex());
    list_selection = LstPopupList(list);

    if (list_selection != -1) {
      SysDBListItemType* pluglistP = MemHandleLock(d.xfer.pluglistH);
      
      /* Store the current plugin */
      p.xfer_current_plug = pluglistP[PlugIndex(list_selection, false)].creator;

      /* Clean up */
      MemHandleUnlock(d.xfer.pluglistH);
    }
  }
}
Esempio n. 4
0
static void
ExamDetailsFormInit(FormType *frm)
{
  UInt16 selectedCourse=0;
  ListType *course;
  ControlType *course_tr, *date_tr, *time_tr;

  course = GetObjectPtr(LIST_exd_course);
  course_tr = GetObjectPtr(LIST_exd_course_trigger);
  date_tr = GetObjectPtr(SELECTOR_exd_date);
  time_tr = GetObjectPtr(SELECTOR_exd_time);

  gExamDetailsNumCourses = CountCourses();

  gExamDetailsItemList = (Char **) MemPtrNew(gExamDetailsNumCourses * sizeof(Char *));
  gExamDetailsItemIDs = (UInt16 *) MemPtrNew(gExamDetailsNumCourses * sizeof(UInt16));
  gExamDetailsItemInd = (UInt16 *) MemPtrNew(gExamDetailsNumCourses * sizeof(UInt16));

  if (gExamsLastSelRowUID == 0) {
    // ADD
    DateTimeType dt;

    selectedCourse = CourseListGen(gExamDetailsItemList, gExamDetailsItemIDs, gExamDetailsItemInd, gExamDetailsNumCourses, 0, CLIST_SEARCH_INDEX);

    TimSecondsToDateTime(TimGetSeconds(), &dt);
    gExamDetailsDate.year=dt.year-MAC_SHIT_YEAR_CONSTANT;

    gExamDetailsDate.month=dt.month;
    gExamDetailsDate.day=dt.day;

    gExamDetailsBegin.hours=14;
    gExamDetailsBegin.minutes=0;

    gExamDetailsEnd.hours=15;
    gExamDetailsEnd.minutes=30;

  } else {
    MemHandle mex, mRoom, old;
    ExamDBRecord *ex;
    UInt16 index=0;
    Char *buffer;
    FieldType *fldRoom;

    fldRoom=GetObjectPtr(FIELD_exd_room);

    DmFindRecordByID(DatabaseGetRefN(DB_MAIN), gExamsLastSelRowUID, &index);

    mex = DmQueryRecord(DatabaseGetRefN(DB_MAIN), index);
    ex = (ExamDBRecord *)MemHandleLock(mex);

    selectedCourse = CourseListGen(gExamDetailsItemList, gExamDetailsItemIDs, gExamDetailsItemInd, gExamDetailsNumCourses, ex->course, CLIST_SEARCH_ID);

    gExamDetailsDate.year=ex->date.year;
    gExamDetailsDate.month=ex->date.month;
    gExamDetailsDate.day=ex->date.day;

    gExamDetailsBegin.hours=ex->begin.hours;
    gExamDetailsBegin.minutes=ex->begin.minutes;

    gExamDetailsEnd.hours=ex->end.hours;
    gExamDetailsEnd.minutes=ex->end.minutes;

    // Copy contents to the memory handle
    mRoom=MemHandleNew(StrLen(ex->room)+1);
    buffer=(Char *)MemHandleLock(mRoom);
    MemSet(buffer, MemPtrSize(buffer), 0);
    StrNCopy(buffer, ex->room, StrLen(ex->room));
    MemHandleUnlock(mRoom);

    // Load fields
    old = FldGetTextHandle(fldRoom);
    FldSetTextHandle(fldRoom, mRoom);
    if (old != NULL)    MemHandleFree(old); 

    MemHandleUnlock(mex);
  }


  LstSetListChoices(course, gExamDetailsItemList, gExamDetailsNumCourses);
  if (gExamDetailsNumCourses < 5)  LstSetHeight(course, gExamDetailsNumCourses);
  else                 LstSetHeight(course, 5);
  LstSetSelection(course, selectedCourse);
  CtlSetLabel(course_tr, LstGetSelectionText(course, selectedCourse));

  ExamDetailsSetTriggers(date_tr, time_tr);
  EditTimeSetSelectorText(time_tr, &gExamDetailsBegin, &gExamDetailsEnd, gExamDetailsTimeTrigger);

}
Esempio n. 5
0
/* Handle the Control preferences */
Boolean PrefsControlPreferenceEvent
    (
    ActionType action
    )
{
    Boolean handled;
    UInt16  i;

    handled = false;

    switch ( action ) {
        case AVAILABLE:
            /* Always available */
            handled = true;
            break;

        case SHOWFIRST:
            handled = showFirst;
            showFirst = false;
            break;

        case LOAD:
            MemMove( controlSelect, Prefs()->select, sizeof( controlSelect ) );
            controlMode = Prefs()->controlMode;

            CtlSetValue( GetObjectPtr( frmPrefsControlMode1 ),
                controlMode == MODE1 );
            CtlSetValue( GetObjectPtr( frmPrefsControlMode2 ),
                controlMode == MODE2 );
            CtlSetValue( GetObjectPtr( frmPrefsControlMode3 ),
                controlMode == MODE3 );

            handled = true;
            break;

        case DISPLAY:
            PrefsShowSection( objectList, controlMode );
            prevControlMode = controlMode;

            if ( controlMode != MODE3 ) {
                for ( i = 0; i < NUM_OF_CONTROL_LISTS; i++ ) {
                    InitializeActionList( frmPrefsControlList1 + i );
                    LstSetHeight( GetObjectPtr( frmPrefsControlList1 + i ),
                        14 );
                    SetListToSelection( frmPrefsControlList1 + i,
                        frmPrefsControlPopup1 + i,
                        controlSelect[ controlMode ][ i ] );
                }
            }
            handled = true;
            break;

        case CLEAR:
            PrefsHideSection( objectList, prevControlMode );
            handled = true;
            break;

        case SAVE:
            MemMove( Prefs()->select, controlSelect, sizeof( controlSelect ) );
            Prefs()->controlMode = controlMode;
            handled = true;
            break;

        default:
            handled = false;
            break;
    }
    return handled;
}
Esempio n. 6
0
/* Populate list with bookmarks, return number of bookmarks in list */
static UInt16 InitBookmarkList
    (
    ListType* list  /* pointer to list */
    )
{
    UInt16      entries;
    UInt16      extEntries;
    UInt16      extraListItems;
    UInt16      i;
    MemHandle   handle;
    Char**      nameList;
    UInt8*      bookmarkPtr;

    handle          = NULL;
    nameList        = NULL;
    bookmarkPtr     = NULL;
    /* default is "Add bookmark" and "View bookmarks" */
    entries         = 0;
    extraListItems  = 2;

    extEntries = CountExtBookmarks();

    handle = ReturnMetaHandle( INTERNAL_BOOKMARKS_ID, NO_PARAGRAPHS );
    if ( handle != NULL ) {
        if ( isPopupList )
            extraListItems = 2;
        else
            extraListItems = 0;

        bookmarkPtr     = MemHandleLock( handle );
        entries        += GET_ENTRIES( bookmarkPtr );
        bookmarkPtr    += BOOKMARK_HEADER_LEN;
    }
    else {
        if ( ! isPopupList ) {
            extraListItems = 0;

            if ( extEntries == 0 ) {
                LstSetListChoices( list, nameList, NO_BOOKMARKS );
                LstSetDrawFunction( list, DrawListItem );

                return NO_BOOKMARKS;
            }
        }
    }
    entries += extraListItems + extEntries;

    /* Allocate arrays for name list */
    nameListHandle = MemHandleNew( entries * sizeof( *nameList ) );
    if ( nameListHandle == NULL ) {
        if ( extraListItems < entries - extEntries )
            MemHandleUnlock( handle );

        return NO_BOOKMARKS;
    }
    nameList = MemHandleLock( nameListHandle );

    if ( isPopupList ) {
        SysCopyStringResource( addBookmark, strMainAddBookmark );
        nameList[ ADD_BOOKMARK ] = addBookmark;
        SysCopyStringResource( editBookmark, strMainViewBookmark );
        nameList[ EDIT_BOOKMARK ] = editBookmark;
    }

    if ( 0 < extEntries )
        InitExtBookmarkList( nameList, extraListItems );

    if ( handle != NULL ) {
        for ( i = extraListItems + extEntries; i < entries; i++ ) {
            nameList[ i ]   = bookmarkPtr;
            bookmarkPtr    += StrLen( bookmarkPtr ) + 1;
        }
    }
    LstSetListChoices( list, nameList, entries );
    LstSetDrawFunction( list, DrawListItem );

    if ( isPopupList )
        LstSetHeight( list, entries );

    if ( extraListItems < entries - extEntries )
        MemHandleUnlock( handle );

    return entries;
}
Esempio n. 7
0
/*
** TrackXferDone
*/
static void TrackXferDone(DynamicButtonType* btn) {
  RectangleType bounds[5], frame, popFrame, popShadowFrame;
  Boolean penDown, on_button;
  Int16 x, y, clicked_on = 0;
  Int16 state = 1;
  Int16 i = 0;
  WinHandle offscreenH = NULL;
  FormType* frm = FrmGetActiveForm();
  const UInt16 listIdx = FrmGetObjectIndex(frm, XferDoneList);
  ListType* list = FrmGetObjectPtr(frm, listIdx);
  UInt16 width = 0, choices = 0;
  Err err = errNone;
  Char str[48];
  Int16 n = 0;

  /* Save the old drawing context */
  WinPushDrawState();

  /* This should match the XferDoneButton bounds */
  FrmGetObjectBounds(frm, FrmGetObjectIndex(frm, btn->id), &bounds[0]);

  /* Invert the done button */
  SelectAndDrawButton(btn, true);
  SndPlaySystemSound(sndClick);

  /* Set the status of each menu pick */
  for (; i < 4; i++)
    d.xfer.status[i] = 0x00;
  
  if (xferGotoIsAlways)
    d.xfer.status[0] = TRACKXFERDONE_ALWAYS;
  else if (xferGotoIsNever)
    d.xfer.status[0] = TRACKXFERDONE_NEVER;
  else if (p.flags&PFLAGS_XFER_GOTO)
    d.xfer.status[0] = TRACKXFERDONE_CHECKED;

  if (xferCompleteIsAlways)
    d.xfer.status[1] = TRACKXFERDONE_ALWAYS;
  else if (xferCompleteIsNever)
    d.xfer.status[1] = TRACKXFERDONE_NEVER;
  else if (d.xfer.complete)
    d.xfer.status[1] = TRACKXFERDONE_CHECKED;

  if (!d.linker_available)
    d.xfer.status[2] = TRACKXFERDONE_NEVER;
  else if (p.flags&PFLAGS_XFER_BACKLINK)
    d.xfer.status[2] = TRACKXFERDONE_CHECKED;
  if (p.flags&PFLAGS_XFER_DELETE)
    d.xfer.status[3] = TRACKXFERDONE_CHECKED;

  for (i = 0; i < 4; ++i) {
    if (!(d.xfer.status[i] & TRACKXFERDONE_NEVER)) {
      d.xfer.choice_map[choices] = i;
      ++choices;

      /* calculate list width */
      SysCopyStringResource(str, XferMenuOptionsStrings + i);
      n = FntCharsWidth(str, StrLen(str));
      width = Max(width, n);
    }
  }

  LstSetDrawFunction(list, XferDoneListDrawFunc);
  LstSetListChoices(list, 0, choices);
  LstSetHeight(list, Min(choices, 10));
  FrmGetObjectBounds(frm, listIdx, &frame);
  frame.topLeft.y = 144 - frame.extent.y - 1; /* -1 to compensate for white border */
  frame.extent.x = width + 15 + 6;
  FrmSetObjectBounds(frm, listIdx, &frame);
  WinGetFramesRectangle(popupFrame, &frame, &popFrame);
  WinGetFramesRectangle(rectangleFrame, &popFrame, &popShadowFrame);

  for (i = 0; i < choices; ++i)
    RctSetRectangle(&bounds[i+1], frame.topLeft.x, frame.topLeft.y + 10 * i, 
		    frame.extent.x, 10);

  /* Save the bits of the whole menu */
  offscreenH = WinSaveBits(&popShadowFrame, &err);
  if (err) abort();

  /* None selected */
  LstSetSelection(list, -1);

  FrmShowObject(frm, listIdx);
  WinEraseRectangle(&popShadowFrame, 0);
  LstDrawList(list);
  WinEraseRectangleFrame(rectangleFrame, &frame);
  WinDrawRectangleFrame(popupFrame, &frame);

  do {
    EvtGetPen(&x, &y, &penDown);
    if (!state || !RctPtInRectangle(x, y, &bounds[state-1])) {
      on_button = false;
      for (i = 1; i <= choices + 1; i++) {
	if ((state != i) && RctPtInRectangle(x, y, &bounds[i-1])) {
	  /* Invert the new state */
	  LstSetSelection(list, i - 2);
	  LstDrawList(list);
	  WinEraseRectangleFrame(rectangleFrame, &frame);
	  WinDrawRectangleFrame(popupFrame, &frame);
	  
	  SelectAndDrawButton(btn, i == 1);
	  
	  state = i;
	  on_button = true;
	}
      }

      if (state && !on_button) {
	/* Moved off the current button */
	LstSetSelection(list, -1);
	LstDrawList(list);
	WinEraseRectangleFrame(rectangleFrame, &frame);
	WinDrawRectangleFrame(popupFrame, &frame);

	if (state == 1) 
	  SelectAndDrawButton(btn, false);
	state = 0;
      }
    }
  } while (penDown);

  FrmHideObject(frm, listIdx);
  LstEraseList(list);

  /* Restore the framed rect */
  WinRestoreBits(offscreenH, popShadowFrame.topLeft.x, popShadowFrame.topLeft.y);

  /* Unselect the button */
  SelectAndDrawButton(btn, false);

  /* Finish up if we just tapped the button */
  if (RctPtInRectangle(x, y, &bounds[0])) {
    FinishXferMode();
    
    /* Restore the old draw state */
    WinPopDrawState();
    return;
  }

  /* Change the setting for goto or delete */
  for (i = 1; i <= choices; i++) {
    if (RctPtInRectangle(x, y, &bounds[i])) {
      clicked_on = i;
      break;
    }
  }

  if (clicked_on) 
    clicked_on = d.xfer.choice_map[clicked_on-1] + 1;

  switch (clicked_on) {
  case 1: /* Goto */
    if (d.xfer.status[0] & TRACKXFERDONE_CHECKED)
      p.flags &= ~PFLAGS_XFER_GOTO;
    else if (!d.xfer.status[0])
      p.flags |= PFLAGS_XFER_GOTO;
    break;
  case 2: /* Complete */
    if (d.xfer.status[1] & TRACKXFERDONE_CHECKED)
      d.xfer.complete = false;
    else if (!d.xfer.status[1])
      d.xfer.complete = true;
    break;
  case 3: /* BackLink */
    if (d.xfer.status[2] & TRACKXFERDONE_CHECKED)
      p.flags &= ~PFLAGS_XFER_BACKLINK;
    else if (!d.xfer.status[2]) {
      p.flags |= PFLAGS_XFER_BACKLINK;
      p.flags &= ~PFLAGS_XFER_DELETE; /* No delete if backlink */
    }
    break;
  case 4: /* Delete */
    if (d.xfer.status[3] & TRACKXFERDONE_CHECKED)
      p.flags &= ~PFLAGS_XFER_DELETE;
    else if (!d.xfer.status[3]) {
      p.flags |= PFLAGS_XFER_DELETE;
      p.flags &= ~PFLAGS_XFER_BACKLINK; /* No backlink if delete */
    }
    break;
  }

  /* Click and redraw the button */
  if (clicked_on) {
    DrawXferDoneButton(btn);
    DynBtnDraw(btn);
    
    if (d.xfer.status[clicked_on-1] & TRACKXFERDONE_ALWAYS)
      SndPlaySystemSound(sndWarning);
    else
      SndPlaySystemSound(sndClick);
  }

  /* Restore the old draw state */
  WinPopDrawState();
}
Esempio n. 8
0
/* Populate list with bookmarks, return number of bookmarks in list */
static UInt16 InitBookmarkList
    (
    ListType* list  /* pointer to list */
    )
{
    UInt16      recordNum;
    UInt16      numRecords;
    UInt16      extEntries;
    UInt16      bookmarks;
    UInt16      extraListItems;
    UInt16      index;
    UInt16      i;

    if ( isPopupList ) {
#ifdef SUPPORT_ANNOTATION
        extraListItems  = 3;
#else
        extraListItems  = 2;
#endif
    }
    else {
        extraListItems  = 0;   
    }

    ReleaseBookmarkList();

    extEntries  = CountExtBookmarks();
    bookmarks   = CountBookmarks();
    numRecords  = GetNumberOfAnnotations();

    numEntries  = extraListItems + extEntries + bookmarks;

    if ( numEntries == 0 ) {
        LstSetListChoices( list, nameList, NO_BOOKMARKS );
        LstSetDrawFunction( list, DrawListItem );

        return NO_BOOKMARKS;
    }

    bookmarkList = SafeMemPtrNew( numEntries *
                            sizeof( BookmarkListEntry* ) );

    for ( i = 0 ; i < numEntries ; i++ ) {
         bookmarkList[ i ] = SafeMemPtrNew( sizeof( BookmarkListEntry ) );
         MemSet( bookmarkList[ i ], sizeof( BookmarkListEntry ), 0 );
    }

    /* Allocate arrays for name list */
    nameList = SafeMemPtrNew( numEntries * sizeof( Char* ) );

    if ( isPopupList ) {
        SysCopyStringResource( addBookmark, strMainAddBookmark );
        nameList[ ADD_BOOKMARK ] = addBookmark;
        bookmarkList[ ADD_BOOKMARK ]->kind = BOOKMARK_ADD_BOOKMARK;
#ifdef SUPPORT_ANNOTATION
        SysCopyStringResource( addAnnotation, strMainAddAnnotation );
        nameList[ ADD_ANNOTATION ] = addAnnotation;
        bookmarkList[ ADD_ANNOTATION ]->kind = BOOKMARK_ADD_ANNOTATION;
#endif
        SysCopyStringResource( editBookmark, strMainViewBookmark );
        nameList[ EDIT_BOOKMARK ] = editBookmark;
        bookmarkList[ EDIT_BOOKMARK ]->kind = BOOKMARK_EDIT_BOOKMARK;
    }

    if ( 0 < extEntries ) {
        InitExtBookmarkList( nameList, extraListItems );
        for ( i = extraListItems ; i < extraListItems + extEntries ; i++ ) {
             bookmarkList[ i ]->kind      = BOOKMARK_EXT_BOOKMARK;
             bookmarkList[ i ]->recordNum = i - extraListItems;
        }
    }
    
    index = extraListItems + extEntries;
    
    for ( recordNum = 0 ; recordNum < numRecords && index < numEntries ;
          recordNum++ ) {

         MemHandle h;
         
         h = GetAnnotationByRecordNum( recordNum );
         
         if ( h != NULL ) {
             AnnotationEntry* entryP;

             entryP = MemHandleLock( h );
             
             if ( 1 < entryP->dataLength &&
                  ! ( ! ( entryP->flags & ANNOTATION_BOOKMARK ) &&
                    Prefs()->noAnnotationsInBookmarkList ) ) {
                 UInt32 labelSize;

                 labelSize = entryP->dataLength - 1;

                 if ( MAX_BOOKMARK_ENTRY_LENGTH < labelSize )
                     labelSize = MAX_BOOKMARK_ENTRY_LENGTH;

                 bookmarkList[ index ]->text = MemPtrNew( labelSize + 1 );

                 if ( bookmarkList[ index ]->text != NULL ) {
                     bookmarkList[ index ]->kind =
                         ( entryP->flags & ANNOTATION_BOOKMARK ) ?
                                BOOKMARK_BOOKMARK :
                                BOOKMARK_ANNOTATION;
                     bookmarkList[ index ]->recordNum = recordNum;

                     StrNCopy( bookmarkList[ index ]->text,
                         ( Char* )entryP + entryP->dataOffset, labelSize + 1 );
                     bookmarkList[ index ]->text[ labelSize ] = 0;

                     nameList[ index ] = bookmarkList[ index ]->text;

                     index++;
                 }
             }

             MemHandleUnlock( h );
         }
    }
    
    numEntries = index;

    LstSetListChoices( list, nameList, numEntries );
    LstSetDrawFunction( list, DrawListItem );

    if ( isPopupList )
        LstSetHeight( list, numEntries );

    return numEntries;
}
Esempio n. 9
0
/***********************************************************************
 *
 * FUNCTION:    SelectTimeZone
 *
 * DESCRIPTION: Display a form showing a time zone and allow the user
 *              to select a different time zone. This is the time zone
 *					 dialog as seen in Date & Dime panel
 *
 * PARAMETERS:
 *		ioTimeZoneP				<->	pointer to time zone to change
 *		ioLocaleInTimeZoneP	<->	Ptr to locale found in time zone.
 *		titleP					 ->	String title for the dialog.
 *		showTimes				 -> 	True => show current and new times
 *		anyLocale				 ->	True => ignore ioLocaleInTimeZoneP on entry.
 *
 * RETURNED:
 *		true if the OK button was pressed (in which case *ioTimeZoneP and
 *		*ioCountryInTimeZoneP might be changed).
 *
 * HISTORY:
 *		03/02/00	peter	Created by Peter Epstein.
 *		04/03/00	peter	Allow NULL currentTimeP.
 *		04/12/00	peter API changed to get rid of trigger text
 *		04/14/00	peter Update current & new time as time passes
 *		07/31/00	kwk	Use SysTicksPerSecond() routine vs. sysTicksPerSecond macro.
 *					kwk	Re-wrote to use set of resources (name, offset, country),
 *							scrollbar vs. arrows, etc.
 *		08/01/00	kwk	Support scroll-to-key. Fixed scrollbar/list sync bugs.
 *		08/02/00	kwk	New API w/ioCountryInTimeZoneP and anyCountry parameters.
 *					kwk	Call FrmHandleEvent _after_ our event handling code has
 *							decided that it doesn't want to handle the event, not before.
 *		08/03/00	kwk	Call LstSetListChoices before calling LstGetVisibleItems,
 *							as otherwise accessing the time zone picker from the
 *							Setup app (when <showTimes> is false) gives you a two-
 *							line high display because LstGetVisibleItems returns 0.
 *		08/18/00	kwk	Play error sound if user writes letter that doesn't
 *							match any entries.
 *					kwk	Don't select item if doing scroll-to-view for entry
 *							that matches the letter the user wrote.
 *		08/21/00	kwk	Scroll-to-view with text entry now scrolls to the top
 *							of the list, versus the middle.
 *		10/09/00	peter	Get rid of scroll bar and let list do the scrolling.
 *		11/17/00	CS		Change ioCountryInTimeZoneP to ioLocaleInTimeZoneP,
 *							(and anyCountry to anyLocale, but that doesn't matter),
 *							since CountryType is only a UInt8, and this may
 *							change someday.
 *
 ***********************************************************************/
Boolean SelectTimeZone(Int16 *ioTimeZoneP, LmLocaleType* ioLocaleInTimeZoneP,
				const Char *titleP, Boolean showTimes, Boolean anyLocale)
{
	FormType* originalForm;
	FormType* dialog;
	EventType event;
	Boolean confirmed = false;
	Boolean done = false;
	Boolean adjustTimes = false;
	Boolean foundLocale = false;
	MemHandle currentTimeHandle, newTimeHandle;
	ListPtr listP;
	Int16 oldTimeZone, newTimeZone, testTimeZone;
	LmLocaleType newTimeZoneLocale;
	Int16 delta, closestDelta, timeZoneIndex, closestIndex;
	DateTimeType currentTime, newTime;
	TimeZoneEntryType* tzArrayP;
	UInt16 numTimeZones;
	MemHandle tzNamesH;
	
	if (showTimes)
	{
		TimSecondsToDateTime(TimGetSeconds(), &currentTime);
	}
	
	oldTimeZone = *ioTimeZoneP;
	newTimeZone = oldTimeZone;
	newTimeZoneLocale = *ioLocaleInTimeZoneP;
	
	originalForm = FrmGetActiveForm();
	dialog = (FormType *) FrmInitForm (TimeZoneDialogForm); 
	listP = FrmGetObjectPtr (dialog, FrmGetObjectIndex (dialog, TimeZoneDialogTimeZoneList));
	
	if (titleP)
	{
		FrmSetTitle (dialog, (Char *) titleP);
	}
	
	FrmSetActiveForm (dialog);
	
	// We need to call LstSetListChoices before calling LstSetHeight below, as otherwise
	// LstGetVisibleItems will return 0.
	tzArrayP = PrvCreateTimeZoneArray(&tzNamesH, &numTimeZones);
	LstSetListChoices(listP, (Char**)tzArrayP, numTimeZones);
	
	if (showTimes)
	{
		currentTimeHandle = MemHandleNew(timeStringLength + 1 + dowLongDateStrLength + 1);
		ErrFatalDisplayIf (!currentTimeHandle, "Out of memory");
		newTimeHandle = MemHandleNew(timeStringLength + 1 + dowLongDateStrLength + 1);
		ErrFatalDisplayIf (!newTimeHandle, "Out of memory");

		PrvSetTimeField(dialog, TimeZoneDialogCurrentTimeField, currentTimeHandle, &currentTime, false);
	}
	else
	{
		// Hide the current and new time.
		FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogCurrentTimeLabel));
		FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogCurrentTimeField));
		FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogNewTimeLabel));
		FrmHideObject(dialog, FrmGetObjectIndex (dialog, TimeZoneDialogNewTimeField));
		
		// Make the list show more items to take up extra the space.
		LstSetHeight(listP, LstGetVisibleItems(listP) + extraTimeZonesToShowWhenNoTimes);
	}
	
	// Find the time zone in the list closest to the current time zone, and that
	// matches <*ioLocaleInTimeZoneP> if <anyLocale> is false.
	closestDelta = hoursInMinutes * hoursPerDay;		// so big that all others will be smaller
	for (timeZoneIndex = 0; timeZoneIndex < numTimeZones; timeZoneIndex++)
	{
		Boolean checkDelta = anyLocale;
		testTimeZone = tzArrayP[timeZoneIndex].tzOffset;
		delta = Abs(testTimeZone - oldTimeZone);
		
		if (!anyLocale)
		{
			if (tzArrayP[timeZoneIndex].tzCountry == ioLocaleInTimeZoneP->country)
			{
				// If we haven't previously found a matching locale, reset the
				// delta so that this entry overrides any previous best entry.
				if (!foundLocale)
				{
					foundLocale = true;
					closestDelta = hoursInMinutes * hoursPerDay;
				}
				
				checkDelta = true;
			}
			
			// If we haven't yet found a matching locale, go for the closest delta.
			else
			{
				checkDelta = !foundLocale;
			}
		}
		
		// If we want to check the time zone delta, do it now.
		if (checkDelta && (delta < closestDelta))
		{
			closestIndex = timeZoneIndex;
			closestDelta = delta;
		}
	}
	
	// Scroll so that time zone is in the center of the screen and select it if it's an exact match.
	LstSetTopItem(listP, max(0, closestIndex - (LstGetVisibleItems(listP) / 2)));
	if ((closestDelta == 0) && (anyLocale || foundLocale))
	{
		LstSetSelection(listP, closestIndex);
		if (showTimes)
		{
			newTime = currentTime;
			PrvSetTimeField(dialog, TimeZoneDialogNewTimeField, newTimeHandle, &newTime, false);
		}
	}
	else
	{
		LstSetSelection(listP, noListSelection);
	}
	
	LstSetDrawFunction(listP, PrvTimeZoneListDrawItem);
	
	FrmDrawForm (dialog);
	
	while (!done)
	{
		Boolean handled = false;
		EvtGetEvent(&event, SysTicksPerSecond());		// so we can update the current and new time

		if (SysHandleEvent ((EventType *)&event))
		{
			continue;
		}
		
		if (event.eType == nilEvent)
		{
			if (showTimes)
			{
				PrvUpdateTimeFields(	dialog,
										&currentTime,
										&newTime,
										currentTimeHandle,
										newTimeHandle,
										TimeZoneDialogCurrentTimeField,
										TimeZoneDialogNewTimeField);
			}
		}
		
		else if (event.eType == ctlSelectEvent)
		{
			handled = true;
			
			switch (event.data.ctlSelect.controlID)
			{
				case TimeZoneDialogOKButton:
					// Set the new time zone.
					*ioTimeZoneP = newTimeZone;
					*ioLocaleInTimeZoneP = newTimeZoneLocale;

					done = true;
					confirmed = true;
				break;

				case TimeZoneDialogCancelButton:
					done = true;
				break;
				
				default:
					ErrNonFatalDisplay("Unknown control in form");
				break;
			}
		}
		
		// User tapped on a time zone in the list.
		else if (event.eType == lstSelectEvent)
		{
			UInt16 localeIndex;
			
			ErrNonFatalDisplayIf(event.data.lstSelect.listID != TimeZoneDialogTimeZoneList,
										"Unknown list in form");
			
			newTimeZone = tzArrayP[event.data.lstSelect.selection].tzOffset;
			newTimeZoneLocale.country =
				tzArrayP[event.data.lstSelect.selection].tzCountry;
			newTimeZoneLocale.language = lmAnyLanguage;
			if (LmLocaleToIndex(&newTimeZoneLocale, &localeIndex) == errNone)
			{
				if (LmGetLocaleSetting(	localeIndex,
												lmChoiceLocale,
												&newTimeZoneLocale,
												sizeof(newTimeZoneLocale)))
				{
					ErrNonFatalDisplay("Can\'t get locale");
				}
			}
			adjustTimes = showTimes;
			handled = true;
		}

		else if (event.eType == keyDownEvent)
		{
			if	(!TxtCharIsHardKey(event.data.keyDown.modifiers, event.data.keyDown.chr))
			{
				//	Hard scroll buttons
				if (EvtKeydownIsVirtual(&event))
				{
					if (event.data.keyDown.chr == vchrPageUp)
					{
						handled = true;
						LstScrollList(listP, winUp, LstGetVisibleItems(listP) - 1);
					}
					else if (event.data.keyDown.chr == vchrPageDown)
					{
						handled = true;
						LstScrollList(listP, winDown, LstGetVisibleItems(listP) - 1);
					}
				}
				else if (TxtCharIsPrint(event.data.keyDown.chr))
				{
					Int16 index;
					
					handled = true;
					index = PrvSearchTimeZoneNames(tzArrayP, numTimeZones, event.data.keyDown.chr);
					
					if (index != noListSelection)
					{
						Int16 delta = index - listP->topItem;
						if (delta < 0)
						{
							LstScrollList(listP, winUp, -delta);
						}
						else if (delta > 0)
						{
							LstScrollList(listP, winDown, delta);
						}
					}
					else
					{
						SndPlaySystemSound(sndError);
					}
				}
			}
		}

		else if (event.eType == appStopEvent)
		{
			EvtAddEventToQueue (&event);
			done = true;
			break;
		}
		
		// If we didn't handle the event, give the form code a crack at it.
		// This simulates the "normal" method of installing an event handler
		// for a form, which gets called, and then if it returns false, the
		// FrmHandleEvent routine gets called.
		if (!handled)
		{
			FrmHandleEvent(dialog, &event); 
		}
		
		// If something changed, and we need to update our time display,
		// do it now.
		if (adjustTimes)
		{
			adjustTimes = false;
			newTime = currentTime;
			TimAdjust(&newTime, (Int32)(newTimeZone - oldTimeZone) * minutesInSeconds);
			PrvSetTimeField(dialog, TimeZoneDialogNewTimeField, newTimeHandle, &newTime, true);
		}
	}	// end while true
		
	if (showTimes)
	{
		FldSetTextHandle(FrmGetObjectPtr (dialog, FrmGetObjectIndex (dialog, TimeZoneDialogCurrentTimeField)), NULL);
		FldSetTextHandle(FrmGetObjectPtr (dialog, FrmGetObjectIndex (dialog, TimeZoneDialogNewTimeField)), NULL);
		MemHandleFree(currentTimeHandle);
		MemHandleFree(newTimeHandle);
	}
	
	FrmEraseForm (dialog);
	FrmDeleteForm (dialog);
	FrmSetActiveForm(originalForm);

	PrvDeleteTimeZoneArray(tzArrayP, tzNamesH);

	return confirmed;
} // SelectTimeZone