Beispiel #1
0
/***********************************************************************
 *
 * FUNCTION:    FntSetFont
 *
 * DESCRIPTION: This routine set the current font.  If the font is a valid
 * font but doesn't exist, the stdFont is used.
 *
 * PARAMETERS:  fontID   id of the font to make the active font
 *
 * RETURNED:    ID of the current font prior to the change.
 *
 * REVISION HISTORY:
 *			Name	Date		Description
 *			----	----		-----------
 *			art	12/14/94	Initial Revision
 *			roger	9/26/97	Now substitutes the stdFont for missing fonts
 *			SCL	12/10/97	Rewrote to support new (separate) font tables
 *			SCL	1/23/98	Now uses stdFont if passed an invalid font
 *			bob	3/5/99	Update GState values with new font
 *
 ***********************************************************************/
FontID FntSetFont (FontID fontID)
{
	FontID newFontID = fontID;
	FontID oldFontID;

	// See if fontID is a valid system font or app font ID
	if ( !FntIsAppDefined(newFontID) ? (newFontID >= UINumSysFonts) :
			(newFontID-fntAppFontCustomBase >= UINumAppFonts) ) {
		ErrNonFatalDisplay("Invalid font");
		newFontID = stdFont;
	}
	
	oldFontID = UICurrentFontID;
	UICurrentFontID = newFontID;
	
	// Set the new font or a default one.
	if ( FntIsAppDefined(newFontID) ) {
		UICurrentFontPtr = UIAppFontPtr[newFontID-fntAppFontCustomBase];
	} else {
		UICurrentFontPtr = UISysFontPtr[newFontID];
	}

	if (UICurrentFontPtr == NULL)
		UICurrentFontPtr = UISysFontPtr[stdFont];

	GState.drawStateP->fontId = UICurrentFontID;
	GState.drawStateP->font = UICurrentFontPtr;

	ErrNonFatalDisplayIf (UICurrentFontPtr == NULL, "Invalid font");
	
	return oldFontID;
}
Beispiel #2
0
/***********************************************************************
 *
 * FUNCTION:	StrChr
 *
 * DESCRIPTION: This routine looks for a character within a string. It
 *		behaves the same as the standard C library function strchr, except
 *		that it works correctly with multi-byte character encodings.
 *
 * PARAMETERS:
 *		str  - string to search
 *		chr  - the character to search for
 *
 * RETURNED:	pointer to the first occurance of character in str, or NULL
 *		if not found.
 *
 * HISTORY:
 *		08/18/95	ron	Created by Ron Marianetti
 *		05/07/96	rsf	Fixed to MemHandle searching for '\0'
 *		10/24/96	rsf	Check chr
 *		08/12/97	ADH	Revised Algorithm
 *		08/26/98	kwk	Changed chr param from Int16 to WChar. Fixed up
 *							sign extension problem.
 *		05/13/00	kwk	Made it work for all char encodings, not just Latin.
 *
 ***********************************************************************/
Char* StrChr(const Char* str, WChar chr)
{
	Char c = (Char)chr;
	register const Char* srcP = str;
	
	ErrNonFatalDisplayIf(str == NULL, "NULL string passed");

	// Correct for sign extension. This will happen if the caller passes
	// a single byte >= 0x80, which the compiler will sign extend.
	if (chr >= 0xFF80)
	{
		ErrNonFatalDisplay("Sign extended character passed to StrChr");
		chr = chr & 0x00FF;
	}
	
	// See if we need to do the slower (multi-byte) search case.
	if (chr > kTxtMaxAlwaysSingleByte)
	{
		Char buffer[maxCharBytes + 1];
		UInt16 len = TxtSetNextChar(buffer, 0, chr);
		if (len > 1)
		{
			buffer[len] = '\0';
			return(StrStr(str, buffer));
		}
	}
	
	// Be sure to handle chr == '\0' correctly
	do
	{
		if (*srcP == c)
		{
			// If the character we're searching for could be part of a
			// multi-byte character, then we need to do an extra check
			// to make sure we didn't find part of a multi-byte character.
			// Since most people use StrChr to search for tabs, returns,
			// etc. this typically never gets executed.
			if (chr > kTxtMaxNeverMultiByte)
			{
				UInt32 charStart, charEnd;
				UInt32 charOffset = srcP - str;
				TxtCharBounds(str, charOffset, &charStart, &charEnd);
				if (charStart == charOffset)
				{
					return((Char*)srcP);
				}
			}
			else
			{
				return((Char*)srcP);
			}
		}
	} while (*srcP++ != 0);
	
	return(NULL);
} // StrChr
Beispiel #3
0
/***********************************************************************
 *
 * FUNCTION:    FntWCharWidth
 *
 * DESCRIPTION: This routine returns the width of the specified character,
 *		which can be any valid character character. If the specified
 *		character does not exist within the current font, the Missing Char
 *		Symbol will be substituted.
 *
 * PARAMETERS:  ch   character whose width is desired
 *
 * RETURNED:    width of the specified character, in pixels
 *
 * HISTORY:
 *		05/12/00	kwk	Created by Ken Krugler from TxtCharWidth.
 *		05/17/00	kwk	Add call to TxtCharIsValid on debug ROMs.
 *
 ***********************************************************************/
