Demonstration Program 2
//
// Text2.c
//
//
// This program demonstrates:
//
// The use of edit text field controls and TextEdit to enter data into the various
// fields of a database record.
//
// The formatting and display of dates, times and numbers.
//
// The program opens a document window in which four edit text fields are displayed. The
// first field requires text to be entered, the second an integer value, the third a
// floating point value (that is, a currency value), and the fourth a date. The user may
// select a field for data entry using the mouse or by cycling between fields using the
// Tab key.
//
// TENew could have been used to create the four edit text fields; however, edit text
// field controls have been used so as to simplify the appearance aspects of window
// activation and deactivation and the setting and erasing of the keyboard focus frame.
// That said, TextEdit functions are widely used to deal directly with the controls' edit
// text structures. Amongst other things, this allows the program to limit the number of
// characters that may be entered in each field and to cause the forward-delete key to be
// used to forward-delete characters. (The forward-delete key is not supported by the
// edit text field control CDEF.)
//
// The current date and the current time are displayed at the top of the window.
//
// The program utilises the following resources:
//
// An 'MBAR' resource, and 'MENU' resources for Apple, File, and Edit menus (preload,
// non-purgeable).
//
// 'CNTL' resources (purgeable) for edit text field controls and primary and secondary
// group boxes (text title variant).
//
// A 'WIND' resource (purgeable) (initially not visible).
//
// 'hrct' and 'hwin' resources (purgeable) for balloon help.
//
// A 'SIZE' resource with the acceptSuspendResumeEvents, doesActivateOnFGSwitch,
// canBackground and is32BitCompatible flags set.
//
//
// ............................................................................. includes
#include <Appearance.h>
#include <ControlDefinitions.h>
#include <Devices.h>
#include <fp.h>
#include <Sound.h>
#include <ToolUtils.h>
// .............................................................................. defines
#define rMenubar 128
#define mApple 128
#define iAbout 1
#define mFile 129
#define iQuit 12
#define mEdit 130
#define iCut 3
#define iCopy 4
#define iPaste 5
#define iClear 6
#define iSelectAll 7
#define rWindow 128
#define cDateAndTimeGroupBox 128
#define cDataEntryGroupBox 129
#define cItemTitleEditText 130
#define cQuantityEditText 131
#define cUnitValueEditText 132
#define cDateEditText 133
#define cLastRecordGroupBox 134
#define cBalloonGroupBox 135
#define kTab 0x09
#define kDel 0x7F
#define kReturn 0x0D
#define kMaxCharasItem 20
#define kMaxCharasQuant 9
#define kMaxCharasValue 9
#define kMaxCharasDate 16
#define topLeft(r) (((Point *) &(r))[0])
#define botRight(r) (((Point *) &(r))[1])
// ............................................................................. typedefs
typedef struct
{
ControlHandle itemControlHdl;
ControlHandle quantControlHdl;
ControlHandle valueControlHdl;
ControlHandle dateControlHdl;
} docStruc, **docStrucHandle;
// ..................................................................... global variables
Boolean gIsColourDevice;
Boolean gPixelDepth;
Boolean gDone;
Boolean gInBackground;
RgnHandle gCursorRegion;
TEHandle gCurrentEditStrucHdl;
SInt16 gMaxCharasThisField;
Rect gItemRect = { 89 ,91,102, 231 };
Rect gQuantRect = { 112 ,91,125,233 };
Rect gValueRect = { 135,91,148,233 };
Rect gDateRect = { 158,91,171,233 };
Str255 gLastRecordItem;
Str255 gLastRecordQuantity;
Str255 gLastRecordUnitValue;
Str255 gLastRecordTotalValue;
Str255 gLastRecordReviewDate;
// .................................................................. function prototypes
void main (void);
void doInitManagers (void);
void doGetControls (WindowPtr);
void eventLoop (void);
void doIdle (void);
void doEvents (EventRecord *);
void doUpdate (EventRecord *);
void doActivate (EventRecord *);
void doActivateWindow (WindowPtr,Boolean);
void doMenuChoice (SInt32);
void doAdjustMenus (void);
void doKeyEvent (SInt8,docStrucHandle);
void doHandleTabKey (void);
void doHandleDelKey (void);
void doInContent (EventRecord *);
void doChangeCurrentEditRec (ControlHandle,Boolean,Point,SInt16);
void doTodaysDate (void);
void doAcceptNewRecord (void);
void doAcceptValueField (TEHandle,TEHandle);
void doAcceptDateField (TEHandle);
TEHandle doGetEditTextHandle (ControlHandle);
void doDrawWindow (void);
void doAdjustCursor (WindowPtr);
void doCopyPString (Str255,Str255);
void doGetDepthAndDevice (void);
// main
void main(void)
{
Handle menubarHdl;
MenuHandle menuHdl;
WindowPtr windowPtr;
docStrucHandle docStrucHdl;
// .................................................................initialise managers
doInitManagers();
// .......................................................... set up menu bar and menus
menubarHdl = GetNewMBar(rMenubar);
if(menubarHdl == NULL)
ExitToShell();
SetMenuBar(menubarHdl);
DrawMenuBar();
menuHdl = GetMenuHandle(mApple);
if(menuHdl == NULL)
ExitToShell();
else
AppendResMenu(menuHdl,'DRVR');
// .................... open window, set Appearance-compliant colour/pattern for window
if(!(windowPtr = GetNewCWindow(rWindow,NULL,(WindowPtr) -1)))
ExitToShell();
SetPort(windowPtr);
TextSize(10);
SetThemeWindowBackground(windowPtr,kThemeBrushDialogBackgroundActive,true);
// ...... get block for document structure, assign handle to window record refCon field
if(!(docStrucHdl = (docStrucHandle) NewHandle(sizeof(docStruc))))
ExitToShell();
SetWRefCon(windowPtr,(SInt32) docStrucHdl);
// ...................... get controls, show window, save background colour and pattern
doGetControls(windowPtr);
ShowWindow(windowPtr);
// ......... get pixel depth and whether colour device for certain Appearance functions
doGetDepthAndDevice();
// .................................................................... enter eventLoop
eventLoop();
}
// doInitManagers
void doInitManagers(void)
{
MaxApplZone();
MoreMasters();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
InitCursor();
FlushEvents(everyEvent,0);
RegisterAppearanceClient();
}
// doGetControls
void doGetControls(WindowPtr windowPtr)
{
ControlHandle controlHdl,lastRecordControlHdl;
docStrucHandle docStrucHdl;
Boolean booleanData = true;
ControlFontStyleRec controlFontStyleStruc;
CreateRootControl(windowPtr,&controlHdl);
docStrucHdl = (docStrucHandle) (GetWRefCon(windowPtr));
if(!(controlHdl = GetNewControl(cDateAndTimeGroupBox,windowPtr)))
ExitToShell();
if(!(controlHdl = GetNewControl(cDataEntryGroupBox,windowPtr)))
ExitToShell();
if(!((*docStrucHdl)->itemControlHdl = GetNewControl(cItemTitleEditText,windowPtr)))
ExitToShell();
if(!((*docStrucHdl)->quantControlHdl = GetNewControl(cQuantityEditText,windowPtr)))
ExitToShell();
if(!((*docStrucHdl)->valueControlHdl = GetNewControl(cUnitValueEditText,windowPtr)))
ExitToShell();
if(!((*docStrucHdl)->dateControlHdl = GetNewControl(cDateEditText,windowPtr)))
ExitToShell();
if(!(lastRecordControlHdl = GetNewControl(cLastRecordGroupBox,windowPtr)))
ExitToShell();
if(!(controlHdl = GetNewControl(cBalloonGroupBox,windowPtr)))
ExitToShell();
controlFontStyleStruc.flags = kControlUseFontMask;
controlFontStyleStruc.font = kControlFontSmallSystemFont;
SetControlFontStyle((*docStrucHdl)->itemControlHdl,&controlFontStyleStruc);
SetControlFontStyle((*docStrucHdl)->quantControlHdl,&controlFontStyleStruc);
SetControlFontStyle((*docStrucHdl)->valueControlHdl,&controlFontStyleStruc);
SetControlFontStyle((*docStrucHdl)->dateControlHdl,&controlFontStyleStruc);
controlFontStyleStruc.font = kControlFontSmallBoldSystemFont;
SetControlFontStyle(lastRecordControlHdl,&controlFontStyleStruc);
SetKeyboardFocus(windowPtr,(*docStrucHdl)->itemControlHdl,kControlEditTextPart);
gCurrentEditStrucHdl = doGetEditTextHandle((*docStrucHdl)->itemControlHdl);
gMaxCharasThisField = kMaxCharasItem;
}
// eventLoop
void eventLoop(void)
{
EventRecord eventStructure;
Boolean gotEvent;
SInt32 sleepTime;
gDone = false;
gCursorRegion = NewRgn();
sleepTime = LMGetCaretTime();
while(!gDone)
{
gotEvent = WaitNextEvent(everyEvent,&eventStructure,sleepTime,gCursorRegion);
if(gotEvent)
doEvents(&eventStructure);
else
doIdle();
}
}
// doIdle
void doIdle(void)
{
static UInt32 oldRawSeconds;
UInt32 rawSeconds;
Str255 timeString;
Rect eraseRect;
IdleControls(FrontWindow());
GetDateTime(&rawSeconds);
if(rawSeconds > oldRawSeconds)
{
TimeString(rawSeconds,true,timeString,NULL);
MoveTo(268,39);
SetRect(&eraseRect,268,29,323,39);
EraseRect(&eraseRect);
DrawString(timeString);
oldRawSeconds = rawSeconds;
}
}
// doEvent
void doEvents(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
docStrucHandle docStrucHdl;
SInt16 partCode;
SInt8 charCode;
windowPtr = FrontWindow();
docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);
switch(eventStrucPtr->what)
{
case mouseDown:
partCode = FindWindow(eventStrucPtr->where,&windowPtr);
switch(partCode)
{
case inMenuBar:
doAdjustMenus();
doMenuChoice(MenuSelect(eventStrucPtr->where));
break;
case inContent:
if(windowPtr != FrontWindow())
SelectWindow(windowPtr);
else
doInContent(eventStrucPtr);
break;
case inDrag:
DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
doAdjustCursor(windowPtr);
break;
case inGoAway:
if(TrackGoAway(windowPtr,eventStrucPtr->where))
gDone = true;
break;
}
break;
case keyDown:
case autoKey:
charCode = eventStrucPtr->message & charCodeMask;
if((eventStrucPtr->modifiers & cmdKey) != 0)
{
doAdjustMenus();
doMenuChoice(MenuEvent(eventStrucPtr));
}
else
doKeyEvent(charCode,docStrucHdl);
break;
case updateEvt:
doUpdate(eventStrucPtr);
break;
case activateEvt:
doActivate(eventStrucPtr);
break;
case osEvt:
switch((eventStrucPtr->message >> 24) & 0x000000FF)
{
case suspendResumeMessage:
gInBackground = (eventStrucPtr->message & resumeFlag) == 0;
if(!gInBackground)
SetCursor(&qd.arrow);
doActivateWindow(FrontWindow(),!gInBackground);
break;
case mouseMovedMessage:
doAdjustCursor(FrontWindow());
break;
}
break;
}
}
// doUpdate
void doUpdate(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
docStrucHandle docStrucHdl;
GrafPtr oldPort;
windowPtr = (WindowPtr) eventStrucPtr->message;
docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);
GetPort(&oldPort);
SetPort(windowPtr);
BeginUpdate((WindowPtr) eventStrucPtr->message);
UpdateControls(windowPtr,windowPtr->visRgn);
doDrawWindow();
EndUpdate((WindowPtr) eventStrucPtr->message);
SetPort(oldPort);
}
// doActivate
void doActivate(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
Boolean becomingActive;
windowPtr = (WindowPtr) eventStrucPtr->message;
becomingActive = ((eventStrucPtr->modifiers & activeFlag) == activeFlag);
doActivateWindow(windowPtr,becomingActive);
}
// doActivateWindow
void doActivateWindow(WindowPtr windowPtr,Boolean becomingActive)
{
ControlHandle controlHdl;
GetRootControl(windowPtr,&controlHdl);
if(becomingActive)
{
ActivateControl(controlHdl);
doDrawWindow();
}
else
{
DeactivateControl(controlHdl);
doDrawWindow();
}
}
// doMenuChoice
void doMenuChoice(SInt32 menuChoice)
{
SInt16 menuID, menuItem;
Str255 itemName;
SInt16 daDriverRefNum;
menuID = HiWord(menuChoice);
menuItem = LoWord(menuChoice);
if(menuID == 0)
return;
switch(menuID)
{
case mApple:
if(menuItem == iAbout)
SysBeep(10);
else
{
GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
daDriverRefNum = OpenDeskAcc(itemName);
}
break;
case mFile:
if(menuItem == iQuit)
gDone = true;
break;
case mEdit:
switch(menuItem)
{
case iCut:
TECut(gCurrentEditStrucHdl);
break;
case iCopy:
TECopy(gCurrentEditStrucHdl);
break;
case iPaste:
TEPaste(gCurrentEditStrucHdl);
break;
case iClear:
TEDelete(gCurrentEditStrucHdl);
break;
case iSelectAll:
TESetSelect(0,(*gCurrentEditStrucHdl)->teLength,gCurrentEditStrucHdl);
break;
}
break;
}
HiliteMenu(0);
}
// doAdjustMenus
void doAdjustMenus(void)
{
MenuHandle fileMenuHdl, editMenuHdl;
fileMenuHdl = GetMenuHandle(mFile);
editMenuHdl = GetMenuHandle(mEdit);
if((*gCurrentEditStrucHdl)->selStart < (*gCurrentEditStrucHdl)->selEnd)
{
EnableItem(editMenuHdl,iCut);
EnableItem(editMenuHdl,iCopy);
EnableItem(editMenuHdl,iClear);
}
else
{
DisableItem(editMenuHdl,iCut);
DisableItem(editMenuHdl,iCopy);
DisableItem(editMenuHdl,iClear);
}
if(TEGetScrapLength() > 0)
EnableItem(editMenuHdl,iPaste);
else
DisableItem(editMenuHdl,iPaste);
if((*gCurrentEditStrucHdl)->teLength > 0)
EnableItem(editMenuHdl,iSelectAll);
else
DisableItem(editMenuHdl,iSelectAll);
DrawMenuBar();
}
// doKeyEvent
void doKeyEvent(SInt8 charCode,docStrucHandle docStrucHdl)
{
if(charCode == kTab)
doHandleTabKey();
else if(charCode == kDel)
doHandleDelKey();
else if(charCode == kReturn)
doAcceptNewRecord();
else
{
if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl) ||
gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
{
if(!((charCode >= '0' && charCode <= '9') || charCode == '.' ||
charCode == '-' ||(charCode < 0x20)))
{
SysBeep(10);
return;
}
}
if(((*gCurrentEditStrucHdl)->teLength < gMaxCharasThisField) || (charCode < 0x20))
TEKey(charCode,gCurrentEditStrucHdl);
else
SysBeep(10);
}
}
// doHandleTabKey
void doHandleTabKey(void)
{
WindowPtr windowPtr;
docStrucHandle docStrucHdl;
ControlHandle oldControlHdl;
Point dummy;
windowPtr = FrontWindow();
docStrucHdl = (docStrucHandle) (GetWRefCon(windowPtr));
GetKeyboardFocus(windowPtr,&oldControlHdl);
if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->itemControlHdl))
doChangeCurrentEditRec((*docStrucHdl)->quantControlHdl,false,dummy,kMaxCharasQuant);
else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl))
doChangeCurrentEditRec((*docStrucHdl)->valueControlHdl,false,dummy,kMaxCharasValue);
else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
doChangeCurrentEditRec((*docStrucHdl)->dateControlHdl,false,dummy,kMaxCharasDate);
else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->dateControlHdl))
doChangeCurrentEditRec((*docStrucHdl)->itemControlHdl,false,dummy,kMaxCharasItem);
Draw1Control(oldControlHdl);
doAdjustCursor(windowPtr);
}
// doHandleDelKey
void doHandleDelKey(void)
{
SInt16 selectionLength;
selectionLength = (*gCurrentEditStrucHdl)->selEnd - (*gCurrentEditStrucHdl)->selStart;
if(selectionLength == 0)
(*gCurrentEditStrucHdl)->selEnd += 1;
TEDelete(gCurrentEditStrucHdl);
}
// doInContent
void doInContent(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
docStrucHandle docStrucHdl;
Boolean shiftKeyPosition;
ControlHandle oldControlHdl, controlHdl;
windowPtr = FrontWindow();
docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);
GetKeyboardFocus(windowPtr,&oldControlHdl);
shiftKeyPosition = (eventStrucPtr->modifiers & shiftKey) != 0;
SetPort(windowPtr);
GlobalToLocal(&eventStrucPtr->where);
if(FindControl(eventStrucPtr->where,windowPtr,&controlHdl))
{
if(controlHdl == (*docStrucHdl)->itemControlHdl)
{
if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->itemControlHdl))
TEClick(eventStrucPtr->where,shiftKeyPosition,
doGetEditTextHandle((*docStrucHdl)->itemControlHdl));
else
{
doChangeCurrentEditRec((*docStrucHdl)->itemControlHdl,true,
eventStrucPtr->where,kMaxCharasItem);
}
}
else if(controlHdl == (*docStrucHdl)->quantControlHdl)
{
if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl))
TEClick(eventStrucPtr->where,shiftKeyPosition,
doGetEditTextHandle((*docStrucHdl)->quantControlHdl));
else
doChangeCurrentEditRec((*docStrucHdl)->quantControlHdl,true,eventStrucPtr->where,
kMaxCharasQuant);
}
else if(controlHdl == (*docStrucHdl)->valueControlHdl)
{
if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
TEClick(eventStrucPtr->where,shiftKeyPosition,
doGetEditTextHandle((*docStrucHdl)->valueControlHdl));
else
doChangeCurrentEditRec((*docStrucHdl)->valueControlHdl,true,eventStrucPtr->where,
kMaxCharasValue);
}
else if(controlHdl == (*docStrucHdl)->dateControlHdl)
{
if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->dateControlHdl))
TEClick(eventStrucPtr->where,shiftKeyPosition,
doGetEditTextHandle((*docStrucHdl)->dateControlHdl));
else
doChangeCurrentEditRec((*docStrucHdl)->dateControlHdl,true,eventStrucPtr->where,
kMaxCharasDate);
}
}
Draw1Control(oldControlHdl);
doAdjustCursor(windowPtr);
}
// doChangeCurrentEditRec
void doChangeCurrentEditRec(ControlHandle newControlHdl,Boolean teClickFlag,
Point mouseXY,SInt16 maxCharas)
{
ClearKeyboardFocus(FrontWindow());
SetKeyboardFocus(FrontWindow(),newControlHdl,kControlEditTextPart);
gCurrentEditStrucHdl = doGetEditTextHandle(newControlHdl);
if(teClickFlag)
TEClick(mouseXY,false,doGetEditTextHandle(newControlHdl));
TESetSelect(0,32767,gCurrentEditStrucHdl);
gMaxCharasThisField = maxCharas;
}
// doTodaysDate
void doTodaysDate(void)
{
UInt32 rawSeconds;
Str255 dateString;
GetDateTime(&rawSeconds);
DateString(rawSeconds,longDate,dateString,NULL);
MoveTo(59,39);
DrawString(dateString);
}
// doAcceptNewRecord
void doAcceptNewRecord(void)
{
WindowPtr windowPtr;
docStrucHandle docStrucHdl;
TEHandle itemEditHdl, quantEditHdl, valueEditHdl, dateEditHdl;
Rect theRect;
Point dummy;
windowPtr = FrontWindow();
docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);
itemEditHdl = doGetEditTextHandle((*docStrucHdl)->itemControlHdl);
quantEditHdl = doGetEditTextHandle((*docStrucHdl)->quantControlHdl);
valueEditHdl = doGetEditTextHandle((*docStrucHdl)->valueControlHdl);
dateEditHdl = doGetEditTextHandle((*docStrucHdl)->dateControlHdl);
if((*itemEditHdl)->teLength == 0 || (*quantEditHdl)->teLength == 0 ||
(*valueEditHdl)->teLength == 0 || (*dateEditHdl)->teLength == 0)
{
SysBeep(10);
return;
}
GetDialogItemText((*itemEditHdl)->hText,gLastRecordItem);
GetDialogItemText((*quantEditHdl)->hText,gLastRecordQuantity);
doAcceptValueField(valueEditHdl,quantEditHdl);
doAcceptDateField(dateEditHdl);
SetRect(&theRect,144,198,310,300);
InvalRect(&theRect);
TESetSelect(0,32767,itemEditHdl);
TEDelete(itemEditHdl);
TESetSelect(0,32767,quantEditHdl);
TEDelete(quantEditHdl);
TESetSelect(0,32767,valueEditHdl);
TEDelete(valueEditHdl);
TESetSelect(0,32767,dateEditHdl);
TEDelete(dateEditHdl);
gCurrentEditStrucHdl = itemEditHdl;
doChangeCurrentEditRec((*docStrucHdl)->itemControlHdl,false,dummy,kMaxCharasItem);
}
// doAcceptValueField
void doAcceptValueField(TEHandle valueEditHdl,TEHandle quantEditHdl)
{
Handle itl4ResourceHdl;
SInt32 numpartsOffset;
SInt32 numpartsLength;
NumberParts *numpartsTablePtr;
Str255 formatString = "\p'$'###,###,###.00;'Valueless';'Valueless'";
NumFormatString formatStringRec;
Str255 inputNumString;
Str255 formattedNumString;
extended80 value80Bit;
Str255 quantityString;
SInt32 quantity;
FormatResultType result;
#if TARGET_CPU_PPC
double valueDouble;
#endif
GetIntlResourceTable(smSystemScript,iuNumberPartsTable,&itl4ResourceHdl,&numpartsOffset,
&numpartsLength);
numpartsTablePtr = (NumberPartsPtr) ((SInt32) *itl4ResourceHdl + numpartsOffset);
StringToFormatRec(formatString,numpartsTablePtr,&formatStringRec);
GetDialogItemText((*valueEditHdl)->hText,inputNumString);
StringToExtended(inputNumString,&formatStringRec,numpartsTablePtr,&value80Bit);
ExtendedToString(&value80Bit,&formatStringRec,numpartsTablePtr,formattedNumString);
doCopyPString(formattedNumString,gLastRecordUnitValue);
GetDialogItemText((*quantEditHdl)->hText,quantityString);
StringToNum(quantityString,&quantity);
#if TARGET_CPU_68K
value80Bit = value80Bit * quantity;
#endif
#if TARGET_CPU_PPC
valueDouble = x80tod(&value80Bit);
valueDouble = valueDouble * quantity;
dtox80(&valueDouble,&value80Bit);
#endif
result = ExtendedToString(&value80Bit,&formatStringRec,numpartsTablePtr,
formattedNumString);
if(result == fFormatOverflow)
doCopyPString("\p(Too large to display)",gLastRecordTotalValue);
else
doCopyPString(formattedNumString,gLastRecordTotalValue);
}
// doAcceptDateField
void doAcceptDateField(TEHandle dateEditHdl)
{
DateCacheRecord dateCacheRec;
Ptr textPtr;
SInt32 textLength, lengthUsed;
LongDateRec longDateTimeRec;
LongDateTime longDateTimeValue;
Str255 dateString;
InitDateCache(&dateCacheRec);
textPtr = (*(*dateEditHdl)->hText);
textLength = (*dateEditHdl)->teLength;
HLock((*dateEditHdl)->hText);
StringToDate(textPtr,textLength,&dateCacheRec,&lengthUsed,&longDateTimeRec);
HUnlock((*dateEditHdl)->hText);
LongDateToSeconds(&longDateTimeRec,&longDateTimeValue);
longDateTimeValue += 15724800;
LongDateString(&longDateTimeValue,longDate,dateString,NULL);
doCopyPString(dateString,gLastRecordReviewDate);
}
// doGetEditTextHandle
TEHandle doGetEditTextHandle(ControlHandle controlHdl)
{
TEHandle textEditHdl;
GetControlData(controlHdl,kControlNoPart,kControlEditTextTEHandleTag,
sizeof(textEditHdl),(Ptr) &textEditHdl,NULL);
return textEditHdl;
}
// doDrawWindow
void doDrawWindow(void)
{
Rect theRect;
SetRect(&theRect,144,198,310,300);
EraseRect(&theRect);
if(!gInBackground)
SetThemeTextColor(kThemeTextColorModelessDialogActive,gPixelDepth,gIsColourDevice);
else
SetThemeTextColor(kThemeTextColorModelessDialogInactive,gPixelDepth,gIsColourDevice);
doTodaysDate();
MoveTo(32,39);
DrawString("\pDate:");
MoveTo(239,39);
DrawString("\pTime:");
MoveTo(34,99);
DrawString("\pItem Title:");
MoveTo(41,122);
DrawString("\pQuantity:");
MoveTo(32,145);
DrawString("\pUnit Value:");
MoveTo(61,168);
DrawString("\pDate:");
MoveTo(240,99);
DrawString("\pEg: Barometers");
MoveTo(240,122);
DrawString("\pEg: 34");
MoveTo(240,145);
DrawString("\pEg: 135.58");
MoveTo(240,168);
DrawString("\pEg: 24 Jul 95");
MoveTo(92,214);
DrawString("\pItem Title:");
MoveTo(99,234);
DrawString("\pQuantity:");
MoveTo(90,254);
DrawString("\pUnit Value:");
MoveTo(87,274);
DrawString("\pTotal Value:");
MoveTo(81,294);
DrawString("\pReview Date:");
MoveTo(112,349);
DrawString("\pBalloon help is available");
MoveTo(147,214);
DrawString(gLastRecordItem);
MoveTo(147,234);
DrawString(gLastRecordQuantity);
MoveTo(147,254);
DrawString(gLastRecordUnitValue);
MoveTo(147,274);
DrawString(gLastRecordTotalValue);
MoveTo(147,294);
DrawString(gLastRecordReviewDate);
}
// doAdjustCursor
void doAdjustCursor(WindowPtr windowPtr)
{
GrafPtr oldPort;
docStrucHandle docStrucHdl;
RgnHandle arrowRegion,iBeamRegion;
Rect iBeamRect;
Point mouseXY;
GetPort(&oldPort);
SetPort(windowPtr);
docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);
arrowRegion = NewRgn();
iBeamRegion = NewRgn();
SetRectRgn(arrowRegion,-32768,-32768,32766,32766);
if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->itemControlHdl))
iBeamRect = gItemRect;
else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl))
iBeamRect = gQuantRect;
else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
iBeamRect = gValueRect;
else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->dateControlHdl))
iBeamRect = gDateRect;
LocalToGlobal(&topLeft(iBeamRect));
LocalToGlobal(&botRight(iBeamRect));
RectRgn(iBeamRegion,&iBeamRect);
DiffRgn(arrowRegion,iBeamRegion,arrowRegion);
GetMouse(&mouseXY);
LocalToGlobal(&mouseXY);
if(PtInRgn(mouseXY,iBeamRegion))
{
SetCursor(*(GetCursor(iBeamCursor)));
CopyRgn(iBeamRegion,gCursorRegion);
}
else
{
SetCursor(&qd.arrow);
CopyRgn(arrowRegion,gCursorRegion);
}
DisposeRgn(arrowRegion);
DisposeRgn(iBeamRegion);
SetPort(oldPort);
}
// doCopyPString
void doCopyPString(Str255 sourceString,Str255 destinationString)
{
SInt16 stringLength;
stringLength = sourceString[0];
BlockMove(sourceString + 1,destinationString + 1,stringLength);
destinationString[0] = stringLength;
}
// doGetDepthAndDevice
void doGetDepthAndDevice(void)
{
GDHandle deviceHdl;
deviceHdl = LMGetMainDevice();
gPixelDepth = (*(*deviceHdl)->gdPMap)->pixelSize;
if(BitTst(&(*deviceHdl)->gdFlags,gdDevType))
gIsColourDevice = true;
}
//
Demonstration Program 2 Comments
When this program is run, the user should enter data in the four edit text fields, using
the tab key or mouse clicks to select the required field and pressing the Return key when
data has been entered in all fields.
In order to observe number formatting effects, the user should occasionally enter very
large numbers and negative numbers in the Value field. In order to observe the effects
of date string parsing and formatting, the user should enter dates in a variety of
formats, for example: "2 Mar 95", "2/3/95", "March 2 1995", "2 3 95", etc.
#define
The constants beginning with c represent resource IDs for group box and edit text field
controls. kTab, kDel, and kReturn represent the character codes generated by the tab,
forward-delete, and return keys. The following four constants are used to limit the
number of characters that can be entered in a particular edit text field.
#typedef
The DocStruc data type will be used for a document structure, which will be attached
to the single window opened by the program. The four fields of this structure will be
assigned handles to separate edit structures.
Global Variables
gIsColourDevice and gPixelDepth will be used by the Appearance Manager function
SetThemeTextColor. gCursorRegion relates to the cursorRgn parameter of the WaitNextEvent
function.
gCurrentEditStrucHdl will be assigned the handle to the edit structure for the currently
active edit text field. gMaxCharasThisField will be assigned a value representing the
maximum number of characters allowed to be entered in the currently active edit text
field. The four Rect variables will be used by the cursor shape changing function to
establish the I-Beam cursor region for the currently active edit text field. The four
Str255 variables will be assigned the strings to be drawn in the "last Record Entered"
group box when the Return key is pressed.
main
SetThemeWindowBackground sets an Appearance-compliant colour/pattern for the window's
content area. This means that the content area will be automatically repainted with that
colour/pattern when required with no further assistance from the application.
doGetControls creates the controls for the window, following which the window is
displayed and the background colour and pattern are saved.
doGetControls
doGetControls creates the window's controls.
Firstly, a root control is created for the window. The edit text field and group box
controls are then created, their handles being assigned to the relevant field of the
window's document structure.
At the next block, SetControlFontStyle is used to set the font for the edit text field
controls to the small system font and the font for the "Last Record Entered" group box to
the small emphasized system font.
At the last block, SetKeyboardFocus is called to set the keyboard focus to the first edit
text field control, the associated edit structure is made the current edit structure, and
the global variable which will limit the number of characters that may be entered in this
edit text field is assigned the appropriate value.
eventLoop
When a NULL event is received, the application-defined function doIdle is called.
Because IdleControls will be called in the idle function to blink the insertion point
caret, WaitNextEvent's sleep parameter is assigned the value returned by a call to
LMGetCaretTime
doIdle
doIdle is called when WaitNextEvent returns a null event. doIdle blinks the insertion
point caret and draws the current time in the top right of the window.
IdleControls is called to ensure that the caret blinks regularly in the edit text field
control with keyboard focus.
GetDateTime retrieves the "raw" seconds value, as known to the system. (This is the
number of seconds since 1 Jan 1904.) If that value is greater than the value retrieved
the last time doIdle was called, TimeString converts the raw seconds value to a string
containing the time formatted according to flags in the numeric format ('itl0') resource.
(Since NULL is specified in the resource handle parameter, the appropriate 'itl0'
resource for the current script system is used.) This string is then drawn in the window
and the retrieved raw seconds value is assigned to the static variable oldRawSeconds for
use next time doIdle is called.
doEvents
doEvents handles initial event processing.
In the case of a mouse-down event in the content region of the window (when it is the
front window), the application-defined function doInContent is called.
In the case of a non-Command key equivalent key-down event, the application-defined
function doKeyEvent is called.
doUpdate and doActivateWindow
doUpdate handles update events. Between the usual calls to BeginUpdate and EndUpdate,
the contents of the window are re-drawn.
doActivateWindow activates or deactivates the window's contents. GetRootControl gets a
handle to the window's root control. This is used in the following lines to either
activate or deactivate all of the controls in the window. In addition, the
application-defined function doDrawWindow is called to draw all the non-control text in
the window in either the normal or dimmed state, as appropriate.
doMenuChoice
doMenuChoice handles Apple, File, and Edit menu choices. In the case of choices from the
Edit menu, the appropriate TextEdit function is called.
doAdjustMenus
doAdjustMenus adjusts the menus.
If there is a selection range in the current edit structure, the Cut, Copy, and Clear
items are enabled, otherwise they are disabled. If there is any text in the TextEdit
private scrap (the call to TEGetScrapLength), the Paste item is enabled, otherwise it is
disabled. If there is any text in the currently activate edit text field, Select All is
enabled, otherwise it is disabled.
doKeyEvent
doKeyEvent handles key-down and auto-key events which are not Command key equivalents.
If the character code is that generated by the tab key or the del key, handling is passed
to other application-defined functions. If the Return key was pressed, control is passed
to an application-defined function which accepts, formats, and displays the entered data
and deletes all text from the edit text fields.
The following occurs if the character code makes it to the else block. Firstly, if the
active edit text field is the Quantity or Unit Value field, and if the character code is
not a numeric character, the minus character, or the period character, the system alert
sound is played and the function returns. TEKey is called provided that the maximum
number of characters allowable in the currently active edit text field will not be
exceeded or the character is one of the non-printing characters. If the number of
characters entered is at the limit and a printing character key was pressed, the
character is not accepted and the system alert sound is played. This arrangement ensures
that, if the number of characters in the edit structure is at the maximum allowed, the
arrow and delete keys, unlike the printing character keys, will not be ignored and will
have their usual effect.
doHandleTabKey
doHandleTabKey handles the tab key. Its purpose is to cycle around the edit text fields
in response to tab key presses, defeating keyboard focus on the currently active edit
text field and setting keyboard focus on the next edit text field in the sequence.
The first two lines retrieve a handle to the document structure for the window. The call
to GetKeyboardFocus gets a handle to the control with keyboard focus. This will be used
in the call to Draw1Control at the bottom of the function.
The central block determines which is the current edit structure (and thus the current
edit text field) and calls the application-defined function that changes the active edit
text field. This call passes the handle to the next edit text field control in the
sequence, together with the maximum number of characters allowed in that field.
The call to Draw1Control on the "old" edit text field control ensures that the insertion
point caret will be erased in that field. The call to doAdjustCursor is required in
order to change the rectangle within which the cursor changes to the I-beam shape.
doHandleDelKey
doHandleDelKey handles the forward-delete key, which is not supported by TextEdit. The
first line gets the current selection length. If the selection length is zero (that is,
an insertion point caret is being displayed), the selection is set to include the
character to the right of the insertion point. TEDelete deletes the current selection
range from the text.
doInContent
doInContent handles mouse-down events in the content region of the window.
The second and third lines get a handle to the window's document structure. . The call
to GetKeyboardFocus gets a handle to the control with keyboard focus. (This will be used
in the call to Draw1Control at the bottom of the function.) The next line gets the
position of shift key at the time of the mouse-down. (TEClick's behaviour depends on the
position of the shift key.)
GlobalToLocal converts the global coordinates of the mouse-down to the local coordinates
required by FindControl and TEClick.
If FindControl reports an enabled item under the mouse, and if that item is the Item
Title edit text field control, and if that control has the keyboard focus, TEClick is
called to take control until the mouse button is released. (Note that the shift key
position is passed in the second parameter.) If the Item Title edit text field control
does not have the keyboard focus, the application-defined function doChangeCurrentEditRec
is called to change the keyboard focus to that control. The same basic procedure is
followed in the case of mouse-downs within the other three edit text field controls.
The call to Draw1Control on the "old" edit text field control ensures that the insertion
point caret will be erased in that field. The call to doAdjustCursor is required in
order to change the rectangle within which the cursor changes to the I-beam shape.
doChangeCurrentEditRec
doChangeCurrentEditRec is called by both doHandleTabKey and doInContent to change
the edit text field control with keyboard focus (and thus the currently active edit
structure).
SetKeyboardFocus sets the keyboard focus to the specified edit text field control. The
next line makes the edit structure associated with that control the current edit
structure.
If this function was called by doInContent (teClick = true), TEClick is called to tell
TextEdit that the mouse-down has occurred in the newly-activated edit structure. Note
that the extend parameter is set to false, telling TextEdit, regardless of the position
of the shift key, that the user is not extending a selection.
TESetSelect ensures that, if there are any characters in the edit structure, they will be
initially highlighted. The last line assigns the appropriate value to the global
variable which controls the maximum allowable number of characters in the active edit
text field.
doTodaysDate
doTodaysDate draws the date at the top of the window.
GetDateTime gets the raw seconds value, as known to the system. DateString converts the
raw seconds value to a string containing a date formatted in long date format according
to flags in the numeric format ('itl0') resource. (Since NULL is specified in the
resource handle parameter, the appropriate 'itl0' resource for the current script system
is used.) This string is then drawn in the window.
doAcceptNewRecord
doAcceptNewRecord is called when the Return key is pressed. Assuming each edit text
field contains at least one character of text, it calls other application-defined
functions to format (where necessary) and display strings in the "Last Record Entered"
group box area, and prepares the edit text fields to accept new data.
The first two lines get a handle to the window's document structure. The next block
copies the handles to the four edit structures to four local variables.
At the next block, if any one of the edit text fields does not contain any text, the
system alert sound is played and the function returns.
The two calls to GetDialogItemText get the text in the "Item Title" and "Quantity" edit
text fields into two global variables. (GetDialogItemText is usually used to get the
text from an editable edit text item in a dialog box. It works here because the first
parameter required by GetDialogItemText is a handle to the hText field of an edit
structure.) No special formatting of these two strings is required.
The call to InvalRect causes an update event to be generated. As will be seen, this
causes the strings created by the preceding block to be drwan in the "Last Record
Entered" group box area.
The next two lines call two application defined functions to format and display strings
derived from the information in the "Unit Value" and "Date" edit text fields.
The next 10 lines delete the text from all edit text fields. The last three lines change
the keyboard focus back to the "Item Title" edit text field.
doAcceptValueField
doAcceptValueField is called by doAcceptNewRecord to get the string from the "Value" edit
structure, convert it to floating point number, convert that number to a formatted number
string, draw that string, get the string in the "Quantity" edit structure, convert that
string to an integer, multiply the floating point number by the integer to arrive at the
"Total Value" value, convert the result to a formatted number string, and draw that
string .
A pointer to a number parts table is required by the functions that convert between
floating point numbers and strings. Accordingly, the first three lines get the required
pointer.
StringToFormatRec converts the number format specification string into the internal
numeric representation required by the functions that convert between floating point
numbers and strings.
With that preparation attended to, GetDialogItemText gets the "Value" edit text field
text into a Pascal string. StringToExtended converts that string into a floating point
number of type extended (80 bits). ExtendedToString converts that number back to a
string, formatted according to the internal numeric representation of the number format
specification string. doCopyPString copies that string to a global variable for
subsequent drawing in the window.
The intention now is to multiply the quantity by the unit value to arrive at a total
value. However, conditional compilation is required here to account for the fact that
the PowerPC Floating Point Unit does not support Motorola's 80-bit extended type.
If the program is being compiled as 680x0 code, the value in the extended80 variable
(unit value) is multiplied by the quantity and the result (total value) is stored in the
extended80 variable. If the program is being compiled as PowerPC code, the extended80
value is converted to a value of type double before the multiplication occurs. The
result of the multiplication is assigned to the variable of type double. This is then
converted to an extended80.
The extended80 value is then passed in the first parameter of ExtendedToString for
conversion to a formatted string. If ExtendedToString does not return fFormatOverflow,
the formatted string is copied to a global variable for subsequent drawing in the window.
doAcceptDateField
doAcceptDateField is called by doAcceptNewRecord to create a long date-time structure
from the string in the "Date" edit structure, add six months to the date, format the date
as a string (long date format), and draw that string in the structure panel.
The function which creates the long date-time structure takes an initialised date cache
structure as a parameter. Accordingly, the first step is to initialise the specified
date cache structure.
The next two lines get a pointer to the text in the "Date" edit structure and the length
of that text. These are passed as parameters in the StringToDate call, which parses the
input string and fills in the relevant fields of the long date-time structure.
LongDateToSeconds converts the long date-time structure to a long date-time value. The
next line adds six months worth of seconds to the long date-time value. The modified
long date-time value is then passed as a parameter to LongDateString. LongDateString
converts the long date-time value to a long format date string formatted according to the
specified international resource. (In this case, NULL is passed as the international
resource parameter, meaning that the appropriate 'itl1' resource for the current script
system is used.)
The formatted date string is copied to a global variable for subsequent drawing in the
window.
doGetEditTextHandle
doGetEditTextHandle returns the handle to the edit structure associated with the
specified edit text control.
doDrawWindow
doDrawWindow draws the non-control text content of the window. The text will be drawn
normal or dimmed depending on whether the application is in the foreground or background.
doAdjustCursor
doAdjustCursor is the cursor adjustment function. It is similar to the cursor adjustment
functions in previous demonstration programs except that the rectangle in which the
cursor is required to change to the I-beam cursor shape is changed to accord with that of
the edit text field with keyboard focus.
Prior to the version issued with Mac OS 8.5 and later, the text backgound colour in
the edit text control would often corrupt after cut and paste operations using the
Edit menu (though not when using the Command-key equivalents). If you experience
this problem when running the demonstration under a version of the Mac OS earlier
than mac OS 8.5, proceed as follows:
Add this data type:
typedef struct
{
RGBColor backColour;
PixPatHandle backPixelPattern;
Pattern backBitPattern;
} backColourPattern;
Add this global variable:
backColourPattern gBackColourPattern;
Add these function prototypes:
void doSaveBackground (backColourPattern *);
void doRestoreBackground (backColourPattern *);
void doSetBackgroundWhite (void);
Add these functions:
// doSaveBackground
void doSaveBackground(backColourPattern *gBackColourPattern)
{
GrafPtr currentPort;
GetPort(¤tPort);
GetBackColor(&gBackColourPattern->backColour);
gBackColourPattern->backPixelPattern = NULL;
if((**((CGrafPtr) currentPort)->bkPixPat).patType != 0)
gBackColourPattern->backPixelPattern = ((CGrafPtr) currentPort)->bkPixPat;
else
gBackColourPattern->backBitPattern =
*(PatPtr) (*(**((CGrafPtr) currentPort)->bkPixPat).patData);
}
// doRestoreBackground
void doRestoreBackground(backColourPattern *gBackColourPattern)
{
RGBBackColor(&gBackColourPattern->backColour);
if(gBackColourPattern->backPixelPattern)
BackPixPat(gBackColourPattern->backPixelPattern);
else
BackPat(&gBackColourPattern->backBitPattern);
}
// doSetBackgroundWhite
void doSetBackgroundWhite(void)
{
RGBColor whiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
RGBBackColor(&whiteColour);
BackPat(&qd.white);
}
//
Add this call:
doSaveBackground(&gBackColourPattern);
in the main function, after the call to ShowWindow.
Add this call:
doRestoreBackground(&gBackColourPattern);
in doIdle, after call to IdleControls,
in doMenuChoice, just before the last break statement,
in doKeyEvent, just before the last closing brace,
in doIncontent, just before the last closing brace, and
in doChangeCurrentEditRec, as the first line.
Add this line:
doSetBackgroundWhite();
in doMenuChoice, immediately before switch(menuItem),
in doKeyEvent, as the first line, and
in doInContent, as the first line.
|

|