TweetFollow Us on Twitter

MACINTOSH C

Demonstration Program

Go to Contents
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// DialogsAndAlerts.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// 
// If Mac OS 8.5 is present, this program initially opens a small modal dialog box which
// is automatically closed after 10 seconds, the timeout value having been set by a call
// to SetDialogTimeout.  The program then:
//
// ¥  Opens a window with an Appearance-compliant window header for the purposes of 
//    displaying advisory text and for proving correct window updating and activation/
//    deactivation in the presence of alert and dialog boxes.
//
// ¥  Allows the user to invoke a demonstration modal alert box, movable modal alert box, 
//    modal dialog box, movable modal dialog box, and modeless dialog box via the 
//    Demonstration menu.
//
// The modal alert box is created using 'ALRT' and 'alrx' resources.
//
// The movable modal alert box is created programmatically using the StandardAlert 
// function and a standard alert structure.
//
// The modal dialog box contains three checkboxes in one group box, and two pop-up menu
// buttons in another group box.
//
// The movable modal dialog box contains four radio buttons in one group box, and a clock
// control and edit text field in another group box..
//
// The modeless dialog box contains, amongst other items, an edit text field.
//
// The modal alert box, movable modal alert box, modal dialog box, and movable modal 
// dialog box use an application-defined event filter function.
//
// The program utilises the following resources:
//
// ¥  An 'MBAR' resource, and 'MENU' resources for Apple, File, Demonstration, and Help
//    pull-down menus, and the pop-up menu buttons (preload, non-purgeable).
//
// ¥  A 'WIND' resource (purgeable) (initially visible).
//
// ¥  An 'ALRT' resource (purgeable), together with an associated 'alrx' resource 
//    (purgeable), and 'dftb' resource (non-purgeable, but 'dftb' resources are auto-
//    matically marked purgeable when read in).
//
// ¥  'DLOG' resources (purgeable) (initially not visible) and associated 'DITL' 
//    resources (purgeable), 'dlgx' resources (purgeable), and 'dftb' resources (non-
//    purgeable, but 'dftb' resources are automatically marked purgeable when read in).
//
// ¥  'CNTL' resources for primary group boxes, separator lines, pop-up menu buttons,
//    a clock, and an image well (all purgeable).
//
// ¥  A 'STR#' resources (purgeable) containing the label and narrative text for the
//    movable modal alert box. 
//
// ¥  A 'cicn' resource (purgeable) for the modeless dialog box.
//
// ¥  A 'ppat' resource (purgeable), which is used to colour the content region of the
//    document window for update proving purposes.
//
// ¥  'hdlg' resources (purgeable) containing balloon help information for the modal and
//    and movable modal dialog boxes.
//
// ¥  An 'hrct' resource and associated 'hwin' resource (both purgeable) containing 
//    balloon help information for the modeless dialog box.
//
// ¥  A 'SIZE' resource with the acceptSuspendResumeEvents and doesActivateOnFGSwitch,
//    and is32BitCompatible flags set.
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include <Appearance.h>
#include <ControlDefinitions.h>
#include <Devices.h>
#include <Gestalt.h>
#include <LowMem.h>
#include <Resources.h>
#include <Sound.h>
#include <ToolUtils.h>

// .............................................................................. defines

#define rMenubar               128
#define mApple                 128
#define  iAbout                1
#define mFile                  129
#define  iClose                4
#define  iQuit                 11
#define mEdit                  130
#define  iCut                  3
#define  iCopy                 4
#define  iPaste                5
#define  iClear                6
#define mDemonstration         131
#define  iModalAlert           1
#define  iMovableAlert         2
#define  iModalDialog          3
#define  iMovableModalDialog   4
#define  iModeless             5
#define rWindow                128
#define rAlert                 128
#define rModal                 129
#define  iGridSnap             4
#define  iShowGrid             5
#define  iShowRulers           6
#define  iFont                 11
#define  iSound                12
#define rMovable               130
#define  iCharcoal             7
#define  iOilPaint             8
#define  iPencil               9
#define  iChalk                10
#define  iClockOne             12
#define rModeless              131
#define  iEditText             2
#define rSplash                132
#define rAlertStrings          128
#define  sLabel                1
#define  sNarrative            2
#define rPixelPattern          128
#define kSearchModeless        1

#define kReturn                (SInt8) 0x0D
#define kEnter                 (SInt8) 0x03
#define kEscape                (SInt8) 0x1B
#define kPeriod                (SInt8) 0x2E

#define MAXLONG                0x7FFFFFFF

// ..................................................................... global variables

Ptr              gPreAllocatedBlockPtr;
ModalFilterUPP   eventFilterUPP;
Str255           gCurrentString;
WindowPtr        gWindowPtr;
SInt16           gPixelDepth;
Boolean          gIsColourDevice            = false;
SInt32           gSleepTime;
Boolean          gDone;
Boolean          gInBackground;
Boolean          gGridSnap                  = kControlCheckBoxUncheckedValue;
Boolean          gShowGrid                  = kControlCheckBoxUncheckedValue;
Boolean          gShowRule                  = kControlCheckBoxUncheckedValue;  
SInt16           gBrushType                 = iCharcoal;
DialogPtr        gSearchModelessDialogPtr   = NULL;

// .................................................................. function prototypes

void    main                             (void);
void    doInitManagers                   (void);
void    eventLoop                        (void);
void    doIdle                           (void);
void    doEvents                         (EventRecord *);
void    doMouseDown                      (EventRecord *);
void    doKeyDown                        (EventRecord *);
void    doUpdate                         (EventRecord *);
void    doUpdateDocument                 (WindowPtr);
void    doUpdateModelessDialog           (EventRecord *);
void    doActivate                       (EventRecord *);
void    doOSEvent                        (EventRecord *);
void    doActivateDocument               (WindowPtr,Boolean);
void    doActivateModelessDialog         (EventRecord *,Boolean);
void    doAdjustMenus                    (void);
void    doMenuChoice                     (SInt32);
void    doEditMenu                       (SInt16);
void    doDemonstrationMenu              (SInt16);
void    doExplicitlyDeactivateDocument   (void);
Boolean doMovableModalAlert              (void);
Boolean doModalDialog                    (void);
Boolean doMovableModalDialog             (void);
Boolean doCreateOrShowModelessDialog     (void);
void    doInContent                      (EventRecord *);
void    doButtonHitInSearchModeless      (void);
void    doHideModelessDialog             (WindowPtr);
void    doPopupMenuChoice                (ControlHandle,SInt16,SInt16);
void    doPlaySound                      (Str255);
void    doDrawMessage                    (WindowPtr,Boolean);
void    doCopyPString                    (Str255,Str255);
void    doGetDepthAndDevice              (void);

pascal Boolean eventFilter  (DialogPtr,EventRecord *,SInt16 *);

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main

