TweetFollow Us on Twitter

MACINTOSH C

Demonstration Program 2

Go to Contents
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// 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.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Fallout Shelter pulls in ten times its u...
When the Fallout TV series was announced I, like I assume many others, assumed it was going to be an utter pile of garbage. Well, as we now know that couldn't be further from the truth. It was a smash hit, and this success has of course given the... | Read more »
Recruit two powerful-sounding students t...
I am a fan of anime, and I hear about a lot that comes through, but one that escaped my attention until now is A Certain Scientific Railgun T, and that name is very enticing. If it's new to you too, then players of Blue Archive can get a hands-on... | Read more »
Top Hat Studios unveils a new gameplay t...
There are a lot of big games coming that you might be excited about, but one of those I am most interested in is Athenian Rhapsody because it looks delightfully silly. The developers behind this project, the rather fancy-sounding Top Hat Studios,... | Read more »
Bound through time on the hunt for sneak...
Have you ever sat down and wondered what would happen if Dr Who and Sherlock Holmes went on an adventure? Well, besides probably being the best mash-up of English fiction, you'd get the Hidden Through Time series, and now Rogueside has announced... | Read more »
The secrets of Penacony might soon come...
Version 2.2 of Honkai: Star Rail is on the horizon and brings the culmination of the Penacony adventure after quite the escalation in the latest story quests. To help you through this new expansion is the introduction of two powerful new... | Read more »
The Legend of Heroes: Trails of Cold Ste...
I adore game series that have connecting lore and stories, which of course means the Legend of Heroes is very dear to me, Trails lore has been building for two decades. Excitedly, the next stage is upon us as Userjoy has announced the upcoming... | Read more »
Go from lowly lizard to wicked Wyvern in...
Do you like questing, and do you like dragons? If not then boy is this not the announcement for you, as Loongcheer Game has unveiled Quest Dragon: Idle Mobile Game. Yes, it is amazing Square Enix hasn’t sued them for copyright infringement, but... | Read more »
Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »

Price Scanner via MacPrices.net

Apple’s 24-inch M3 iMacs are on sale for $150...
Amazon is offering a $150 discount on Apple’s new M3-powered 24″ iMacs. Prices start at $1149 for models with 8GB of RAM and 256GB of storage: – 24″ M3 iMac/8-core GPU/8GB/256GB: $1149.99, $150 off... Read more
Verizon has Apple AirPods on sale this weeken...
Verizon has Apple AirPods on sale for up to 31% off MSRP on their online store this weekend. Their prices are the lowest price available for AirPods from any Apple retailer. Verizon service is not... Read more
Apple has 15-inch M2 MacBook Airs available s...
Apple has clearance, Certified Refurbished, 15″ M2 MacBook Airs available starting at $1019 and ranging up to $300 off original MSRP. These are the cheapest 15″ MacBook Airs for sale today at Apple.... Read more
May 2024 Apple Education discounts on MacBook...
If you’re a student, teacher, or staff member at any educational institution, you can use your .edu email address when ordering at Apple Education to take up to $300 off the purchase of a new MacBook... Read more
Clearance 16-inch M2 Pro MacBook Pros in stoc...
Apple has clearance 16″ M2 Pro MacBook Pros available in their Certified Refurbished store starting at $2049 and ranging up to $450 off original MSRP. Each model features a new outer case, shipping... Read more
Save $300 at Apple on 14-inch M3 MacBook Pros...
Apple has 14″ M3 MacBook Pros with 16GB of RAM, Certified Refurbished, available for $270-$300 off MSRP. Each model features a new outer case, shipping is free, and an Apple 1-year warranty is... Read more
Apple continues to offer 14-inch M3 MacBook P...
Apple has 14″ M3 MacBook Pros, Certified Refurbished, available starting at only $1359 and ranging up to $270 off MSRP. Each model features a new outer case, shipping is free, and an Apple 1-year... Read more
Apple AirPods Pro with USB-C return to all-ti...
Amazon has Apple’s AirPods Pro with USB-C in stock and on sale for $179.99 including free shipping. Their price is $70 (28%) off MSRP, and it’s currently the lowest price available for new AirPods... Read more
Apple Magic Keyboards for iPads are on sale f...
Amazon has Apple Magic Keyboards for iPads on sale today for up to $70 off MSRP, shipping included: – Magic Keyboard for 10th-generation Apple iPad: $199, save $50 – Magic Keyboard for 11″ iPad Pro/... Read more
Apple’s 13-inch M2 MacBook Airs return to rec...
Apple retailers have 13″ MacBook Airs with M2 CPUs in stock and on sale this weekend starting at only $849 in Space Gray, Silver, Starlight, and Midnight colors. These are the lowest prices currently... Read more

Jobs Board

Liquor Stock Clerk - S. *Apple* St. - Idaho...
Liquor Stock Clerk - S. Apple St. Boise Posting Begin Date: 2023/10/10 Posting End Date: 2024/10/14 Category: Retail Sub Category: Customer Service Work Type: Part Read more
*Apple* App Developer - Datrose (United Stat...
…year experiencein programming and have computer knowledge with SWIFT. Job Responsibilites: Apple App Developer is expected to support essential tasks for the RxASL Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.