Int16 FntWCharWidth(WChar iChar)
{
	Char buffer[maxCharBytes];

	if (iChar >= 0xFF80) {
		ErrNonFatalDisplay("Sign extended char passed to FntWCharWidth");
		iChar &= 0x00FF;
	}

	// On debug ROMs, make sure the character is valid (e.g. not a
	// virtual character).
	ErrNonFatalDisplayIf(!TxtCharIsValid(iChar), "Invalid char passed to FntWCharWidth");
	
	return(FntCharsWidth(buffer, TxtSetNextChar(buffer, 0, iChar)));
} // FntWCharWidth
Beispiel #4
0
/************************************************************
 *
 *	FUNCTION:	PrvConvertIToH	<internal>
 *
 *	DESCRIPTION: convert an integer to hexadecimal ascii
 *
 *	PARAMETERS: Integer to convert and string pointer to store results
 *
 *	RETURNS: s
 *
 *	HISTORY:
 *		07/04/95	RM		Created by Ron Marianetti
 *		07/31/97	AdamH	Modified to return the end of the string to work with
 *							StrVPrintF.
 *		04/02/98	roger	Added sizeModifier and fixed to emit less than 8 digits when not a long
 *		11/08/99	kwk	Non-fatal alert if unknown sizeModifier.
 *
 *************************************************************/
static Char * PrvConvertIToH(Char * s, UInt32 number, SizeModifierType sizeModifier)
{
	UInt32		mask;
	UInt32		digit;
	UInt16		digitCount;
	
	// Check for err
	ErrNonFatalDisplayIf(s == NULL, "NULL string passed");
	
	switch (sizeModifier)
	   {
		case sizeLong:
			digitCount = 8;
		   break;
		case sizeShort: 
			digitCount = 4;
			number <<= 16;
		   break;
		case sizeInt:
			digitCount = 4;
			number <<= 16;
		   break;
		default:
			ErrNonFatalDisplay("Invalid sizeModifier");
			digitCount = 8;
			break;
		}
	
	mask = 0xF0000000;
	while (digitCount-- > 0) 
		{
		digit = (number & mask) >> 28;
		if (digit < 0x0A) 
			*s++ = digit + '0';
		else
			*s++ = digit - 10 + 'A';
			
		number <<= 4;
		}
	*s = '\0';

	return s;
}
Beispiel #5
0
/***********************************************************************
 *
 * FUNCTION:    SelectTime
 *
 * DESCRIPTION: Display a form showing a start and end time.
 *					 Allow the user to change the time and then
 *              return them.
 *					 pTimeDiff.
 *
 * PARAMETERS:  pStartTime	- pointer to TimeType
 *              pEndTime   - pointer to TimeType
 *              untimed  	- true if there isn't a time.
 *              title	   - string containing the title
 *              startOfDay - used when "All Day" button selected.
 *					 endOfDay	- our used when "All Day" button selected.
 *              startOfDisplay - first hour initially visible
 *
 * RETURNED:	 True if the time was changed by the user.
 * 				 The first three parameters may change.
 *
 * REVISION HISTORY:
 *			Name	Date		Description
 *			----	----		-----------
 *			roger	12/2/94	Initial Revision
 *			trev	08/12/97	made non modified passed variables constant
 *			css	06/08/99	added new parameter & "All Day" button for gromit change.
 *
 ***********************************************************************/