void  main(void)
{
  SInt32      response;
  DialogPtr   modalDialogPtr;
  SInt16      itemHit;
  Handle      menubarHdl;
  MenuHandle  menuHdl;
  OSErr       osError;
  
  // ........ get nonrelocatable block low in heap for modeless dialog's dialog structure

  if(!(gPreAllocatedBlockPtr = NewPtr(sizeof(DialogRecord))))
    ExitToShell();

  // ................................................................ initialise managers

  doInitManagers();

  // .............. open small modal dialog and automatically dismiss it after 10 seconds

#if TARGET_CPU_PPC
  osError = Gestalt(gestaltSystemVersion,&response);
  
  if(osError == noErr && response >= 0x00000850)
  {
    modalDialogPtr = GetNewDialog(rSplash,NULL,(WindowPtr) -1);

    SetDialogTimeout(modalDialogPtr,kStdOkItemIndex,10);
  
    do
    {
      ModalDialog(NULL,&itemHit);  
    } while(itemHit != kStdOkItemIndex);
  
    DisposeDialog(modalDialogPtr);
  }
#endif

  // ................................ create routine descriptor for event filter function

  eventFilterUPP = NewModalFilterProc((ProcPtr) eventFilter);

  // .......................................................... 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');

  // ............................................ initial advisory text for window header

  doCopyPString("\pBalloon help is available for dialog boxes",gCurrentString);

  // ....................................................... open a window, set font size

  if(!(gWindowPtr = GetNewCWindow(rWindow,NULL,(WindowPtr)-1)))
    ExitToShell();

  SetPort(gWindowPtr);
  TextSize(10);
  
  // ......... 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();  
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× eventLoop

void  eventLoop(void)
{
  EventRecord    eventStructure;
  Boolean        gotEvent;    

  gSleepTime = MAXLONG;
  gDone = false;
  
  while(!gDone)
  {
    gotEvent = WaitNextEvent(everyEvent,&eventStructure,gSleepTime,NULL);

    if(gotEvent)
      doEvents(&eventStructure);
    else
      doIdle();
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doIdle

void  doIdle(void)
{
  if(FrontWindow() == gSearchModelessDialogPtr)
    IdleControls(gSearchModelessDialogPtr);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  switch(eventStrucPtr->what)
  {
    case mouseDown:
      doMouseDown(eventStrucPtr);
      break;

    case keyDown:
    case autoKey:
      doKeyDown(eventStrucPtr);
      break;

    case updateEvt:
      doUpdate(eventStrucPtr);
      break;

    case activateEvt:
      doActivate(eventStrucPtr);
      break;

    case osEvt:
      doOSEvent(eventStrucPtr);
      HiliteMenu(0);
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMouseDown

void  doMouseDown(EventRecord *eventStrucPtr)
{
  WindowPtr windowPtr;
  SInt16    partCode;

  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);
      break;

    case inGoAway:
      if(TrackGoAway(windowPtr,eventStrucPtr->where))
      {
        if(((WindowPeek) windowPtr)->windowKind == kDialogWindowKind)
        {
          doHideModelessDialog(windowPtr);
          doCopyPString("\pBalloon help is available for dialog boxes",gCurrentString);
        }
      }
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doKeyDown

void  doKeyDown(EventRecord *eventStrucPtr)
{
  WindowPtr     windowPtr;
  SInt8         charCode;
  SInt16        whichModeless, itemHit;
  ControlHandle controlHdl;
  UInt32        finalTicks;

  windowPtr = FrontWindow();
  charCode = eventStrucPtr->message & charCodeMask;

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    if((eventStrucPtr->modifiers & cmdKey) != 0)
    {
      doAdjustMenus();
      doMenuChoice(MenuEvent(eventStrucPtr));
    }
  }
  else
  {
    if((whichModeless = ((WindowPeek) windowPtr)->refCon) == kSearchModeless)
    {
      if((charCode == kReturn) || (charCode == kEnter))
      {
        GetDialogItemAsControl(windowPtr,kStdOkItemIndex,&controlHdl);
        HiliteControl(controlHdl,kControlButtonPart);
        Delay(8,&finalTicks);
        HiliteControl(controlHdl,kControlNoPart);
        doButtonHitInSearchModeless();
        return;
      }
    
      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        if(charCode == 'X' || charCode == 'x' ||  charCode == 'C' || charCode == 'c' ||
           charCode == 'V' || charCode == 'v')
        {
          HiliteMenu(mEdit);
          DialogSelect(eventStrucPtr,&(DialogPtr) windowPtr,&itemHit);
          Delay(4,&finalTicks);
          HiliteMenu(0);
        }
        else
        {
          doAdjustMenus();
          doMenuChoice(MenuEvent(eventStrucPtr));
        }
        return;
      }
  
      DialogSelect(eventStrucPtr,&(DialogPtr) windowPtr,&itemHit);
    }
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdate

void  doUpdate(EventRecord *eventStrucPtr)
{
  WindowPtr  windowPtr;

  windowPtr = (WindowPtr) eventStrucPtr->message;

  if(!(IsDialogEvent(eventStrucPtr)))
    doUpdateDocument(windowPtr);
  else
    doUpdateModelessDialog(eventStrucPtr);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdateDocument

void  doUpdateDocument(WindowPtr windowPtr)
{
  GrafPtr       oldPort;
  PixPatHandle  pixpatHdl;

  BeginUpdate(windowPtr);

  GetPort(&oldPort);
  SetPort(windowPtr);

  pixpatHdl = GetPixPat(rPixelPattern);
  FillCRect(&windowPtr->portRect,pixpatHdl);
  DisposePixPat(pixpatHdl);
  doDrawMessage(windowPtr,windowPtr == FrontWindow() && !gInBackground);

  SetPort(oldPort);
    
  EndUpdate(windowPtr);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdateModelessDialog

void  doUpdateModelessDialog(EventRecord *eventStrucPtr)
{
  WindowPtr windowPtr;
  SInt16    itemHit;

  DialogSelect(eventStrucPtr,&windowPtr,&itemHit);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doActivate

void  doActivate(EventRecord *eventStrucPtr)
{
  WindowPtr  windowPtr;
  Boolean    becomingActive;

  windowPtr = (WindowPtr) eventStrucPtr->message;
  becomingActive = (eventStrucPtr->modifiers & activeFlag) == activeFlag;

  if(!(IsDialogEvent(eventStrucPtr)))
    doActivateDocument(windowPtr,becomingActive);
  else
    doActivateModelessDialog(eventStrucPtr,becomingActive);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOSEvent

void  doOSEvent(EventRecord *eventStrucPtr)
{
  WindowPtr  windowPtr;
  
  switch((eventStrucPtr->message >> 24) & 0x000000FF)
  {
    case suspendResumeMessage:

      windowPtr = FrontWindow();
      gInBackground = (eventStrucPtr->message & resumeFlag) == 0;

      if(!(IsDialogEvent(eventStrucPtr)))
        doActivateDocument(windowPtr,!gInBackground);
      else
        doActivateModelessDialog(eventStrucPtr,!gInBackground);
      break;

    case mouseMovedMessage:
    break;
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doActivateDocument

void  doActivateDocument(WindowPtr windowPtr,Boolean becomingActive)
{
  if(becomingActive)
    doAdjustMenus();

  doDrawMessage(windowPtr,becomingActive);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doActivateModelessDialog

void  doActivateModelessDialog(EventRecord *eventStrucPtr,Boolean becomingActive)
{
  SInt16    whichModeless;
  WindowPtr windowPtr;
  SInt16    itemHit;  

  DialogSelect(eventStrucPtr,&windowPtr,&itemHit);

  if(becomingActive)
  {
    doAdjustMenus();
    if((whichModeless = ((WindowPeek) windowPtr)->refCon) == kSearchModeless)
      gSleepTime = LMGetCaretTime();
  }
  else
  {
    if((whichModeless = ((WindowPeek) windowPtr)->refCon) == kSearchModeless)
      gSleepTime = MAXLONG;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAdjustMenus

void  doAdjustMenus(void)
{
  WindowPtr   windowPtr;
  MenuHandle  menuHdl;

  windowPtr = FrontWindow();

  if(((WindowPeek) windowPtr)->windowKind == kApplicationWindowKind)
  {
    menuHdl = GetMenuHandle(mFile);
    EnableItem(menuHdl,0);
    DisableItem(menuHdl,4);
    menuHdl = GetMenuHandle(mEdit);
    DisableItem(menuHdl,0);
    menuHdl = GetMenuHandle(mDemonstration);
    EnableItem(menuHdl,0);    
    EnableItem(menuHdl,5);
  }
  else if(((WindowPeek) windowPtr)->windowKind == kDialogWindowKind)
  {
    menuHdl = GetMenuHandle(mFile);
    EnableItem(menuHdl,0);
    EnableItem(menuHdl,4);
    menuHdl = GetMenuHandle(mEdit);
    EnableItem(menuHdl,0);    
    menuHdl = GetMenuHandle(mDemonstration);
    EnableItem(menuHdl,0);    
    DisableItem(menuHdl,5);
  }

  DrawMenuBar();
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× 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;
      else if(menuItem == iClose)
      {
        if(((WindowPeek) FrontWindow())->windowKind == kDialogWindowKind)
          doHideModelessDialog(FrontWindow());
      }
      break;

    case mEdit:
      doEditMenu(menuItem);
      break;

    case mDemonstration:
      doDemonstrationMenu(menuItem);
      break;
  }

  HiliteMenu(0);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEditMenu

void  doEditMenu(SInt16 menuItem)
{
  WindowPtr windowPtr;
  SInt16    whichModeless;

  windowPtr = FrontWindow();

  if(((WindowPeek) windowPtr)->windowKind == kDialogWindowKind)
  {
    if((whichModeless = ((WindowPeek) windowPtr)->refCon) == kSearchModeless)
    {
      switch(menuItem)
      {
        case iCut:
          DialogCut((DialogPtr) windowPtr);
          break;

        case iCopy:
          DialogCopy((DialogPtr) windowPtr);
          break;

        case iPaste:
          DialogPaste((DialogPtr) windowPtr);
          break;

        case iClear:
          DialogDelete((DialogPtr) windowPtr);
          break;
      }
    }
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDemonstrationMenu

void  doDemonstrationMenu(SInt16 menuItem)
{
  switch(menuItem)
  {
    case iModalAlert:
      doExplicitlyDeactivateDocument();
      StopAlert(rAlert,eventFilterUPP);
      break;

    case iMovableAlert:
      doExplicitlyDeactivateDocument();
      if(!doMovableModalAlert())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

      break;

    case iModalDialog:
      doExplicitlyDeactivateDocument();
      if(!doModalDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iMovableModalDialog:
      doExplicitlyDeactivateDocument();
      if(!doMovableModalDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iModeless:
      if(!doCreateOrShowModelessDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××× doExplicitlyDeactivateDocument

void  doExplicitlyDeactivateDocument(void)
{
  if(FrontWindow() && ((WindowPeek) FrontWindow())->windowKind != kDialogWindowKind)
    doActivateDocument(FrontWindow(),false);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMovableModalAlert

Boolean  doMovableModalAlert(void)
{
  AlertStdAlertParamRec  paramRec;
  Str255                labelText;
  Str255                narrativeText;
  OSErr                  osError;
  SInt16                itemHit;

  paramRec.movable        = true;
  paramRec.helpButton     = false;
  paramRec.filterProc     = eventFilterUPP;
  paramRec.defaultText    = (StringPtr) kAlertDefaultOKText;
  paramRec.cancelText     = (StringPtr) kAlertDefaultCancelText;
  paramRec.otherText      = NULL;
  paramRec.defaultButton  = kAlertStdAlertOKButton;
  paramRec.cancelButton   = kAlertStdAlertCancelButton;
  paramRec.position       = kWindowDefaultPosition;

  GetIndString(labelText,rAlertStrings,sLabel);
  GetIndString(narrativeText,rAlertStrings,sNarrative);

  osError = StandardAlert(kAlertCautionAlert,labelText,narrativeText,¶mRec,&itemHit);
  if(osError == noErr)
    return true;
  else
    return false;
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doModalDialog

Boolean  doModalDialog(void)
{
  DialogPtr     modalDialogPtr;
  ControlHandle controlHdl;
  SInt16        itemHit, controlValue;

  if(!(modalDialogPtr = GetNewDialog(rModal,NULL,(WindowPtr) -1)))
    return(false);

  SetDialogDefaultItem(modalDialogPtr,kStdOkItemIndex);
  SetDialogCancelItem(modalDialogPtr,kStdCancelItemIndex);

  GetDialogItemAsControl(modalDialogPtr,iGridSnap,&controlHdl);
  SetControlValue(controlHdl,gGridSnap);
  GetDialogItemAsControl(modalDialogPtr,iShowGrid,&controlHdl);
  SetControlValue(controlHdl,gShowGrid);
  GetDialogItemAsControl(modalDialogPtr,iShowRulers,&controlHdl);
  SetControlValue(controlHdl,gShowRule);

  ShowWindow(modalDialogPtr);

  do
  {
    ModalDialog(eventFilterUPP,&itemHit);
    
    if(itemHit == iGridSnap || itemHit == iShowGrid || itemHit == iShowRulers)
    {
      GetDialogItemAsControl(modalDialogPtr,itemHit,&controlHdl);
      SetControlValue(controlHdl,!GetControlValue(controlHdl));
    }
    else if(itemHit == iFont || itemHit == iSound)
    {
      GetDialogItemAsControl(modalDialogPtr,itemHit,&controlHdl);
      controlValue = GetControlValue(controlHdl);
      doPopupMenuChoice(controlHdl,controlValue,itemHit);
    }
  } while((itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex));

  if(itemHit == kStdOkItemIndex)
  {
    GetDialogItemAsControl(modalDialogPtr,iGridSnap,&controlHdl);
    gGridSnap = GetControlValue(controlHdl);
    GetDialogItemAsControl(modalDialogPtr,iShowGrid,&controlHdl);
    gShowGrid = GetControlValue(controlHdl);
    GetDialogItemAsControl(modalDialogPtr,iShowRulers,&controlHdl);
    gShowRule = GetControlValue(controlHdl);        
  }

  DisposeDialog(modalDialogPtr);
  doCopyPString("\pBalloon help is available for dialog boxes",gCurrentString);

  return(true);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMovableModalDialog

Boolean  doMovableModalDialog(void)
{
  DialogPtr     movableModaDialogPtr;
  ControlHandle controlHdl;
  SInt16        oldBrushType, itemHit, a;
  
  if(!(movableModaDialogPtr = GetNewDialog(rMovable,NULL,(WindowPtr) -1)))
    return(false);

  SetDialogDefaultItem(movableModaDialogPtr,kStdOkItemIndex);
  SetDialogCancelItem(movableModaDialogPtr,kStdCancelItemIndex);
  SetDialogTracksCursor(movableModaDialogPtr,true);

  GetDialogItemAsControl(movableModaDialogPtr,gBrushType,&controlHdl);
  SetControlValue(controlHdl,kControlRadioButtonCheckedValue);
  
  GetDialogItemAsControl(movableModaDialogPtr,iClockOne,&controlHdl);
  SetKeyboardFocus(movableModaDialogPtr,controlHdl,kControlClockPart);

  oldBrushType = gBrushType;

  ShowWindow(movableModaDialogPtr);

  do
  {
    ModalDialog(eventFilterUPP,&itemHit);

    if(itemHit >= iCharcoal && itemHit <= iChalk)
    {
      for(a=iCharcoal;a<=iChalk;a++)
      {
        GetDialogItemAsControl(movableModaDialogPtr,a,&controlHdl);
        SetControlValue(controlHdl,kControlRadioButtonUncheckedValue);
      }

      GetDialogItemAsControl(movableModaDialogPtr,itemHit,&controlHdl);
      SetControlValue(controlHdl,kControlRadioButtonCheckedValue);
      gBrushType = itemHit;
    }
  } while((itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex));

  if(itemHit == kStdCancelItemIndex)
    gBrushType = oldBrushType;

  DisposeDialog(movableModaDialogPtr);
  return(true);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCreateOrShowModelessDialog

Boolean  doCreateOrShowModelessDialog(void)
{
  Boolean       booleanData;    
  ControlHandle controlHdl;
  Str255        stringData = "\pwicked googly";

  if(gSearchModelessDialogPtr == NULL)
  {
    if(!(gSearchModelessDialogPtr = GetNewDialog(rModeless,gPreAllocatedBlockPtr,
                                                 (WindowPtr) -1)))
      return(false);

    SetWRefCon(gSearchModelessDialogPtr,(SInt32) kSearchModeless);
    
    booleanData = true;
    GetDialogItemAsControl(gSearchModelessDialogPtr,kStdOkItemIndex,&controlHdl);
    SetControlData(controlHdl,kControlNoPart,kControlPushButtonDefaultTag,
                   sizeof(booleanData),(Ptr) &booleanData);

    GetDialogItemAsControl(gSearchModelessDialogPtr,iEditText,&controlHdl);
    SetDialogItemText((Handle) controlHdl,stringData);
    SelectDialogItemText(gSearchModelessDialogPtr,iEditText,0,32767);

    ShowWindow(gSearchModelessDialogPtr);
  }
  else
  {
    ShowWindow(gSearchModelessDialogPtr);
    SelectWindow(gSearchModelessDialogPtr);
  }

  return(true);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInContent

void  doInContent(EventRecord *eventStrucPtr)
{
  WindowPtr windowPtr;
  SInt16    whichModeless;
  DialogPtr dialogPtr;
  SInt16    itemHit;

  windowPtr = FrontWindow();

  if(!(IsDialogEvent(eventStrucPtr)))
  {  
    // Handle clicks in document window content region here.
  }
  else
  {
    if((whichModeless = ((WindowPeek) windowPtr)->refCon) == kSearchModeless)
    {
      if(DialogSelect(eventStrucPtr,&dialogPtr,&itemHit))
        if(itemHit == kStdOkItemIndex)
          doButtonHitInSearchModeless();
    }
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doButtonHitInSearchModeless

void  doButtonHitInSearchModeless(void)
{
  ControlHandle  controlHdl;
  WindowPtr      oldPort;

  GetDialogItemAsControl(gSearchModelessDialogPtr,iEditText,&controlHdl);
  GetDialogItemText((Handle) controlHdl,gCurrentString);

  GetPort(&oldPort);
  SetPort(gWindowPtr);
  doDrawMessage(gWindowPtr,false);
  SetPort(oldPort);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doHideModelessDialog

void  doHideModelessDialog(WindowPtr windowPtr)
{
  SInt16  whichModeless;

  HideWindow(windowPtr);

  if((whichModeless = ((WindowPeek) windowPtr)->refCon) == kSearchModeless)
    gSleepTime = MAXLONG;
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× eventFilter

pascal Boolean  eventFilter(DialogPtr dialogPtr,EventRecord *eventStrucPtr,SInt16 *itemHit)
{
  Boolean  handledEvent;
  GrafPtr  oldPort;

  handledEvent = false;
  
  if((eventStrucPtr->what == updateEvt) && 
     ((WindowPtr) eventStrucPtr->message != dialogPtr))
  {
    doUpdate(eventStrucPtr);
  }
  else
  {
    GetPort(&oldPort);
    SetPort(dialogPtr);

    handledEvent = StdFilterProc(dialogPtr,eventStrucPtr,itemHit);

    SetPort(oldPort);
  }

  return(handledEvent);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doPopupMenuChoice

void  doPopupMenuChoice(ControlHandle controlHdl,SInt16 controlValue,SInt16 itemHit)
{
  MenuHandle  menuHdl;
  Size        actualSize;
  Str255      itemName;
  GrafPtr     oldPort;

  GetControlData(controlHdl,kControlNoPart,kControlPopupButtonMenuHandleTag,
                 sizeof(menuHdl),(Ptr) &menuHdl,&actualSize);
  GetMenuItemText(menuHdl,controlValue,itemName);    
  doCopyPString(itemName,gCurrentString);

  GetPort(&oldPort);
  SetPort(gWindowPtr);
  doDrawMessage(gWindowPtr,false);
  SetPort(oldPort);

  if(itemHit == iSound)
    doPlaySound(itemName);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doPlaySound

void  doPlaySound(Str255 sndResourceName)
{
  SndListHandle  soundHdl;
  SndChannelPtr  soundChanPtr = NULL;

  if(soundHdl = (SndListHandle) GetNamedResource('snd ',sndResourceName))
    SndPlay(soundChanPtr,soundHdl,1);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDrawMessage

void  doDrawMessage(WindowPtr windowPtr,Boolean inState)
{
  Rect    headerRect;
  SInt16  windowWidth, stringWidth;

  SetRect(&headerRect,windowPtr->portRect.left - 1,windowPtr->portRect.top - 1,
          windowPtr->portRect.right + 1,windowPtr->portRect.top + 26);
  DrawThemeWindowHeader(&headerRect,inState);
  
  if(inState == kThemeStateActive)
    SetThemeTextColor(kThemeTextColorWindowHeaderActive,gPixelDepth,gIsColourDevice);
  else
    SetThemeTextColor(kThemeTextColorWindowHeaderInactive,gPixelDepth,gIsColourDevice);

  windowWidth = (windowPtr)->portRect.right - (windowPtr)->portRect.left;
  stringWidth = StringWidth(gCurrentString);
  MoveTo((windowWidth / 2) - (stringWidth / 2), 17);
  DrawString(gCurrentString);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× 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 Comments

When this program is run, the user should:

*   Invoke alert and dialog boxes by choosing items in the Demonstration menu, noting
    window update/activation/deactivation and menu enabling/disabling effects.

*   Choose Show Balloons from the Help menu and pass the cursor over the various items
    in the dialog boxes, noting the information in the help balloons.  Also note the 
    updating of alert and dialog boxes, and of the window, behind the help balloon when
    the balloon closes.

*   Note the effects on the Apple, Help, and Application menus when the various alert 
    and dialog boxes are the front window.

*   Click anywhere outside the modal alert box and modal dialog box when they are the
    frontmost window, noting that the only response is the system alert sound.

*   Note that, when the movable modal alert box and movable modal dialog box are
    displayed:

*   The program can be sent to the background by clicking outside the alert or dialog
    box and the document window or by selecting another application from the Application
    menu.

*   The program can be brought to the foreground again by clicking inside the alert or
    dialog box, or the docuemnt window, or by selecting the program from the Application
    menu.

*   Note that, when the movable modal dialog box is displayed, the Edit menu and its Cut,
    Copy, and Paste items are displayed whenever the edit text field has keyboard focus.

*   Note that, when the modeless dialog box is displayed:

*   It behaves like a normal document window when the user:

*   Clicks outside it (or selects another application from the Application menu) when it
    is the frontmost window.

*   Clicks inside it (or selects the program from the Application menu) when it is not
    the frontmost window.

*   It can be hidden by clicking in the close box or by selecting Close from the File
    menu.

*   A modal alert box, movable modal alert box, modal dialog box or movable modal dialog
    box can be invoked "on top of" the modeless dialog box.

*   The Edit menu and its Cut, Copy, Paste, and Clear items are enabled so as to support
    text editing in the edit text field.

*   Note that all alert and dialog boxes respond correctly to Return and Enter key 
    presses, and that the modal alert box, modal dialog box and movable modal dialog box
    also respond correctly to escape key and Command-period presses.

*   Note that, when an alert box or dialog box is the frontmost window, the window and
    content region are deactivated, the latter evidenced by dimming of the text in the
    document window's window header and the drawing of the header in the deactivated 
    mode.

*   In the modal dialog box, click on the checkboxes to change their settings, noting
    that the new settings are remembered when the dialog box is dismissed using the OK
    button, but not remembered when the dialog box is dismissed using the Cancel button.
    Also, choose items in the two pop-up menu buttons, noting that the chosen item is
    displayed in the docuemnt window's window header.

*   In the movable modal dialog box, click on the radio buttons to change their 
    settings, noting that the new setting is remembered when the dialog box is 
    dismissed using the OK button, but not remembered when the dialog box is dismissed
    using the Cancel button.  In the case of the clock control and edit text field,
    change the item/part with keyboard focus using the Tab key or by clicking in that
    item/part.  In the case of the edit text field, enter text, and edit that text 
    using the Edit menu's Cut, Copy, Paste, and Clear items and their Command-key
    equivalents.  Note that the cursor shape changes whenever the cursor is moved over
    the edit text field.

*   In the modeless dialog box, enter text, and edit that text using the Edit menu's
    Cut, Copy, Paste, and Clear items and their Command-key equivalents.  Note that,
    because no cursor adjustment function is included in the program, the cursor shape
    does not change whenever the cursor is moved over the edit text field.  Also note
    that, when the Search button is clicked (or the Return or Enter keys are pressed)
    the text in the edit text field is displayed in the docuemnt window's window
    header.

In the 'DITL' resources for the modal and movable modal dialog boxes, note that the item
numbers of the primary group box items are lower than the item numbers of the items
visually contained by those group box items.  This is to ensure that the group boxes do
not draw over, and thus erase, the image of these contained items.

In the 'alrx' resources, note that all feature flags are set except for the
kAlertFlagsAlertIsMovable flag in the 'alrx' resource for the modal alert box.  In the
'dlgx' resources, note that all feature flags are set except for the
kDialogFlagsHandlesMovableModal flag in 'dlgx' resources for the modal dialog box and
modeless dialog box.  Thus all alert and dialog boxes have a root control and embedding
hierarchy, and are fully Appearance-compliant.

Although this program only opens one modeless dialog box, a unique value is assigned to
the associated window structure's refCon field to illustrate the usual method for
differentiating between the several modeless dialogs boxes a program could open at any
one time.

#define

The first #defines establish constants for menu bar, window, and menu resource IDs, and
for menu IDs and menu item numbers.  Constants are then established for alert and dialog
resource IDs and for the item numbers of certain items in the item lists associated with
the three dialogs.  rAlertStrings represents the resource ID of a 'STR#' holding strings
for the label and narrative text for the movable alert box, and the two following
constants are used to index these strings.  The value represented by kSearchModeless will
be assigned to the modeless dialog box's window structure's refCon field.

The penultimate block of #defines establish constants representing the character codes
for the Return, Enter, escape, and period keys.

Finally, MAXLONG is defined as the maximum possible long value.  This value will be
assigned to WaitNextEvent's sleep parameter at program launch.

Global Variables

gPreAllocatedBlockPtr will be assigned a pointer to a pre-allocated block of memory for
the modeless dialog box's dialog structure.

eventFilterUPP will be assigned a universal procedure pointer to an application-defined
event filter function.

gCurrentString will be assigned advisory and other strings for display in the document
window's window header.  gWindowPtr will be assigned the pointer to the single window
opened by the program.  gPixelDepth will be assigned the pixel depth of the graphics
port. gIsColourDevice will be assigned true if the graphics device is a colour device and
false if it is a monochrome device.  The values in these last two variables are required
by the Appearance Manager function SetThemeTextColor.

gSleepTime will be assigned the value to be used as the sleep parameter in the
WaitNextEvent call.  (This value will be changed during program execution.)  gDone
controls the exit from the main event loop.  gInBackground relates to foreground/
background switching.

The next three variables will contain the current setting of the checkboxes in the modal
dialog box.  The next variable will contain the identity of the newly selected radio
button in the movable modal dialog box. 

Finally, the pointer to the dialog structure for the modeless dialog box is declared as a
global variable.

main

After the call to doInitManagers, and provided Mac OS 8.5 or later is present, 
GetNewDialog is called to create a small modal dialog.  SetDialogTimeout is then called 
with 10 (seconds) passed in the inSecondsToWait parameter and 1 passed in the 
inButtonToPress parameter.  (In the associated 'DITL' resource, Item 1 is the OK push 
button, which has been hidden.)  The use of SetDialogTimeout requires that the 
application handle events for the dialog box through the ModalDialog function, hence the 
ModalDialog do-while loop.  This allows the Dialog Manager to simulate an item selection.
After 10 seconds, the Dialog Manager simulates a user click in the (invisible) OK button,
causing the do-while loop to exit.  The dialog is then disposed of.

The modeless dialog will be created when the user chooses the Modeless Dialog item in the
Demonstration menu, and will remain in existence until the program terminates.  To avoid
heap fragmentation effects, the nonrelocatable block for the modeless dialog's dialog
structure is pre-allocated here, before the system software managers are initialised, so
as to ensure that it is located as low in the heap as possible.

After the system software managers are initialised, a call to NewModalFilterProc creates
a routine descriptor for the event filter function.  (If this program was required to be
compiled as 68K code only, this routine descriptor would not be required.)

RegisterAppearanceClient is called to ensure that the new Appearance-compliant menu bar
definition function (resource ID 63) will be used regardless of whether system-wide
Appearance is selected on or off in the Appearance control panel.

The next block sets up the drop-down menus.

The call to the application-defined function doCopyPString causes the string in the first
parameter to be copied to the global variable gCurrentString.  The string in
gCurrentString, which will be changed at various points in the code, will be drawn in the
document window's window header.

The next block opens a window and sets the font size for the window to 10pt.

The call to the application-defined function doGetDepthAndDevice determines the current
pixel depth of the graphics port, and whether the current graphics device is a colour
device, and assigns the results to the global variables gPixelDepth and gIsColourDevice.

The main event loop is then entered, and continues until gDone is set to true.

Note that error handling here and in other areas of this demonstration program is
somewhat rudimentary.  In the unlikely event that certain calls fail, ExitToShell is
called to terminate the program.

eventLoop

The main event loop continues until gDone is set to true by the user choosing Quit from
the File menu.

The variable which will be used as WaitNextEvent's sleep parameter (gSleepTime) is
initially set to MAXLONG, indicating that the application has no need for null events and
that it will yield the microprocessor to other applications for the maximum possible time
if no events are pending for it.  Note that the value assigned to gSleepTime will be
changed at certain points in the program.

doIdle

doIdle is invoked whenever WaitNextEvent returns a null event.

If the front window is the modeless dialog box, the function IdleControls is called. 
IdleControls calls the control definition function of those controls in the specified
window which do idle-time processing.  In this case, the control is an edit text field,
and the call causes the control definition function to call TextEdit to blink the
insertion point caret.

doEvents

doEvents switches according to the event type received.  (It is important to remember at
this point that events that occur when an alert box, modal dialog box, or movable modal
dialog box has been invoked are not handled by the main event loop but by the ModalDialog
function.)

doMouseDown

doMouseDown handles mouse-down events.  Mouse-downs in the content region and in the
close box are of significance to the demonstration.

If the mouse-down occurred in the content region, and if it was not in the frontmost
window,  SelectWindow is called to generate the necessary activate events.  If the
mouse-down was in the frontmost window, the application-defined function doInContent is
called to further process the event.

If a mouse-down occurred in a close box, if TrackGoAway returns true, and if the window
is a modeless dialog box, the application-defined function doHideModeless is called.  (In
this demonstration, the modeless dialog box, but not the document window, has a close
box.)  Also, the text for the window header is replaced with the default advisory text.

doKeyDown

doKeyDown handles all key-down and auto-key events, switching according to whether the
event occurred in the modeless dialog box or the document window.

First, the character code is extracted from the message field of the event structure. 
Then IsDialogEvent is called to determine whether the event occurred in a modeless dialog
box or a document window.

If the event occurred in a document window, and if the modifiers field of the event
structure indicates that the Command key was down, the application-defined function for
adjusting the menus is called, MenuEvent is called to return the long value containing
the menu and menu item associated with the Command-key equivalent, and the long value is
passed to doMenuChoice for further handling.

If, however, the event occurred in a modeless dialog box, and if that dialog box is the
Search modeless dialog box:

*   If the key pressed was the Return or Enter key, GetDialogItemAsControl is called to
    get a handle to the single press button control in the Search modeless dialog box
    (item 1 in the item list).  The press button is then highlighted for eight ticks,
    and then unhighlighted before an application-defined function is called to extract
    the text from the edit text field and display it in the document window's window
    header.  doKeyDown then returns because it is not intended that the edit text
    field receive Return and Enter key presses.

*   If the Command key was down:

*   If either the X, C, or V key was pressed (that is, the user has pressed the Cut,
    Copy, or Paste Command-key equivalent), DialogSelect is called to further handle
    the event.  DialogSelect uses TextEdit to cut, copy, or paste the text in the edit
    text field.  (The calls to HiliteMenu briefly highlight the Edit menu to indicated
    to the user that an Edit menu Command-key equivalent has just been used.  This
    replicates the highlighting that ModalDialog performs when Command-key presses
    occur in modal and movable modal dialog boxes with edit text fields.)

*   If neither the X, C, nor V key was pressed, the application-defined function for
    adjusting the menus is called, MenuEvent is called to return the long value
    containing the menu and menu item associated with the Command-key equivalent, and
    the long value is passed to doMenuChoice for further handling.

    Thus the Command-key equivalents other than those for Cut, Copy, and Paste remain
    available to the user via the main event loop, while the Command-key equivalents
    for  Cut, Copy, and Paste are trapped and passed to DialogSelect for handling.
    At the last line in the outer if block, doKeyDown returns if the Command key was
    down.

*   If the Return key and the Enter key were not pressed, and if the Command key was
    not down, DialogSelect is called to handle the keystroke in conjunction with
    TextEdit, the visual result being that the character appears in the edit text
    field.

doUpdate

doUpdate performs the initial handling of update events.

If the call to IsDialogEvent reveals that the event is for a window of the document kind,
an application-defined function for updating the document window is called, otherwise an
application-defined function for updating modeless dialog boxes is called.

doUpdateDocument

doUpdateDocument simply fills the content region of the document window with a colour,
using a pixel patter ('ppat') resource and a call to FillCRect for that purpose, and then
calls an application-defined function which draws a window header frame, and some text,
in the appropriate mode (activated or deactivated) depending on whether the window is the
frontmost window or not.

doUpdateModelessDialog

doUpdateModelessDialog calls DialogSelect to handle the update event.  DialogSelect calls
BeginUpdate, DrawDialog, and EndUpdate to redraw the the modeless dialog's content area. 
(To restrict the redraw to the update region, an alternative is to call BeginUpdate,
UpdateDialog, and EndUpdate.)

doActivate

doActivate performs initial handling of activate events.

If the call to IsDialogEvent reveals that the event is for a window of the document kind,
the application-defined function for activating/deactivating the document window is
called, otherwise the application-defined function for activating/deactivating a modeless
dialog box is called.

doOSEvent

doOSEvent handles operating system events,.

If the event is a suspend/resume event, doOSEvent calls the appropriate window activation
function (depending on whether the event is for the document window or a modeless
dialog), indicating with the value in gInBackground whether the window should be
activated or deactivated.

doActivateDocument

doActivateDocument performs window activation/deactivation for the document window.

If the window is becoming active, the menus are adjusted as appropriate for a document
window.  The call to the application-defined function doDrawMessage draws a window header
frame in the window, and some advisory text, in either the activated or deactivated mode.

doActivateModelessDialog

doActivateModelessDialog performs window activation and deactivation for a modeless
dialog box.

DialogSelect is called to handle the event.  If the modeless dialog box is becoming
active, DialogSelect activates all controls and redraws the one-pixel-wide modeless
dialog frame in the undimmed mode.  If the modeless dialog box is going to the back,
DialogSelect deactivates all controls and redraws the one-pixel-wide modeless dialog
frame in the dimmed mode.

At the next block, if the modeless dialog box is becoming active, and if it is the Search
modeless dialog box (identified by a unique value assigned by the application to the
dialog window structure's refCon field), the global variable used in the sleep parameter
of the WaitNextEvent function is assigned the value returned by LMGetCaretTime (which is
the value set by the user at the Insertion Point Blinking section in the General Controls
control panel).  This is necessary to endure that null events will always be generated,
and thus doIdle and IdleControls will be called, at an interval short enough to ensure
insertion point caret blinking at the proper rate.  (The differentiation between modeless
dialog boxes in this instance is for illustrative purposes only, since the program only
ever opens one modeless dialog box.  Other modeless dialog boxes might not necessarily
contain edit text fields.)

If the Search modeless dialog box is to be deactivated, the sleep parameter for the
WaitNextEvent function is reset to the maximum long value.

doAdjustMenus

doAdjustMenus is called by the document window and modeless dialog box activation
functions to adjust the menus as appropriate to the type of the frontmost window, that
is, whether the frontmost window is the document window or the modeless dialog box.

doMenuChoice

doMenuChoice handles menu choices.

If the choice was the Quit item in the File menu, gDone is set to true, thus terminating
the program.  If the choice was the Close item in the File menu, and if the front window
is a modeless dialog box, an application-defined function which hides modeless dialog
boxes is called.  (In this program, and because the document window does not have a close
box, the Close item is only enabled when the modeless dialog box is the front window.)

doEditMenu

doEditMenu first determines whether the front window is a modeless dialog box, and
whether it is the Search modeless dialog (which has an edit text field).  If so, Cut,
Copy, Paste, and Clear selections from the Edit menu will cause the Dialog Manager, in
conjunction with TextEdit, to perform those operations on selected text in the edit text
field.  The call to the application-defined function doFixEditTextBackground following
the Cut, Paste, and Clear calls is intended to compensate for what appears to be a small
bug in the edit text field control definition function (see below).

doDemonstrationMenu

doDemonstrationMenu handles choices from the Demonstration menu, switching according to
the menu item passed to it.  (Error handling in this function is somewhat rudimentary in
that the program simply terminates.)

If the user chose Modal Alert, StopAlert is called to create, display, manage, and
dispose of the modal alert box.  Before invoking any type of alert box, however, an
application must explicitly deactivate the front document window, if one exists. 
Accordingly, an application-defined function is called to perform that action.  Note that
a universal procedure pointer to an application-defined event filter function is passed
in StopAlert's second parameter.  StopAlert handles all user interaction within the modal
alert box, disposing of the alert box when the user clicks the OK button or presses the
Return key.

If the user chose Movable Modal Alert, the application-defined function which deactivates
the frontmost document window (if one exists) is called, following which the application
defined function which creates, displays, handles user interaction, and disposes of the
movable modal alert box is called.  (As will be seen, for the movable modal alert box
also uses the application-defined event filter function.)

if the user chose Modal Dialog or Movable Modal Dialog, the same general procedure is
followed, except that the application-defined function which creates, displays, handles
user interaction, and disposes of the modal dialog or movable modal dialog is called. 
(As will be seen, for the modal dialog box and movable modal dialog box also use the
application-defined event filter function.)

If the user chose Modeless Dialog, the application-defined function for creating and
displaying the modeless dialog box is called.

doExplicitlyDeactivateDocument

doExplicitlyDeactivateDocument is called prior to the opening of all but the modeless
dialog box to explicitly deactivate the frontmost document window (if one exists).

If there is at least one window of any type open, and if that front window is of the
document window kind, the application-defined function for activating/deactivating
document windows is called to deactivate the window.

doMovableModalAlert

doMovableModalAlert creates, displays, manages, and disposes of the movable modal alert
box.  Unlike the modal alert box, and all the dialog boxes, the movable modal dialog box
in this demonstration is created programmatically, rather than from 'ALRT' and 'alrx'
resources.

At the first nine lines, values are assigned to the fields of a standard alert structure. 
In sequence: the alert box is to be a movable modal alert box; a help button is not to be
displayed; the event filter function used is to be the application-defined event filter
function pointed to by the universal procedure pointer eventFilterUPP; the default text
for the OK button is to be used; the default text for the Cancel button is to be used; no
"left-most" button is required;  the default push button is to be the first push button
(which will thus have the default ring drawn around it and have the Return and Enter keys
aliased to it); the Cancel push button is to be the second push button (which will thus
have escape and Command-period key presses aliased to it); the alert box is to be
displayed in the alert position on the parent window screen.  (With regard to the last
field, in this structure, the constant kWindowDefaultPosition equates to
kWindowAlertPositionParentWindowScreen.)

The two calls to GetIndString retrieve the specified strings from the specified 'STR#'
resource.  These are passed in the label text and narrative text parameters in the
following call to StandardAlert.

The call to StandardAlert creates and displays the alert, handles all user interaction
(by internally calling ModalDialog), including dismissing the alert box when either the
OK or Cancel buttons are hit.  (The item hit is returned in StandardAlert's last
parameter.  In a real application, the appropriate action would be taken, based on which
item was hit, following the call to StandardAlert.)

doModalDialog

doModalDialog creates, displays, manages, and disposes of the modal dialog box.

The call to GetNewDialog creates the modal dialog box from the specified resource as the
frontmost window.

The call to SetDialogDefaultItem tells the Dialog Manager which is the default push
button item, to alias the Return and Enter keys to that item, and to draw the default
ring around that item.  The call to SetDialogCancelItem tells the Dialog Manager which is
the Cancel push button item, and aliases the escape key and Command-period key presses to
that item.

The next block gets handles to the three checkbox controls and sets the value of those
controls to the current values contained in the global variables relating to each
control.

With the modal dialog box fully prepared, it is made visible by the call to ShowWindow.

The do/while loop continues to execute until ModalDialog reports that either the OK or
Cancel button has been "hit".  Within the loop, ModalDialog retains control until one of
the enabled items has been hit.

If a checkbox is hit, GetDialogItemAsControl is called to get a handle to the control and
SetControlValue is called to flip that control's control value.  (If it is 0, it is
flipped to 1, and vice versa.)  If one of the pop-up menu buttons is hit,
GetDialogItemAsControl is called to get a handle to the control and GetControlValue is
called to get the menu item number of the menu item chosen, following which an
application defined function is called to extract the menu item text and display it in
the window header.  (In the case of the Sound pop-up menu button, an additional function
is called to play the associated 'snd ' resource.)

Note that the first parameter in the ModalDialog call is a universal procedure pointer to
the application-defined event filter function.

When the do/while loop exits, and if the user hit the OK button, handles to each of the
three checkboxes are retrieved for the purposes of retrieving the control's value and
assigning it to the relevant global variable.  (If the user "hit" the Cancel button, the
global variables retain the values they contained before the dialog was created and
displayed.)

The dialog is then disposed of, and true is returned to the calling function.  (The call
to doCopyPString simply causes the text displayed in the window header text to be
replaced with the default advisory text.)

doMovableModalDialog

doMovableModalDialog creates, displays, manages, and disposes of the movable modal dialog
box.

The call to GetNewDialog creates the movable modal dialog box from the specified resource
as the frontmost window.

The call to SetDialogDefaultItem tells the Dialog Manager which is the default push
button item, to alias the Return and Enter keys to that item, and to draw the default
ring around that item.  The call to SetDialogCancelItem tells the Dialog Manager which is
the Cancel push button item, and to alias the escape key and Command-period key presses
to that item.  The call to SetDialogTracksCursor tells the Dialog Manager to track the
cursor and change it to the I-Beam cursor shape whenever it is over an edit text field.

The first call to GetDialogItemAsControl gets a handle to the radio button control
represented by the current value in the global variable gBrushType.  The value of that
control is then set to 1.  The second call to GetDialogItemAsControl gets a handle to the
clock control.  The call to SetKeyboardFocus sets the keyboard focus to that item.

Before the session of user interaction begins, the current value in the global variable
gBrushType, which stores the item number of the currently selected radio button, is
copied to the local variable oldBrushTupe.

With the movable modal dialog box fully prepared, it is made visible by the call to
ShowWindow.

The do/while loop continues to execute until ModalDialog reports that either the OK or
Cancel button has been "hit".  Within the loop, ModalDialog retains control until one of
the enabled items is hit.

If a radio button is hit, a for loop sets the control value of all radio button controls
to 0.  A call to GetDialogItemAsControl then gets a handle to the radio button control
that was hit.  A call to  SetControlValue then sets that control's value to 1, and the
item number of this radio button is assigned to the global variable gBrushType.

Note that the first parameter in the ModalDialog call is a universal procedure pointer to
the application-defined event filter function.  Note also that all user interaction
relating to the clock control and edit text field is handled automatically by
ModalDialog, including the movement of keyboard focus between the items.

When the do/while loop exits, and if the user hit the Cancel button, the value stored in
the local variable oldBrushType is assigned to gBrushType, ensuring that any change to
the currently selected radio button within the do/while loop is ignored.  (In a real
application, a long date/time value from the clock control, and the text from the edit
text field would possibly be retrieved at this point if the user hit the OK push button.)

The dialog is then disposed of, and true is returned to the calling function.

doCreateOrShowModelessDialog

In this program, the modeless dialog box is only created once, that is, when the user
first chooses Modeless Dialog from the Demonstration menu.  Clicks in its close box, or
choosing Close from the File menu while the modeless dialog is the frontmost window, will
cause the dialog box to be hidden, not disposed of.

Accordingly, the first line determines whether the modeless dialog box is already open. 
If it is not: the call to GetNewDialog creates the modeless dialog box (with the
previously pre-allocated nonrelocatable block passed in the second parameter); the call
to SetWRefCon assigns the constant kSearchModeless to the refCon field of the dialog's
window structure so as to facilitate the future identification of this particular
modeless dialog box; a call to SetControlData with the kControlPushButtonDefaultTag tag
constant causes the control definition function to draw the default ring around the
specified push button; a call to SetDialogItemText assigns some initial text to the edit
text field; a call to SelectDialogItemText selects the text in the edit text field. 
(Note that, if the edit text field did not contain text, this latter call would simply
display the insertion point caret, which would be made to blink by the call to
IdleControls within the application-defined function doIdle.)

If, on the other hand, the modeless dialog box has already been opened, the call to
ShowWindow displays the dialog box and the call to SelectWindow generates the necessary
activate events.

doInContent

doInContent continues the content region mouse-down handling initiated by doMouseDown. 
doInContent is called by doMouseDown only if the mouse-down occurred in the frontmost
(active) window.

The first line gets a pointer to the frontmost window.

If the event occurred in the document window, the mouse-down event would be handled in
the if section of the if/else block.  (No action is required in this demonstration.)

If the event occurred in a modeless dialog box, and if that modeless dialog box is the
Search modelss dialog box (which contains an edit text field), DialogSelect is called to
handle the event.  DialogSelect tracks enabled controls (only the push button is
enabled), returning true if the mouse button is released while the cursor is still inside
the control, and highlights any selection made in the edit text field.  If DialogSelect
returns true, and if the item hit was the OK (Search) push button, an application-defined
function is called to perform the actions required in the event of a hit on that button.
doButtonHitInSearchModeless

doButtonHitInSearchModeless further processes, to completion, a hit on the OK (Search)
button in the modeless dialog box.  It simply demonstrates retrieval of the text in an
edit text field in a dialog box.

The call to GetDialogItemAsControl gets a handle to the edit text field, and the call to
GetDialogItemText copies the text in the edit text field to the global variable
gCurrentString.  The following lines cause that text to be drawn, in the dimmed mode, in
the window header in the document window.

doHideModelessDialog

doHideModelessDialog hides a modeless dialog box.

The call to HideWindow makes the dialog box invisible.  If the modeless dialog box is the
Search modal dialog box, the sleep parameter for the WaitNextEvent function is reset to
the maximum possible long value, because insertion point caret blinking is not required
while the Search dialog box is hidden.
eventFilter

eventFilter is the application-defined event filter function which, in conjunction with
ModalDialog, handles events in all alert and dialog boxes except the modeless dialog box. 
In this program, a universal procedure pointer to eventFilter is passed as the first
parameter in the StopAlert and ModalDialog calls.

If the event is an update event, and if it is not for the dialog box or alert box in
question, the application's document window updating function is called, and false is
returned.  This response to an update event in the application's own document windows
also allows ModalDialog to perform a minor switch when necessary so that background
applications can update their windows as well.

If the event is not an update event, the current graphics port is saved and then set to
that of the alert or dialog box.  The event is then passed to the standard event filter
function for handling. If the standard event filter function handles the event, it will
return true and, in the itemHit parameter, the number of the item that it handled. 
ModalDialog (and StopAlert, which calls Modal Dialog internally) will then return this
item number.  A call to SetPort then restores the previously save graphics port.

Note that the calls to GetPort and SetPort are actually redundant when this event filter
function is used by all but the movable modal dialog box.  The calls are only necessary
when SetDialogTracksCursor has been called to cause the Dialog Manager to automatically
track the cursor, and the movable modal dialog box is the only modal alert or dialog box
which requires this tracking (because it contains an edit text field.)

doPopupMenuChoice, doPlaySound, doDrawMessage, doCopyPString, and doGetDepthAndDevice

doPopupMenuChoice, doPlaySound, doDrawMessage, doCopyPString, and doGetDepthAndDevice are
incidental to the demonstration.  All perform the same duties as the similarly-named
functions in the demonstration program Controls1, which is associated with Chapter 7 -
Introduction to Controls.  doDrawMessage is used in this program to prove the explicit
deactivation of the document window's content area when alert and dialog boxes other than
the modeless dialog box are invoked.
EDIT TEXT CONTROL BACKGROUND COLOUR PROBLEM
There was an apparent bug in the version of the edit text control CDEF 
included with Versions 1.0 through 1.0.3 of the Appearance Manager, but which is 
not evident in the version of the CDEF included with Mac OS 8.5.  This bug 
manifested itself in the edit text item in the modeless dialog of the demonstration
program as corruption of the text background colour whenever a cut, clear, or paste
was made via the Edit menu (though not via the Command-key equivalents).

If you are running this demonstration under a version of the Mac OS earlier than 
8.5, this bug will almost certainly be evident.  One workaround is to force a 
re-draw of the edit text item in the modeless dialog immediately after DialogCut, 
DialogClear, and DialogDelete are called.  Proceed as follows:

Add this function prototype:

  void  doFixEditTextBackground(void);

Add this function:

  // ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFixEditTextBackground

  void  doFixEditTextBackground(void)
  {
    ControlHandle controlHdl;

    GetDialogItemAsControl(gSearchModelessDialogPtr,iEditText,&controlHdl);
    DeactivateControl(controlHdl);
    ActivateControl(controlHdl);
  }

In the doEditMenu function, add a call to doFixEditTextBackground immediately after
the calls to DialogCut, DialogClear, and DialogDelete.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for up to $150 off Apple’s new MSRP, starting at only $849. Free 1-2 day delivery is available to most US... Read more
M2 Mac minis on sale for $100-$200 off MSRP,...
B&H Photo has Apple’s M2-powered Mac minis back in stock and on sale today for $100-$200 off MSRP. Free 1-2 day shipping is available for most US addresses: – Mac mini M2/256GB SSD: $499, save $... Read more
Mac Studios with M2 Max and M2 Ultra CPUs on...
B&H Photo has standard-configuration Mac Studios with Apple’s M2 Max & Ultra CPUs in stock today and on Easter sale for $200 off MSRP. Their prices are the lowest available for these models... Read more
Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply 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
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
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
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.