Boolean SelectTime (TimeType * startTimeP, TimeType * endTimeP, 
	Boolean untimed, const Char * titleP, Int16 startOfDay, Int16 endOfDay, 
	Int16 startOfDisplay)
{
	Int16							firstHour;
	Char 							startTimeText [timeStringLength];
	Char 							endTimeText [timeStringLength];
	Char							timeChars [timeStringLength];
	TimePtr						timeP;
	FormType 					*originalForm, *frm;
	ListPtr 						hoursLst, minutesLst;
	ControlPtr 					startTimeCtl, endTimeCtl;
	EventType 					event;
	Boolean 						confirmed = false;
	MemHandle 						hoursItems;
	TimeType 					startTime, endTime, timeDiff;
	TimeFormatType 			timeFormat;
	ChangingTimeType			changingTime;

	// Get the time format from the system preerances;
	timeFormat = (TimeFormatType)PrefGetPreference(prefTimeFormat);


	// Because this routine only deals with minutes in five minute
	// intervals we convert the proposed times from those passed.
	startTime.hours = startTimeP->hours;
	startTime.minutes = startTimeP->minutes;
	endTime.hours = endTimeP->hours;
	endTime.minutes = endTimeP->minutes;
	TimeDifference (&endTime, &startTime, &timeDiff);
	
	// Make sure the end time is displayable (clips at 11:55 pm)
	AdjustTimes (&startTime, &endTime, &timeDiff, changingStartTime);
	
	// Clear the buffer that holds written characters.
	*timeChars = 0;

	startOfDisplay = min (startOfDisplay, 12);

	originalForm = FrmGetActiveForm();
	frm = (FormType *) FrmInitForm (TimeSelectorForm);
	FrmSetActiveForm (frm);

	hoursLst = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorHourList));
	minutesLst = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorMinuteList));
	startTimeCtl = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorStartTimeButton));
	endTimeCtl = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorEndTimeButton));


	// Set list to use either 12 or 24 hour time
	hoursItems = SysFormPointerArrayToStrings (
		((timeFormat == tfColon24h) || (timeFormat == tfDot24h)) ? 
			(Char *) Hours24Array() : (Char *) Hours12Array(), 24);
 
 	LstSetListChoices (hoursLst, MemHandleLock(hoursItems), 24);
	LstSetTopItem (hoursLst, startOfDisplay);
	//	Used to do LstMakeItemVisible (hoursLst, startTime.hours); no longer.


	if (! untimed)
		{
		LstSetSelection (hoursLst, startTime.hours);
		LstSetSelection (minutesLst, startTime.minutes / 5);

		CtlSetValue (startTimeCtl, true);
		changingTime = changingStartTime;
		}
	else
		{
		// The hour list is dynamically created and doesn't have a selection
		LstSetSelection (minutesLst, noListSelection);

		changingTime = changingNoTime;
		}


	// Set the start and end time buttons to the current times or blank them
	// if No Time is selected.
	SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, 
		timeFormat, untimed);
		

	// This needs to be taken out when SelectTimeV33 goes away.  It allows for backward 
	// compatibility for this change of adding the end of day variable as a parameter.
	if (endOfDay != noDisplayOfAllDay)
	{
	  FrmShowObject (frm, FrmGetObjectIndex (frm, TimeSelectorAllDayButton));
	}
	
	FrmSetTitle (frm, (Char *) titleP);
	FrmDrawForm (frm);
	
	
	while (true)
		{
		EvtGetEvent (&event, evtWaitForever);

		if (SysHandleEvent ((EventType *)&event))
			continue;
			
		if (event.eType == appStopEvent)
			{
			// Cancel the dialog and repost this event for the app
			EvtAddEventToQueue(&event);
			confirmed = false;
			break;
			}
			
		// Handle these before the form does to overide the default behavior
		if (changingTime == changingNoTime &&
			event.eType == lstEnterEvent && 
			event.data.lstEnter.listID == TimeSelectorMinuteList)
			{
			SndPlaySystemSound(sndError);
			continue;
			}

		FrmHandleEvent (frm, &event);


		// If the start or end time buttons are pressed then change
		// the time displayed in the lists.
		if (event.eType == ctlSelectEvent)
			{
			// "Ok" button pressed?
			if (event.data.ctlSelect.controlID == TimeSelectorOKButton)
				{
				confirmed = true;
				}

			// "Cancel" button pressed?
			else if (event.data.ctlSelect.controlID == TimeSelectorCancelButton)
				{
				break;
				}

			// Start time button pressed?
			else if (event.data.ctlSelect.controlID == TimeSelectorStartTimeButton)
				{
				if (changingTime != changingStartTime)
					{
					if (changingTime == changingNoTime)
						{
						SetTimeTriggers (startTime, endTime, startTimeText, 
							endTimeText, timeFormat, false);
						}

					CtlSetValue (endTimeCtl, false);
					LstSetSelection (hoursLst, startTime.hours);
					LstSetSelection (minutesLst, startTime.minutes / 5);
					changingTime = changingStartTime;
					}
				else
					CtlSetValue(startTimeCtl, true);
				}

			// End time button pressed?
			else if (event.data.ctlSelect.controlID == TimeSelectorEndTimeButton)
				{
				if (changingTime != changingEndTime)
					{
					if (changingTime == changingNoTime)
						{
						SetTimeTriggers (startTime, endTime, startTimeText, 
							endTimeText, timeFormat, false);
						}

					CtlSetValue(startTimeCtl, false);
					LstSetSelection (hoursLst, endTime.hours);
					LstSetSelection (minutesLst, endTime.minutes / 5);
					changingTime = changingEndTime;
					}
				else
					CtlSetValue(endTimeCtl, true);
				}

			// No time button pressed?
			else if (event.data.ctlSelect.controlID == TimeSelectorNoTimeButton)
				{
				if (changingTime != changingNoTime)
					{
					if (changingTime == changingStartTime)
						CtlSetValue(startTimeCtl, false);
					else
						CtlSetValue(endTimeCtl, false);
					SetTimeTriggers (startTime, endTime, startTimeText, 
						endTimeText, timeFormat, true);
					
					LstSetSelection (hoursLst, noListSelection);
					LstSetSelection (minutesLst, noListSelection);
					changingTime = changingNoTime;
					}
					// Get us out of this form display now.
					confirmed = true;
				}

			// All day button pressed?
			else if (event.data.ctlSelect.controlID == TimeSelectorAllDayButton)
				{
				if (changingTime != changingNoTime)
					{
					if (changingTime == changingStartTime)
						CtlSetValue(startTimeCtl, false);
					else
						CtlSetValue(endTimeCtl, false);
					
					LstSetSelection (hoursLst, noListSelection);
					LstSetSelection (minutesLst, noListSelection);
					changingTime = changingNoTime;
					}
											
					// No matter what, the minutes are 0 for both because only the hour is registered for start/end
					// times.
					startTime.minutes = 0;
					endTime.minutes 	= 0;
					startTime.hours 	= startOfDay;
					endTime.hours 		= endOfDay;
					
					// Set the times to the new times.
					SetTimeTriggers (startTime, endTime, startTimeText, 
						endTimeText, timeFormat, true);
					// Get us out of this form display now.  First set the changing time to anything but the changingNoTime value
					// so that the pointers at the end of this function get set correctly.
					changingTime = changingStartTime;
					confirmed = true;
				}

			// Clear the buffer that holds written characters.
			*timeChars = 0;
			}


		// If either list is changed then get the new time.  If the
		// start time is changed then change the end time so that the
		// the time difference remains the same.  If the end time is
		// changed then make sure the end time isn't before the start
		// time.  Also calculate a new time difference.
		else if (event.eType == lstSelectEvent)
			{
         // First, get the info from the list which has changed.
			if (event.data.lstSelect.listID == TimeSelectorHourList)
				{
				if (changingTime == changingStartTime)
               startTime.hours = (UInt8) LstGetSelection (hoursLst);
           	else if (changingTime == changingEndTime)
               endTime.hours = (UInt8) LstGetSelection (hoursLst);
           	else if (changingTime == changingNoTime)
           		{
               startTime.hours = (UInt8) LstGetSelection (hoursLst);
					SetTimeTriggers (startTime, endTime, startTimeText, 
						endTimeText, timeFormat, false);
					CtlSetValue (endTimeCtl, false);
					LstSetSelection (minutesLst, startTime.minutes / 5);
					changingTime = changingStartTime;
					}
				}
         else if (event.data.lstSelect.listID == TimeSelectorMinuteList)
				{
				if (changingTime == changingStartTime)
               startTime.minutes = (UInt8) LstGetSelection (minutesLst) * 5;
           	else if (changingTime == changingEndTime)
					endTime.minutes = (UInt8) LstGetSelection (minutesLst) * 5;
           	else if (changingTime == changingNoTime)
           		{
               ErrNonFatalDisplay("lstEnterEvent not being filtered.");
               }
				}


			if (AdjustTimes (&startTime, &endTime, &timeDiff, changingTime))
				{
				if (changingTime == changingStartTime)
					{
					TimeToAscii (startTime.hours, startTime.minutes, timeFormat, 
						startTimeText);
					CtlSetLabel (startTimeCtl, startTimeText);
					}
				else if (changingTime == changingEndTime)
					{
					LstSetSelection (hoursLst, startTime.hours);
					LstSetSelection (minutesLst, startTime.minutes / 5);
					}
				}
			TimeToAscii(endTime.hours, endTime.minutes, timeFormat, endTimeText);
			CtlSetLabel(endTimeCtl, endTimeText);


			// Clear the buffer that holds written characters.
			*timeChars = 0;
			}


		// Handle character written in the time picker.
		else if (event.eType == keyDownEvent)
			{
			if (changingTime == changingEndTime)
				{
				timeP = &endTime;
				firstHour = startTime.hours;
				}
			else
				{
				timeP = &startTime;
				firstHour = startOfDisplay;
				}
		
			// If a backspace character was written, change the time picker's
			// current setting to "no-time".
			if (event.data.keyDown.chr == backspaceChr)
				{
				*timeChars = 0;
				if (changingTime != changingNoTime)
					{
					if (changingTime == changingStartTime)
						CtlSetValue (startTimeCtl, false);
					else
						CtlSetValue (endTimeCtl, false);
					SetTimeTriggers (startTime, endTime, startTimeText, 
						endTimeText, timeFormat, true);
					LstSetSelection (hoursLst, noListSelection);
					LstSetSelection (minutesLst, noListSelection);
					changingTime = changingNoTime;
					}
				}

			// A linefeed character confirms the dialog box.
			else if (event.data.keyDown.chr == linefeedChr)
				{
				confirmed = true;
				}

			// If next-field character toggle between start time in end
			// time.
			else if (event.data.keyDown.chr == nextFieldChr)
				{
				*timeChars = 0;
				if (changingTime == changingStartTime)
					{
					CtlSetValue (startTimeCtl, false);
					CtlSetValue (endTimeCtl, true);
					changingTime = changingEndTime;
					}
				else
					{
					CtlSetValue (endTimeCtl, false);
					CtlSetValue (startTimeCtl, true);
					changingTime = changingStartTime;
					}
				}


			// If a valid time character was written, translate the written 
			// character into a time and update the time picker's UI.
			else if (TranslateTime (timeFormat, event.data.keyDown.chr, 
				firstHour, timeChars, timeP))
				{
				if (changingTime == changingNoTime)
					{
					changingTime = changingStartTime;
					CtlSetValue (startTimeCtl, true);
					}

				AdjustTimes (&startTime, &endTime, &timeDiff, changingTime);
				
				SetTimeTriggers (startTime, endTime, startTimeText, 
					endTimeText, timeFormat, false);

				LstSetSelection (hoursLst, timeP->hours);
				LstSetSelection (minutesLst, timeP->minutes / 5);
				}
			}

		// Has the dialog been confirmed.
		if (confirmed)
			{
			if (changingTime != changingNoTime)
				{
				*startTimeP = startTime;
				*endTimeP = endTime;
				}
			else
				{
				TimeToInt(*startTimeP) = noTime;
				TimeToInt(*endTimeP) = noTime;
				}
			break;
			}

		}

	FrmEraseForm (frm);
	FrmDeleteForm (frm);
	MemHandleFree (hoursItems);
	
	FrmSetActiveForm(originalForm);
	
	return (confirmed);
	}
Beispiel #6
0
/***********************************************************************
 *
 * FUNCTION:    GetCharsWidth
 *
 * DESCRIPTION: This routine returns width of a character that is reference
 *              via a font mapping table.
 *
 * PARAMETERS:  charsP - pointer to the character to measure
 *              charSizeP - length of the character measured (return value)
 *
 * RETURNED:    width of the character in pixels
 *
 * HISTORY:
 *		03/02/98	art	Created by Art Lamb.
 *		07/16/98	kwk	Re-enabled check for invalid low byte before assuming
 *							that a missing character is single byte.
 *		11/30/00	kwk	Alter flow so that valid double-byte check is done if
 *							low-byte is in range but undefined (e.g. 0x7F).
 *
 ***********************************************************************/
static Int16 GetCharsWidth (const Char* charsP, Int16* charSizeP)
{
	Int16 				ch;
	Int32 				index;
	Int16					width;
	Int16					charSize;
	Int16 				firstChar;
	Int16 				lastChar;
	FontPtr				fontP;
	FontTablePtr		fontListP;
	FontMapPtr			fontMap;
	FontCharInfoType * charInfo;

	charSize = 1;

	index = *(UInt8 *)charsP;
	fontMap = (FontMapPtr) (UICurrentFontPtr+1);
	if ((UICurrentFontPtr->fontType & fntAppFontMap) == fntAppFontMap)
		fontListP = GAppSubFontListPtr;
	else
		fontListP = UIFontListPtr;
	fontP = fontListP [fontMap[index].value];
	if (fontMap[index].state == fntStateNextIsChar)
		{
		charsP++;
		charSize = 2;
		}

	firstChar = fontP->firstChar;
	lastChar = fontP->lastChar;
	charInfo = (FontCharInfoType *) (&fontP->owTLoc) + fontP->owTLoc;

	ch = *(UInt8 *)charsP++;

	*charSizeP = charSize;
	if (ch >= firstChar && ch <= lastChar)
		{
		width = charInfo[ch - firstChar].width;
		if (width != fntMissingChar)
			return(width);
		}

	// If the character is a double byte character and the low byte 
	// is invalid then the low byte is the first byte of the 
	// next character.
	// DOLATER kwk - This means that we're no longer truely
	// int'l, as we've got checks for character size = 2 here. Better would
	// be to use the font map table to decide if the byte is valid.
	
	width = charInfo[lastChar - firstChar +1].width;
	if ((charSize == 2) && ((TxtByteAttr(ch) & byteAttrLast) == 0))
		{

#if (ERROR_CHECK_LEVEL == ERROR_CHECK_FULL)
		if ((GIntlData->intlFlags & kStrictChecksFlag) != 0)
		{
			ErrNonFatalDisplay("Measuring width of invalid double-byte character");
		}
#endif

		*charSizeP = 1;
		}

	return (width);
}
Beispiel #7
0
/***********************************************************************
 *
 * FUNCTION: PrvMultibyteWrap
 *
 * DESCRIPTION: Given a string, determine the number of characters that
 *		can be displayed within the specified width. We assume that the
 *		current font is a multi-byte font, and that FntWordWrap has
 *		already screened out odd cases.
 *
 * PARAMETERS:
 *		iStringP	 -> pointer to a null-terminated string
 *		iMaxWidth -> maximum line width in pixels
 *
 * RETURNED:
 *		length of the line in bytes
 *
 * HISTORY:
 *		05/29/00	kwk	Created by Ken Krugler from Art's original code.
 *		06/19/00	kwk	Re-wrote to be faster - do all character processing
 *							here, versus calling other routines.
 *		07/29/00	kwk	Catch case of not even one character fitting on a line.
 *		11/29/00	kwk	Report non-fatal alert if wrapping invalid double-byte
 *							and strict Intl Mgr flag is set.
 *		11/30/00	kwk	If invalid double-byte, keep using sub-font and invalid
 *							low byte to match behavior of draw/measure code.
 *
 ***********************************************************************/
static UInt16 PrvMultibyteWrap(const Char* iStringP, UInt16 iMaxWidth)
{
	const Char* textP = iStringP;
	const FontMapType* fontMapP;
 	UInt16 lineWidth = 0;
	UInt16 charSize;
	UInt32 offset;
	
	// The font map follows the regular font header information.
	fontMapP = (const FontMapType*)(UICurrentFontPtr+1);

	// As soon as lineWidth is == or > iMaxWidth, we can stop looping. When
	// we call TxtGetWordWrapOffset, we only back up the break offset if we
	// exceeded the iMaxWidth limit. Note that this isn't the same as the
	// original FntWordWrap algorithm, which would always back up even if
	// lineWidth == iMaxWidth, thus not using the full width of the display.
	while (lineWidth < iMaxWidth)
	{
		UInt8 curChar = *textP++;
		
		// A null (end of string) immediately terminates processing, and
		// the offset is before (to the left of) the null byte.
		if (curChar == chrNull)
		{
			return(textP - iStringP - 1);
		}
		
		// A linefeed immediately terminates processing, and the offset is
		// to the right of the linefeed character.
		else if (curChar == chrLineFeed)
		{
			return(textP - iStringP);
		}

		// A tab's width is the distance from the current line width to the
		// next tab-stop position (currently fixed at 20 pixels).		
		else if (curChar == chrTab)
		{
			lineWidth += fntTabChrWidth - (lineWidth % fntTabChrWidth);
			charSize = 1;
		}
		
		// We've got a regular character, so figure out its width.
		else 
		{
			const FontType* fontP = UIFontListPtr[fontMapP[curChar].value];
			const FontCharInfoType* charInfoP;
			UInt8 firstChar;
			UInt8 lastChar;
			Int8 width;
	
			// See if we've got a multi-byte character.
			if (fontMapP[curChar].state == fntStateNextIsChar)
			{
				curChar = *textP++;
				if ((curChar == chrNull)
#if (ERROR_CHECK_LEVEL == ERROR_CHECK_FULL)
				|| ((TxtByteAttr(curChar) & byteAttrLast) == 0))
#else
				|| (false))
#endif
				{
					// We've got an invalid low byte, treat it as a single byte
					// character. Note that we'll continue to use the sub-font,
					// and the invalid character index, since the font should
					// have a missing character defined at that location.
					charSize = 1;
					textP--;
					
#if (ERROR_CHECK_LEVEL == ERROR_CHECK_FULL)
					if ((GIntlData->intlFlags & kStrictChecksFlag) != 0)
					{
						ErrNonFatalDisplay("Wrapping an invalid double-byte character");
					}
#endif
				}
				else
				{
					charSize = 2;
				}
			}
			else
			{
Beispiel #8
0
/***********************************************************************
 * chooses an displays the requested form
 ***********************************************************************/
static Boolean
AppHandleEvent( EventPtr eventP)
{
  UInt16 formId;
  FormPtr frmP;

  switch (eventP->eType) {
  case frmLoadEvent:
    // Load the form resource.
    formId = eventP->data.frmLoad.formID;
    frmP = FrmInitForm(formId);
    FrmSetActiveForm(frmP);

    // Set the event handler for the form.  The handler of the currently
    // active form is called by FrmHandleEvent each time is receives an
    // event.
    switch (formId) {
    case FORM_main:
      FrmSetEventHandler(frmP, MainFormHandleEvent);
      break;

    case FORM_courselist:
      FrmSetEventHandler(frmP, CourseListHandleEvent);
      break;

    case FORM_evt_det:
      FrmSetEventHandler(frmP, EditTimeFormHandleEvent);
      break;

    case FORM_course_det:
      FrmSetEventHandler(frmP, EditCourseFormHandleEvent);
      break;

    case FORM_settings:
      FrmSetEventHandler(frmP, SettingsFormHandleEvent);
      break;

    case FORM_coursetypes:
      FrmSetEventHandler(frmP, CourseTypeFormHandleEvent);
      break;

    case FORM_exams:
      FrmSetEventHandler(frmP, ExamsFormHandleEvent);
      break;

    case FORM_exam_details:
      FrmSetEventHandler(frmP, ExamDetailsFormHandleEvent);
      break;
        
    case NewNoteView:
      FrmSetEventHandler(frmP, NoteViewHandleEvent);
      break;

    case FORM_alarm_sets:
      FrmSetEventHandler(frmP, AlarmFormHandleEvent);
      break;

    default:
      ErrNonFatalDisplay("Invalid Form Load Event");
      break;
    }
    break;

  default:
    return false;
  }
  return true;
}
Beispiel #9
0
/***********************************************************************
 *
 * FUNCTION:    RepeatDrawDescription
 *
 * DESCRIPTION: This routine draws the text description of the current
 *              repeat type and frequency.
 *
 *              The description is created from a template string.  The
 *              repeat type and frequency determines which template is
 *              used.  The template may contain one or more of the
 *              following token:
 *                   ^d - day name (ex: Monday)
 *							^f - frequency
 *                   ^x - day of the month ordinal number (ex: 1st - 31th)
 *                   ^m - month name (ex: July)
 *                   ^w - week ordinal number (1st, 2nd, 3rd, 4th, or last)
 *
 * PARAMETERS:  frm - pointer to the repeat dialog box
 *
 * RETURNED:    nothing
 *
 ***********************************************************************/
void RepeatDrawDescription(FormType* frm) {
  UInt8 repeatOn;
  UInt16 i;
  UInt16 len;
  UInt16 freq;
  UInt16 dayOfWeek;
  UInt16 templateId = repeatNoneString;
  UInt16 repeatOnCount = 0;
  Char* descP = NULL;
  Char* resP = NULL;
  Char* saveResP = NULL;
  MemHandle descH = NULL;
  MemHandle resH = NULL;
  RepeatInfoType repeat;
  FieldType* fld = GetObjectPointer(frm, RepeatDescField);

  FldEraseField (fld);

  /* Get the current setting of the repeat ui gadgets. */
  RepeatGetUIValues(frm, &repeat);
  
  /*
  ** Determine which template string to use.  The template string is
  ** used to format the description string. Note that we could add
  ** a soft constant which tells us whether we need to use different
  ** strings for freq == 1 case (depends on language), thus saving space.
  */
  freq = repeat.repeatFrequency;
  switch (repeat.repeatType) {
  case repeatNone:
    templateId = repeatNoneString;
    break;
    
  case repeatHourly:
    if (freq == 1)
      /* "Every hour" */
      templateId = everyHourRepeatString;
    else
      /* "Every [other | 2nd | 3rd...] hour" */
      templateId = hourlyRepeatString;
    break;
    
  case repeatDaily:
    if (freq == 1)
      /* "Every day" */
      templateId = everyDayRepeatString;
    else
      /* "Every [other | 2nd | 3rd...] day" */
      templateId = dailyRepeatString;
    break;
    
  case repeatWeekly:
    if (freq == 1)
      /* "Every week on [days of week]" */
      templateId = everyWeekRepeat1DayString;
    else
      templateId = weeklyRepeat1DayString;
    
    /*
    ** Generate offset to appropriate string id,
    ** based on # of days that we need to append.
    */
    for (i = 0; i < daysInWeek; i++) {
      if (repeat.repeatOn & (1 << i) ) 
	repeatOnCount++;
    }
    templateId += repeatOnCount - 1;
    break;

  case repeatMonthlyByDate:
    if (freq == 1)
      /* "The ^w ^d of every month" */
      templateId = everyMonthByDateRepeatString;
    else
      templateId = monthlyByDateRepeatString;
    break;
    
  case repeatMonthlyByDay:
    if (freq == 1)
      templateId = everyMonthByDayRepeatString;
    else
      templateId = monthlyByDayRepeatString;
    break;
    
  case repeatYearly:
    if (freq == 1)
      templateId = everyYearRepeatString;
    else
      templateId = yearlyRepeatString;
    break;
    
  default:
    ErrNonFatalDisplay("Unknown repeat type");
    break;
  }

  /*
  ** Allocate a block to hold the description and copy the template
  ** string into it.
  */
  resH = DmGetResource(strRsc, templateId);
  resP = MemHandleLock(resH);
  descH = MemHandleNew(MemPtrSize(resP));
  ASSERT(descH);
  descP = MemHandleLock(descH);
  StrCopy(descP, resP);
  MemHandleUnlock(resH);
  
  /* Substitute the month name string for the month name token. */
  resH = DmGetResource(strRsc, repeatMonthNamesString);
  resP = MemHandleLock(resH);
  for (i = 1; i < d.frm_date.month; i++)
    resP = StrChr(resP, spaceChr) + 1;
  len = StrChr(resP, spaceChr) - resP;
  descP = SubstituteStr(descP, monthNameToken, resP, len);
  MemHandleUnlock(resH);

  /* Substitute the day name string for the day name token. */
  if ((repeatOnCount == 1) || (repeat.repeatType == repeatMonthlyByDay))
    templateId = repeatFullDOWNamesString;
  else
    templateId = repeatShortDOWNamesString;
  
  resH = DmGetResource(strRsc, templateId);
  resP = MemHandleLock(resH);
  if (repeat.repeatType == repeatWeekly) {
    dayOfWeek = repeat.repeatStartOfWeek;
    repeatOn = repeat.repeatOn;
    saveResP = resP;
    while (StrStr (descP, dayNameToken)) {
      for (i = 0; i < daysInWeek; i++) {
	if (repeatOn & (1 << dayOfWeek)) {
	  repeatOn &= ~(1 << dayOfWeek);
	  break;
	}
	dayOfWeek = (dayOfWeek + 1 + daysInWeek) % daysInWeek;
      }
      resP = saveResP;
      for (i = 0; i < dayOfWeek; i++)
	resP = StrChr(resP, spaceChr) + 1;
      
      len = StrChr(resP, spaceChr) - resP;
      descP = SubstituteStr(descP, dayNameToken, resP, len);
    }
  } else {
    dayOfWeek = DayOfWeek (d.frm_date.month, d.frm_date.day,
			   d.frm_date.year/* + firstYear*/);
    for (i = 0; i < dayOfWeek; i++)
      resP = StrChr(resP, spaceChr) + 1;
    len = StrChr(resP, spaceChr) - resP;
    descP = SubstituteStr(descP, dayNameToken, resP, len);
  }
  MemHandleUnlock (resH);

  /*
  ** Substitute the repeat frequency string for the frequency token. Note that
  ** we do something special for 2nd (other), since the gender of 'other' changes
  ** for some languages, depending on whether the next word is day, month, week,
  ** or year.
  */
  if (freq == 2) {
    Char otherFreqName[16];
    const UInt16 index = repeat.repeatType - repeatNone;
    SysStringByIndex(freqOrdinal2ndStrlID, index, otherFreqName, sizeof(otherFreqName));
    descP = SubstituteStr(descP, frequenceToken, otherFreqName, StrLen(otherFreqName));
  } else {
    resH = DmGetResource(strRsc, freqOrdinalsString);
    resP = MemHandleLock(resH);
    for (i = 1; i < freq; i++)
      resP = StrChr(resP, spaceChr) + 1;
    len = StrChr(resP, spaceChr) - resP;
    descP = SubstituteStr(descP, frequenceToken, resP, len);
    MemHandleUnlock(resH);
  }

  /*
  ** Substitute the repeat week string (1st, 2nd, 3rd, 4th, or last)
  ** for the week ordinal token.
  */
  if (repeat.repeatType == repeatMonthlyByDay) {
    resH = DmGetResource(strRsc, weekOrdinalsString);
    resP = MemHandleLock(resH);
    for (i = 0; i < repeat.repeatOn / daysInWeek; i++)
      resP = StrChr (resP, spaceChr) + 1;
    len = StrChr(resP, spaceChr) - resP;
    descP = SubstituteStr(descP, weekOrdinalToken, resP, len);
    MemHandleUnlock(resH);
  } else {
    /* make sure the week ordinal token really doesn't appear */
    ErrNonFatalDisplayIf(StrStr(descP, weekOrdinalToken) != NULL, "week ordinal not substituted");
  }

  /*
  ** Substitute the repeat date string (1st, 2nd, ..., 31th) for the
  ** day ordinal token.
  */
  resH = DmGetResource(strRsc, dayOrdinalsString);
  resP = MemHandleLock(resH);
  for (i = 1; i < d.frm_date.day; i++)
    resP = StrChr(resP, spaceChr) + 1;
  len = StrChr(resP, spaceChr) - resP;
  descP = SubstituteStr(descP, dayOrdinalToken, resP, len);
  MemHandleUnlock(resH);

  /* Draw the description. */
  MemHandleUnlock(descH);
  FldFreeMemory(fld);
  FldSetTextHandle(fld, descH);
  FldDrawField(fld);
}
Beispiel #10
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