TweetFollow Us on Twitter

MACINTOSH C CARBON

Demonstration Program DialogsAndAlerts

Goto Contents

// *******************************************************************************************
// DialogsAndAlerts.h                                                      CLASSIC EVENT MODEL
// *******************************************************************************************
// 
// This program initially opens a small modal dialog which is automatically closed after 10
// seconds, the timeout value having been set by a call to SetDialogTimeout.  The program
// then:
//
// o  Opens a window for the purposes of displaying  advisory text and proving correct window
//    updating and activation/deactivation in the  presence of alerts and dialogs.
//
// o  Allows the user to invoke, via the Demonstration menu, modal and movable modal alerts
//    and dialogs, a modeless dialog and, on Mac OS X, a window-modal alert and dialog
//    (i.e., sheets).  
//
// The modal alert box is created programmatically using the StandardAlert function.
//
// The movable modal alert is created programmatically using the StandardAlert function on Mac
// OS 9 and the CreateStandardAlert function on Mac OS X.
//
// The modal dialog contains three checkboxes in one group box, and two pop-up menu buttons in
// another group box.
//
// The movable modal dialog contains four radio buttons in one group box, and a clock control
// and edit text item in another group box.
//
// The modeless dialog contains, amongst other items, an edit text item.
//
// The modal and movable modal alerts and dialogs use an application-defined event filter
// (callback) function.
//
// The program utilises the following resources:
//
// o  A 'plst' resource.
//
// o  An 'MBAR' resource, and 'MENU' resources for Apple, File, and Demonstration pull-down
//    menus, and the pop-up menu buttons (preload, non-purgeable).
//
// o  A 'WIND' resource (purgeable) (initially visible).
//
// o  '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).
//
// o  'CNTL' resources for primary group boxes, separator lines, pop-up menu buttons, a clock,
//    and an image well (all purgeable).
//
// o  'STR#' resources (purgeable) containing the message and informative text for the alerts.
//
// o  A 'cicn' resource (purgeable) for the modeless dialog box.
//
// o  A 'ppat' resource (purgeable), which is used to colour the content region of the
//    document window for update proving purposes.
//
// o  'hdlg' resources (purgeable) containing balloon help information for the modal and
//    movable modal dialog.
//
// o  An 'hrct' resource and associated 'hwin' resource (both purgeable) containing balloon
//    help information for the modeless dialog.
//
// o  A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
//    doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// *******************************************************************************************

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

#include <Carbon.h>

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

#define rMenubar                 128
#define mAppleApplication        128
#define  iAbout                  1
#define mFile                    129
#define  iClose                  4
#define  iQuit                   12
#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  iWindowModalAlert       7
#define  iWindowModalDialog      8
#define mFont                    132
#define rWindow                  128
#define rSplash                  128
#define rModalDialog             129
#define  iGridSnap               4
#define  iShowGrid               5
#define  iShowRulers             6
#define  iFont                   11
#define  iSound                  12
#define rMovableModalDialog      130
#define  iCharcoal               7
#define  iOilPaint               8
#define  iPencil                 9
#define  iChalk                  10
#define  iClockOne               12
#define rModelessDialog          131
#define  iEditTextSearchModeless 2
#define rSheetDialog             132
#define  iEditTextSheetDialog    2
#define rAlertStrings            128
#define  sModalMessage           1
#define  sModalInformative       2
#define  sMovableMessage         3
#define  sMovableInformative     4
#define rSheetStrings            132
#define  sAlertSheetMessage      1
#define  sAlertSheetInformative  2
#define rPixelPattern            128
#define kSearchModeless          1
#define kSheetDialog             2

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

#define MAX_UINT32               0xFFFFFFFF

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

void    main                           (void);
void    doPreliminaries                (void);
OSErr   quitAppEventHandler            (AppleEvent *,AppleEvent *,SInt32);
void    eventLoop                      (void);
void    doIdle                         (void);
void    doEvents                       (EventRecord *);
void    doMouseDown                    (EventRecord *);
void    doKeyDown                      (EventRecord *);
void    doUpdate                       (EventRecord *);
void    doUpdateDocument               (WindowRef);
void    doActivate                     (EventRecord *);
void    doActivateDocument             (WindowRef,Boolean);
void    doActivateDialogs              (EventRecord *,Boolean);
void    doOSEvent                      (EventRecord *);
void    doAdjustMenus                  (void);
void    doMenuChoice                   (SInt32);
void    doEditMenu                     (MenuItemIndex);
void    doDemonstrationMenu            (MenuItemIndex);
void    doExplicitlyDeactivateDocument (void);
Boolean doModalAlerts                  (Boolean);
Boolean doMovableModalAlertOnX         (void);
Boolean doModalDialog                  (void);
Boolean doMovableModalDialog           (void);
Boolean doCreateOrShowModelessDialog   (void);
void    doInContent                    (EventRecord *);
void    doButtonHitInSearchModeless    (void);
void    doHideModelessDialog           (WindowRef);
Boolean eventFilter                    (DialogRef,EventRecord *,SInt16 *);
void    doPopupMenuChoice              (ControlRef,SInt16);
void    doDrawMessage                  (WindowRef,Boolean);
void    doCopyPString                  (Str255,Str255);

Boolean doSheetAlert                   (void);
Boolean doSheetDialog                  (void);
void    doButtonHitInSheetDialog       (void);

void    helpTagsModal                  (DialogRef);
void    helpTagsMovableModal           (DialogRef);
void    helpTagsModeless               (DialogRef);

// *******************************************************************************************
// DialogsAndAlerts.c
// *******************************************************************************************

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

#include "DialogsAndAlerts.h"

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

Boolean        gRunningOnX        = false;
ModalFilterUPP gEventFilterUPP;
Str255         gCurrentString;
WindowRef      gWindowRef;
SInt32         gSleepTime;
Boolean        gDone;
Boolean        gGridSnap          = kControlCheckBoxUncheckedValue;
Boolean        gShowGrid          = kControlCheckBoxUncheckedValue;
Boolean        gShowRule          = kControlCheckBoxUncheckedValue;  
SInt16         gBrushType         = iCharcoal;
DialogRef      gModelessDialogRef = NULL;

// ************************************************************************************** main

void  main(void)
{
  MenuBarHandle menubarHdl;
  SInt32        response;
  MenuRef       menuRef;
  DialogRef     dialogRef;
  SInt16        itemHit;

  // ........................................................................ do preliminaries
  
  doPreliminaries();

  // ............................................................... set up menu bar and menus

  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  Gestalt(gestaltMenuMgrAttr,&response);
  if(response & gestaltMenuMgrAquaLayoutMask)
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
    {
      DeleteMenuItem(menuRef,iQuit);
      DeleteMenuItem(menuRef,iQuit - 1);
      DisableMenuItem(menuRef,0);
    }
    
    gRunningOnX = true;
  }

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

  dialogRef = GetNewDialog(rSplash,NULL,(WindowRef) -1);
  SetDialogTimeout(dialogRef,kStdOkItemIndex,10);

  do
  {
    ModalDialog(NULL,&itemHit);  
  } while(itemHit != kStdOkItemIndex);
  
  DisposeDialog(dialogRef);

  // ............................ create universal procedure pointer for event filter function

  gEventFilterUPP = NewModalFilterUPP((ModalFilterProcPtr) eventFilter);

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

  doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",gCurrentString);

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

  if(!(gWindowRef = GetNewCWindow(rWindow,NULL,(WindowRef)-1)))
    ExitToShell();

  SetPortWindowPort(gWindowRef);
  if(!gRunningOnX)
    TextSize(10);

  // ......................................................................... enter eventLoop

  eventLoop();
}

// *************************************************************************** doPreliminaries

void  doPreliminaries(void)
{
  OSErr osError;
  
  MoreMasterPointers(192);
  InitCursor();
  FlushEvents(everyEvent,0);

  osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
                            NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler),
                            0L,false);
  if(osError != noErr)
    ExitToShell();
}

// **************************************************************************** doQuitAppEvent

OSErr  quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
  OSErr    osError;
  DescType returnedType;
  Size     actualSize;

  osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,NULL,0,
                              &actualSize);

  if(osError == errAEDescNotFound)
  {
    gDone = true;
    osError = noErr;
  } 
  else if(osError == noErr)
    osError = errAEParamMissed;

  return osError;
}

// ********************************************************************************* eventLoop

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

  gSleepTime = MAX_UINT32;
  gDone = false;

  while(!gDone)
  {
    gotEvent = WaitNextEvent(everyEvent,&eventStructure,gSleepTime,NULL);
    if(gotEvent)
      doEvents(&eventStructure);
    else
    {
      if(eventStructure.what == nullEvent)
        if(!gRunningOnX)
          doIdle();
    }
  }
}

// ************************************************************************************ doIdle

void  doIdle(void)
{
  if(FrontWindow() == GetDialogWindow(gModelessDialogRef))
    IdleControls(GetDialogWindow(gModelessDialogRef));
}

// ********************************************************************************** doEvents

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

    case keyDown:
      doKeyDown(eventStrucPtr);
      break;

    case autoKey:
      if((eventStrucPtr->modifiers & cmdKey) == 0)
        doKeyDown(eventStrucPtr);
      break;

    case updateEvt:
      doUpdate(eventStrucPtr);
      break;

    case activateEvt:
      doActivate(eventStrucPtr);
      break;

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

// ******************************************************************************* doMouseDown

void  doMouseDown(EventRecord *eventStrucPtr)
{
  WindowRef      windowRef;
  WindowPartCode partCode;

  partCode = FindWindow(eventStrucPtr->where,&windowRef);

  switch(partCode)
  {
    case inMenuBar:
      doAdjustMenus();
      doMenuChoice(MenuSelect(eventStrucPtr->where));
      break;

    case inContent:
      if(windowRef != FrontWindow())
        SelectWindow(windowRef);
      else
        doInContent(eventStrucPtr);
      break;

    case inDrag:
      DragWindow(windowRef,eventStrucPtr->where,NULL);
      break;

    case inGoAway:
      if(TrackGoAway(windowRef,eventStrucPtr->where))
      {
        if(GetWindowKind(windowRef) == kDialogWindowKind)
        {
          doHideModelessDialog(windowRef);
          doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",
                        gCurrentString);
        }
      }
      break;
  }
}

// ********************************************************************************* doKeyDown

void  doKeyDown(EventRecord *eventStrucPtr)
{
  WindowRef  windowRef;
  SInt8      charCode;
  SInt32     windowRefCon;
  SInt16     itemHit;
  ControlRef controlRef;
  UInt32     finalTicks;
  DialogRef  dialogRef;
  
  windowRef = FrontWindow();
  charCode = eventStrucPtr->message & charCodeMask;

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    if((eventStrucPtr->modifiers & cmdKey) != 0)
    {
      doAdjustMenus();
      doMenuChoice(MenuEvent(eventStrucPtr));
    }
  }
  else
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
    {
      if((charCode == kReturn) || (charCode == kEnter))
      {
        GetDialogItemAsControl(GetDialogFromWindow(windowRef),kStdOkItemIndex,&controlRef);
        HiliteControl(controlRef,kControlButtonPart);
        Delay(8,&finalTicks);
        HiliteControl(controlRef,kControlEntireControl);
        if(windowRefCon == kSearchModeless)
          doButtonHitInSearchModeless();
        else if(windowRefCon == kSheetDialog)
          doButtonHitInSheetDialog();
        return;
      }

      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        if(charCode == 'X' || charCode == 'x' ||  charCode == 'C' || charCode == 'c' ||
            charCode == 'V' || charCode == 'v')
        {
          HiliteMenu(mEdit);
          DialogSelect(eventStrucPtr,&dialogRef,&itemHit);
          Delay(4,&finalTicks);
          HiliteMenu(0);
        }
        else
        {
          doAdjustMenus();
          doMenuChoice(MenuEvent(eventStrucPtr));
        }

        return;
      }

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

// ********************************************************************************** doUpdate

void  doUpdate(EventRecord *eventStrucPtr)
{
  WindowRef windowRef;
  DialogRef dialogRef;
  SInt16    itemHit;

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    windowRef = (WindowRef) eventStrucPtr->message;
    doUpdateDocument(windowRef);
  }
  else
    DialogSelect(eventStrucPtr,&dialogRef,&itemHit);
}

// ************************************************************************** doUpdateDocument

void  doUpdateDocument(WindowRef windowRef)
{
  GrafPtr      oldPort;
  PixPatHandle pixpatHdl;
  Rect         portRect;

  BeginUpdate(windowRef);

  GetPort(&oldPort);
  SetPortWindowPort(windowRef);

  pixpatHdl = GetPixPat(rPixelPattern);
  GetWindowPortBounds(windowRef,&portRect);
  FillCRect(&portRect,pixpatHdl);
  DisposePixPat(pixpatHdl);
  doDrawMessage(windowRef,windowRef == FrontWindow());

  SetPort(oldPort);

  EndUpdate(windowRef);
}

// ******************************************************************************** doActivate

void  doActivate(EventRecord *eventStrucPtr)
{
  Boolean   becomingActive;
  WindowRef windowRef;

  becomingActive = (eventStrucPtr->modifiers & activeFlag) == activeFlag;

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    windowRef = (WindowRef) eventStrucPtr->message;
    doActivateDocument(windowRef,becomingActive);
  }
  else
    doActivateDialogs(eventStrucPtr,becomingActive);
}

// ************************************************************************ doActivateDocument

void  doActivateDocument(WindowRef windowRef,Boolean becomingActive)
{
  if(becomingActive)
    doAdjustMenus();

  doDrawMessage(windowRef,becomingActive);
}

// ****************************************************************** doActivateModelessDialog

void  doActivateDialogs(EventRecord *eventStrucPtr,Boolean becomingActive)
{
  DialogRef dialogRef;
  SInt16    windowRefCon;
  SInt16    itemHit;  

  DialogSelect(eventStrucPtr,&dialogRef,&itemHit);

  windowRefCon = GetWRefCon(GetDialogWindow(dialogRef));

  if(becomingActive)
  {
    doAdjustMenus();
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
      gSleepTime = GetCaretTime();
  }
  else
  {
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
      gSleepTime = MAX_UINT32;
  }
}

// ********************************************************************************* doOSEvent

void  doOSEvent(EventRecord *eventStrucPtr)
{
  switch((eventStrucPtr->message >> 24) & 0x000000FF)
  {
    case suspendResumeMessage:
      if((eventStrucPtr->message & resumeFlag) == 1)
        SetThemeCursor(kThemeArrowCursor);
      break;
  }
}

// ***************************************************************************** doAdjustMenus

void  doAdjustMenus(void)
{
  WindowRef windowRef;
  MenuRef   menuRef;
  SInt32    windowRefCon;

  windowRef = FrontWindow();

  if(GetWindowKind(windowRef) == kApplicationWindowKind)
  {
    menuRef = GetMenuRef(mFile);
    DisableMenuItem(menuRef,iClose);
    menuRef = GetMenuRef(mEdit);
    DisableMenuItem(menuRef,0);
    menuRef = GetMenuRef(mDemonstration);
    EnableMenuItem(menuRef,iModeless);
    if(gRunningOnX)
    {
      if(IsWindowCollapsed(gWindowRef))
      {
        DisableMenuItem(menuRef,iWindowModalDialog);
        DisableMenuItem(menuRef,iWindowModalAlert);
      }
      else
      {
        EnableMenuItem(menuRef,iWindowModalDialog);
        EnableMenuItem(menuRef,iWindowModalAlert);
      }
    }
  }
  else if(GetWindowKind(windowRef) == kDialogWindowKind)
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless)
    {
      menuRef = GetMenuRef(mFile);
      EnableMenuItem(menuRef,iClose);
      menuRef = GetMenuRef(mEdit);
      EnableMenuItem(menuRef,0);    
      menuRef = GetMenuRef(mDemonstration);
      DisableMenuItem(menuRef,iModeless);
    }
    else if(windowRefCon == kSheetDialog)
    {
      menuRef = GetMenuRef(mFile);
      DisableMenuItem(menuRef,iClose);
      menuRef = GetMenuRef(mEdit);
      EnableMenuItem(menuRef,0);    
      menuRef = GetMenuRef(mDemonstration);
      EnableMenuItem(menuRef,iModeless);
      DisableMenuItem(menuRef,iWindowModalAlert);
    }
    else
    {
      menuRef = GetMenuRef(mFile);
      DisableMenuItem(menuRef,iClose);
      menuRef = GetMenuRef(mEdit);
      DisableMenuItem(menuRef,0);    
      menuRef = GetMenuRef(mDemonstration);
      EnableMenuItem(menuRef,iModeless);
    }
  }

  DrawMenuBar();
}

// ****************************************************************************** doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  MenuID        menuID;
  MenuItemIndex menuItem;
  SInt16        windowRefCon;

  menuID = HiWord(menuChoice);
  menuItem = LoWord(menuChoice);

  if(menuID == 0)
    return;

  switch(menuID)
  {
    case mAppleApplication:
      if(menuItem == iAbout)
        SysBeep(10);
      break;

    case mFile:
      if(menuItem == iQuit)
        gDone = true;
      else if(menuItem == iClose)
      {
        if(GetWindowKind(FrontWindow()) == kDialogWindowKind)
        {
          windowRefCon = GetWRefCon(FrontWindow());
          if(windowRefCon == kSearchModeless)
            doHideModelessDialog(GetDialogWindow(gModelessDialogRef));
        }
      }
      break;

    case mEdit:
      doEditMenu(menuItem);
      break;

    case mDemonstration:
      doDemonstrationMenu(menuItem);
      break;
  }

  HiliteMenu(0);
}

// ******************************************************************************** doEditMenu

void  doEditMenu(MenuItemIndex menuItem)
{
  WindowRef windowRef;
  SInt16    windowRefCon;
  DialogRef dialogRef;

  windowRef = FrontWindow();

  if(GetWindowKind(FrontWindow()) == kDialogWindowKind)
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
    {
      dialogRef = GetDialogFromWindow(windowRef);

      switch(menuItem)
      {
        case iCut:
          DialogCut(dialogRef);
          break;

        case iCopy:
          DialogCopy(dialogRef);
          break;

        case iPaste:
          DialogPaste(dialogRef);
          break;

        case iClear:
          DialogDelete(dialogRef);
          break;
      }
    }
  }
}

// *********************************************************************** doDemonstrationMenu

void  doDemonstrationMenu(MenuItemIndex menuItem)
{
  switch(menuItem)
  {
    case iModalAlert:
      if(!doModalAlerts(false))
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iMovableAlert:
      if(gRunningOnX)
      {
        if(!doMovableModalAlertOnX())
        {
          SysBeep(10);
          ExitToShell();
        }
      }
      else if(!doModalAlerts(true))
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

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

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

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

    case iWindowModalAlert:
      if(!doSheetAlert())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iWindowModalDialog:
      if(!doSheetDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;
  }
}

// ************************************************************ doExplicitlyDeactivateDocument

void  doExplicitlyDeactivateDocument(void)
{
  if(FrontWindow() && (GetWindowKind(FrontWindow()) != kDialogWindowKind))
    doActivateDocument(FrontWindow(),false);
}

// ***************************************************************************** doModalAlerts

Boolean  doModalAlerts(Boolean movable)
{
  AlertStdAlertParamRec paramRec;
  Str255                messageText, informativeText;
  Str255                otherText = "\pOther";
  OSErr                 osError;
  DialogItemIndex       itemHit;

  doExplicitlyDeactivateDocument();

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

  if(!movable)
    GetIndString(messageText,rAlertStrings,sModalMessage);
  else
    GetIndString(messageText,rAlertStrings,sMovableMessage);
  GetIndString(informativeText,rAlertStrings,sModalInformative);

  osError = StandardAlert(kAlertStopAlert,messageText,informativeText,¶mRec,&itemHit);
  if(osError == noErr)
  {
    if(itemHit == kAlertStdAlertOKButton)
      doCopyPString("\pOK Button hit",gCurrentString);
    else if (itemHit == kAlertStdAlertCancelButton)
      doCopyPString("\pCancel Button hit",gCurrentString);
    else if (itemHit == kAlertStdAlertOtherButton)
      doCopyPString("\pOther Button hit",gCurrentString);
    else if (itemHit == kAlertStdAlertHelpButton)
      doCopyPString("\pHelp Button hit",gCurrentString);
  }

  return (osError == noErr);
}

// ******************************************************************** doMovableModalAlertOnX

Boolean  doMovableModalAlertOnX(void)
{
  AlertStdCFStringAlertParamRec paramRec;
  Str255                        messageText, informativeText;
  CFStringRef                   messageTextCF, informativeTextCF;
  OSErr                         osError;
  DialogRef                     dialogRef;
  DialogItemIndex               itemHit;

  doExplicitlyDeactivateDocument();

  GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne);
  paramRec.movable      = true;
  paramRec.helpButton   = true;
  paramRec.cancelButton = kAlertStdAlertCancelButton;
  paramRec.cancelText   = CFSTR("Cancel");
  paramRec.otherText    = CFSTR("Other");

  GetIndString(messageText,rAlertStrings,sMovableMessage);
  GetIndString(informativeText,rAlertStrings,sMovableInformative);
  messageTextCF = CFStringCreateWithPascalString(NULL,messageText,
                                                 CFStringGetSystemEncoding());
  informativeTextCF = CFStringCreateWithPascalString(NULL,informativeText,
                                                     CFStringGetSystemEncoding());

  osError = CreateStandardAlert(kAlertCautionAlert,messageTextCF,informativeTextCF,¶mRec,
                                &dialogRef);
  if(osError == noErr)
  {
    osError = RunStandardAlert(dialogRef,NULL,&itemHit);
    if(osError == noErr)
    {
      if(itemHit == kAlertStdAlertOKButton)
        doCopyPString("\pOK Button hit",gCurrentString);
      else if (itemHit == kAlertStdAlertCancelButton)
        doCopyPString("\pCancel Button hit",gCurrentString);
      else if (itemHit == kAlertStdAlertOtherButton)
        doCopyPString("\pOther Button hit",gCurrentString);
      else if (itemHit == kAlertStdAlertHelpButton)
        doCopyPString("\pHelp Button hit",gCurrentString);
    }
  }

  if(messageTextCF != NULL)
    CFRelease(messageTextCF);
  if(informativeTextCF != NULL)
    CFRelease(informativeTextCF);

  return (osError == noErr);
}

// ***************************************************************************** doModalDialog

Boolean  doModalDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  OSStatus   osError;
  MenuRef    menuRef;
  SInt16     numberOfItems, itemHit, controlValue;

  doExplicitlyDeactivateDocument();

  if(!(dialogRef = GetNewDialog(rModalDialog,NULL,(WindowRef) -1)))
    return false;
 
  SetDialogDefaultItem(dialogRef,kStdOkItemIndex);
  SetDialogCancelItem(dialogRef,kStdCancelItemIndex);

  GetDialogItemAsControl(dialogRef,iGridSnap,&controlRef);
  SetControlValue(controlRef,gGridSnap);
  GetDialogItemAsControl(dialogRef,iShowGrid,&controlRef);
  SetControlValue(controlRef,gShowGrid);
  GetDialogItemAsControl(dialogRef,iShowRulers,&controlRef);
  SetControlValue(controlRef,gShowRule);

  menuRef = NewMenu(mFont,NULL);

  if((osError = CreateStandardFontMenu(menuRef,0,0,0,NULL)) == noErr)
  {
    GetDialogItemAsControl(dialogRef,iFont,&controlRef);
    SetControlMinimum(controlRef,1);
    numberOfItems = CountMenuItems(menuRef);
    SetControlMaximum(controlRef,numberOfItems);
    SetControlData(controlRef,kControlEntireControl,kControlPopupButtonMenuRefTag,
                   sizeof(menuRef),&menuRef);
  }
  else
    return false;

  if(gRunningOnX)
    helpTagsModal(dialogRef);

  ShowWindow(GetDialogWindow(dialogRef));

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

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

  DisposeDialog(dialogRef);

  doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",gCurrentString);

  return true;
}

// ********************************************************************** doMovableModalDialog

Boolean  doMovableModalDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  SInt16     oldBrushType, itemHit, a;

  doExplicitlyDeactivateDocument();

  if(!(dialogRef = GetNewDialog(rMovableModalDialog,NULL,(WindowRef) -1)))
    return false;

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

  GetDialogItemAsControl(dialogRef,gBrushType,&controlRef);
  SetControlValue(controlRef,kControlRadioButtonCheckedValue);
  
  GetDialogItemAsControl(dialogRef,iClockOne,&controlRef);
  SetKeyboardFocus(GetDialogWindow(dialogRef),controlRef,kControlClockPart);

  oldBrushType = gBrushType;

  if(gRunningOnX)
    helpTagsMovableModal(dialogRef);

  ShowWindow(GetDialogWindow(dialogRef));

  do
  {
    ModalDialog(gEventFilterUPP,&itemHit);

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

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

  if(itemHit == kStdCancelItemIndex)
    gBrushType = oldBrushType;

  DisposeDialog(dialogRef);

  return true;
}

// ************************************************************** doCreateOrShowModelessDialog

Boolean  doCreateOrShowModelessDialog(void)
{
  ControlRef controlRef;
  Str255     stringData = "\pwicked googly";
  MenuRef    menuRef;

  if(gModelessDialogRef == NULL)
  {
    if(!(gModelessDialogRef = GetNewDialog(rModelessDialog,NULL,(WindowRef) -1)))
      return false;

    SetWRefCon(GetDialogWindow(gModelessDialogRef),(SInt32) kSearchModeless);
    
    SetDialogDefaultItem(gModelessDialogRef,kStdOkItemIndex);

    GetDialogItemAsControl(gModelessDialogRef,iEditTextSearchModeless,&controlRef);
    SetDialogItemText((Handle) controlRef,stringData);
    SelectDialogItemText(gModelessDialogRef,iEditTextSearchModeless,0,32767);

    if(gRunningOnX)
      helpTagsModeless(gModelessDialogRef);

    ShowWindow(GetDialogWindow(gModelessDialogRef));
  }
  else
  {
    ShowWindow(GetDialogWindow(gModelessDialogRef));
    SelectWindow(GetDialogWindow(gModelessDialogRef));
  }

  if(gRunningOnX)
  {
    menuRef = GetMenuRef(mFile);
    EnableMenuItem(menuRef,0);
  }

  return true;
}

// ******************************************************************************* doInContent

void  doInContent(EventRecord *eventStrucPtr)
{
  WindowRef windowRef;
  SInt32    windowRefCon;
  DialogRef dialogRef;
  SInt16    itemHit;

  windowRef = FrontWindow();

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    // Handle clicks in document window content region here.
  }
  else
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless)
    {
      if(DialogSelect(eventStrucPtr,&dialogRef,&itemHit))
        if(itemHit == kStdOkItemIndex)
          doButtonHitInSearchModeless();
    }
    else if(windowRefCon == kSheetDialog)
    {
      if(DialogSelect(eventStrucPtr,&dialogRef,&itemHit))
        if(itemHit == kStdOkItemIndex)
          doButtonHitInSheetDialog();
    }
  }
}

// *************************************************************** doButtonHitInSearchModeless

void  doButtonHitInSearchModeless(void)
{
  ControlRef controlRef;
  GrafPtr    oldPort;

  GetDialogItemAsControl(gModelessDialogRef,iEditTextSearchModeless,&controlRef);
  GetDialogItemText((Handle) controlRef,gCurrentString);

  GetPort(&oldPort);
  SetPortWindowPort(gWindowRef);
  doDrawMessage(gWindowRef,false);
  SetPort(oldPort);
}

// ********************************************************************** doHideModelessDialog

void  doHideModelessDialog(WindowRef windowRef)
{
  SInt16  windowRefCon;
  MenuRef menuRef;

  if(gRunningOnX)
    BringToFront(gWindowRef);

  HideWindow(windowRef);

  windowRefCon = GetWRefCon(windowRef);
  if(windowRefCon == kSearchModeless)
    gSleepTime = MAX_UINT32;

  if(gRunningOnX)
  {
    menuRef = GetMenuRef(mFile);
    DisableMenuItem(menuRef,0);
  }
}

// ******************************************************************************* eventFilter

Boolean  eventFilter(DialogRef dialogRef,EventRecord *eventStrucPtr,SInt16 *itemHit)
{
  Boolean handledEvent;
  GrafPtr oldPort;

  handledEvent = false;
  
  if((eventStrucPtr->what == updateEvt) && 
     ((WindowRef) eventStrucPtr->message != GetDialogWindow(dialogRef)))
  {
    if(!gRunningOnX)
      doUpdate(eventStrucPtr);
  }
  else if((eventStrucPtr->what == autoKey) && ((eventStrucPtr->modifiers & cmdKey) != 0))
  {
    handledEvent = true;
    return handledEvent;
  }
  else
  {
    GetPort(&oldPort);
    SetPortDialogPort(dialogRef);

    handledEvent = StdFilterProc(dialogRef,eventStrucPtr,itemHit);

    SetPort(oldPort);
  }

  return handledEvent;
}

// ************************************************************************* doPopupMenuChoice

void  doPopupMenuChoice(ControlRef controlRef,SInt16 controlValue)
{
  MenuRef menuRef;
  Size    actualSize;
  Str255  itemName;
  GrafPtr oldPort;

  GetControlData(controlRef,kControlEntireControl,kControlPopupButtonMenuHandleTag,
                 sizeof(menuRef),&menuRef,&actualSize);
  GetMenuItemText(menuRef,controlValue,itemName);    
  doCopyPString(itemName,gCurrentString);

  GetPort(&oldPort);
  SetPortWindowPort(gWindowRef);
  doDrawMessage(gWindowRef,false);
  SetPort(oldPort);
}

// ***************************************************************************** doDrawMessage

void  doDrawMessage(WindowRef windowRef,Boolean inState)
{
  Rect        portRect, headerRect;
  CFStringRef stringRef;
  Rect        textBoxRect;

  if(windowRef == gWindowRef)
  {
    SetPortWindowPort(windowRef);
    GetWindowPortBounds(windowRef,&portRect);
    SetRect(&headerRect,portRect.left - 1,portRect.bottom - 26,portRect.right + 1,
            portRect.bottom + 1);
    DrawThemePlacard(&headerRect,inState);

    if(inState == kThemeStateActive)
      TextMode(srcOr);
    else
      TextMode(grayishTextOr);

    stringRef = CFStringCreateWithPascalString(NULL,gCurrentString,
                                               CFStringGetSystemEncoding());
    SetRect(&textBoxRect,portRect.left,portRect.bottom - 19,portRect.right,
              portRect.bottom - 4);
    DrawThemeTextBox(stringRef,kThemeSmallSystemFont,0,true,&textBoxRect,teJustCenter,NULL);
    if(stringRef != NULL)    
      CFRelease(stringRef);

    TextMode(srcOr);
  }
}

// ***************************************************************************** doCopyPString

void  doCopyPString(Str255 sourceString,Str255 destinationString)
{
  SInt16 stringLength;

  stringLength = sourceString[0];
  BlockMove(sourceString + 1,destinationString + 1,stringLength);
  destinationString[0] = stringLength;
}

// *******************************************************************************************
// Sheets.c
// *******************************************************************************************

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

#include "DialogsAndAlerts.h"

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

WindowRef gSheetDialogWindowRef = NULL;

extern WindowRef gWindowRef;
extern Boolean   gRunningOnX;
extern Str255    gCurrentString;

// ****************************************************************************** doSheetAlert

Boolean  doSheetAlert(void)
{
  AlertStdCFStringAlertParamRec paramRec;
  Str255                        messageText, informativeText;
  CFStringRef                   messageTextCF, informativeTextCF;
  OSStatus                      osError;
  DialogRef                     dialogRef;
  MenuRef                       menuRef;

  GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne);

  GetIndString(messageText,rSheetStrings,sAlertSheetMessage);
  GetIndString(informativeText,rSheetStrings,sAlertSheetInformative);
  messageTextCF = CFStringCreateWithPascalString(NULL,messageText,
                                                 CFStringGetSystemEncoding());
  informativeTextCF = CFStringCreateWithPascalString(NULL,informativeText,
                                                     CFStringGetSystemEncoding());

  osError = CreateStandardSheet(kAlertCautionAlert,messageTextCF,informativeTextCF,¶mRec,
                                GetWindowEventTarget(gWindowRef),&dialogRef);
  if(osError == noErr)
    osError = ShowSheetWindow(GetDialogWindow(dialogRef),gWindowRef);

  CFRelease(messageTextCF);
  CFRelease(informativeTextCF);

  menuRef = GetMenuRef(mDemonstration);
  if(menuRef != NULL)
  {
    DisableMenuItem(menuRef,iWindowModalDialog);
    DisableMenuItem(menuRef,iWindowModalAlert);
  }

  return (osError == noErr);
}

// ***************************************************************************** doSheetDialog

Boolean  doSheetDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  Str255     stringData = "\pBradman";
  OSStatus   osError = noErr;
  MenuRef    menuRef;
 
  if(!(dialogRef = GetNewDialog(rSheetDialog,NULL,(WindowRef) -1)))
    return false;

  SetWRefCon(GetDialogWindow(dialogRef),(SInt32) kSheetDialog);
    
  SetDialogDefaultItem(dialogRef,kStdOkItemIndex);

  GetDialogItemAsControl(dialogRef,iEditTextSheetDialog,&controlRef);
  SetDialogItemText((Handle) controlRef,stringData);
  SelectDialogItemText(dialogRef,iEditTextSheetDialog,0,32767);

  gSheetDialogWindowRef = GetDialogWindow(dialogRef);
  osError = ShowSheetWindow(gSheetDialogWindowRef,gWindowRef);

  menuRef = GetMenuRef(mDemonstration);
  if(menuRef != NULL)
    DisableMenuItem(menuRef,iWindowModalDialog);

  return (osError == noErr);
}

// ****************************************************************** doButtonHitInSheetDialog

void  doButtonHitInSheetDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  GrafPtr    oldPort;

  dialogRef = GetDialogFromWindow(gSheetDialogWindowRef);

  GetDialogItemAsControl(dialogRef,iEditTextSheetDialog,&controlRef);
  GetDialogItemText((Handle) controlRef,gCurrentString);

  HideSheetWindow(gSheetDialogWindowRef);
  DisposeDialog(dialogRef);
  gSheetDialogWindowRef = NULL;

  GetPort(&oldPort);
  SetPortWindowPort(gWindowRef);
  doDrawMessage(gWindowRef,true);
  SetPort(oldPort);
}

// *******************************************************************************************
// HelpTags.c
// *******************************************************************************************

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

#include "DialogsAndAlerts.h"
#include <string.h>

// ***************************************************************************** helpTagsModal

void  helpTagsModal(DialogRef dialogRef)
{
  HMHelpContentRec helpContent;
  SInt16           a;
  static SInt16    itemNumber[7] = { 1,2,3,7,8,10,11 };
  ControlRef       controlRef;

  memset(&helpContent,0,sizeof(helpContent));

  HMSetTagDelay(500);
  HMSetHelpTagsDisplayed(true);

  helpContent.version = kMacHelpVersion;
  helpContent.tagSide = kHMOutsideTopCenterAligned;
  helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 129;

  for(a = 1;a <= 7; a++)
  {
    helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
    GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef);
    HMSetControlHelpContent(controlRef,&helpContent);
  }
}

// ********************************************************************** helpTagsMovableModal

void  helpTagsMovableModal(DialogRef dialogRef)
{
  HMHelpContentRec helpContent;
  SInt16           a;
  static SInt16    itemNumber[9] = { 1,2,3,4,6,11,12,13,14 };
  ControlRef       controlRef;

  memset(&helpContent,0,sizeof(helpContent));

  HMSetTagDelay(500);
  HMSetHelpTagsDisplayed(true);

  helpContent.version = kMacHelpVersion;
  helpContent.tagSide = kHMOutsideTopCenterAligned;
  helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 130;

  for(a = 1;a <= 9; a++)
  {
    helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
    GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef);
    HMSetControlHelpContent(controlRef,&helpContent);
  }
}

// ************************************************************************** helpTagsModeless

void  helpTagsModeless(DialogRef dialogRef)
{
  HMHelpContentRec helpContent;
  SInt16           a;
  static SInt16    itemNumber[7] = { 1,2,3,4,5,6,7 };
  ControlRef       controlRef;

  memset(&helpContent,0,sizeof(helpContent));

  HMSetTagDelay(500);
  HMSetHelpTagsDisplayed(true);

  helpContent.version = kMacHelpVersion;
  helpContent.tagSide = kHMOutsideTopCenterAligned;
  helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 131;

  for(a = 1;a <= 7; a++)
  {
    helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
    GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef);
    HMSetControlHelpContent(controlRef,&helpContent);
  }
}

// *******************************************************************************************

Demonstration Program DialogsAndAlerts Comments

When this program is run, the user should:

o Invoke alerts and dialogs by choosing items in the Demonstration menu, noting window
  update/activation/deactivation and menu enabling/disabling effects.

o On Mac OS 8/9, choose Show Balloons from the Help menu and pass the cursor over the various
  items in the dialogs, noting the information in the help balloons.  Also note the updating of
  alerts and dialogs, and of the window, behind the help balloon when the balloon closes.

o On Mac OS X, pause the cursor over the various items in the dialogs, noting the information
  in the help tags.

o Note the effects on the menus when the various alerts and dialogs are the front window.

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

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

o The program can be sent to the background by clicking outside the alert or dialog and the
  document window, or by bringing another application to the foreground.

o The program can be brought to the foreground again by clicking inside the alert or dialog, or
  the document window.

o Note that, when the movable modal dialog and (on Mac OS X) the window-modal (sheet) dialog
  are displayed, the Edit menu and its Cut, Copy, and Paste items are enabled, given that the
  edit text items in these dialogs always have keyboard focus.

o Note that, when the modeless dialog is displayed:

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

    o Clicks outside it when it is the frontmost window.

    o Clicks inside it when it is not the frontmost window.

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

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

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

o Note that all alerts and dialogs respond correctly to Return and Enter key presses, and that
  the modal alert, modal dialog and movable modal dialog also respond correctly to escape key
  and Command-period presses.

o Note that, when an alert or dialog 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.

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

o In the movable modal dialog, click on the radio buttons to change their settings, noting that
  the new setting is remembered when the dialog is dismissed using the OK button, but not
  remembered when the dialog is dismissed using the Cancel button.  In the case of the clock
  control and edit text item, 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 item, 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 item.

o In the modeless dialog and (on Mac OS X) the window-modal (sheet) dialog, 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 item.  Also 
  note that, when the Search button is clicked (or the Return or Enter keys are pressed) the 
  text in the edit text item is displayed in the document window's window header.

o On Mac OS X, when a window-modal (sheet) alert or dialog is showing, minimise the window into
  the Dock and then expand the window from the dock. 

In the 'DITL' resources for the modal and movable modal dialogs, 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 'dlgx' resources, note that all feature flags are set except for the
kDialogFlagsHandlesMovableModal flag in 'dlgx' resources for the modal dialog and modeless
dialog.  Thus dialogs have a root control and embedding hierarchy.

Although, for demonstration purposes, this program creates modal alerts and dialogs, it is
emphasised that Aqua Human Interface Guidelines require that, on Mac OS X, applications use
modal alerts and dialogs only in exceptional purposes.  On Mac OS X, the vast majority of
alerts and dialogs should be application-modal or window-modal.

On Mac OS X, explanatory Help tags are available for the modal, movable modal, and modeless
dialogs.  The associated source code (in the source code file HelpTags.c) is not explained in
these comments because the provision of Help tags is incidental to the demonstration.  For
information on creating help tags, see Chapter 25.  Note that it is also possible to display
help tags on Mac OS 8/9; however, it is considered by the author that their "look" is somewhat
at odds with the Platinum appearance, and that help balloons remain the most appropriate option
for Mac OS 8/9.

The CodeWarrior project for this program adds the CarbonFrameWorksLib stub library because
certain functions are used that are only available on Mac OS X.  (See "Carbon and Available
APIs" at Chapter 25.)  Those functions (CreateStandardAlert, RunStandardAlert,
GetStandardAlertDefaultParams, CreateStandardSheet, ShowSheetWindow, HideSheetWindow) are only
called when the program is run on Mac OS X.

DialogsAndAlerts.h

defines

Constants are established for dialog resource IDs and for the item numbers of certain items in
the item lists associated with the dialogs.  rAlertStrings and rSheetStrings represent the
resource IDs of 'STR#' resources holding strings for the message and informative text (label
and narrative text in Mac OS 8/9 parlance) for the modal alert, movable modal alert, and
window-modal (sheet) alert.

The values represented by kSearchModeless and kSheetDialog will be stored as the reference
constant in the window object in, respectively, the modeless dialog and window-modal (sheet)
dialog objects.  This enables the program to distinguish between these two dialogs.

The penultimate block establishes constants representing the character codes for the Return,
Enter, escape, and period keys.

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

DialogsAndAlerts.c

Global Variables

gEventFilterUPP will be assigned a universal procedure pointer to an application-defined event
filter (callback) function.  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.)
 
The three variables after gDone will store the current control value of the checkboxes in the
modal dialog.  The next variable will store the item number of the currently selected radio
button in the movable modal dialog. 

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

main

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 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.  (Note that pressing the Return key before the 10 seconds has elapsed will also
dispose of the dialog.)

The call to NewModalFilterUPP creates a universal procedure pointer for the event filter
(callback) function.

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 variable that will be used as WaitNextEvent's sleep parameter (gSleepTime) is initially set
to the maximum unsigned long value.  Note that the value assigned to gSleepTime will be changed
at certain points in the program.

When a NULL event is returned by WaitNextEvent, if the program is running on Mac OS 8/9, doIdle
is called.

doIdle

doIdle is invoked, on Mac OS 8/9 only, whenever WaitNextEvent returns a null event.

If the front window is the modeless dialog, 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 control, and the call causes
the control definition function to call TextEdit to blink the insertion point caret.  (This
call is not necessary on Mac OS X because controls on Mac OS X have built-in timers.)

doEvents

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

Note that, at the autoKey case, the function doKeyDown is called only if the Command key is not
down.  This is to prevent the Command-key equivalents for cut, copy, and paste from repeating
when the user presses and holds down those Command-key equivalents while editing text in the
modeless dialog's edit text item.

In this program, autoKey events generated while the Command key is down are also discarded in
the event filter (callback) function eventFilter (see below).  This means that the behaviour of
the edit text item in the movable modal dialog will replicate that of the edit text item in the
modeless dialog.

(Many commercial and shareware programs (BBEdit excepted) do not discard autoKey events in
these circumstances.  The author considers that to be an oversight.)

doMouseDown

doMouseDown handles mouse-down events.  Mouse-downs in the content region and in the close
box/button are of significance to the demonstration.  If a mouse-down occurred in a close
box/button, if TrackGoAway returns true, and if the window is the modeless dialog,
doHideModelessDialog is called.  (In this demonstration, the modeless dialog, but not the
document window, has a close box/button.)

doKeyDown

doKeyDown handles all key-down and auto-key events.

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 the modeless dialog or
window-modal (sheet) dialog, or in the 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 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 the modeless dialog dialog or window-modal (sheet) dialog:

o If the key pressed was the Return or Enter key, GetDialogItemAsControl is called to get a
  reference to the single push button control in the modeless dialog (item 1 in the item 
  list). The push button is then highlighted for eight ticks (this has an effect on Mac OS 8/9
  only), and then unhighlighted before a function is called to extract the text from the edit
  text item and display it in the document window's window header.  doKeyDown then returns 
  because it is not intended that the edit text item receive Return and Enter key presses.

o If the Command key was down:

  o 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 item.  (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 dialogs with
    edit text items.)

  o If neither the X, C, nor V key was pressed, the 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.

  o doKeyDown returns so as to bypass the second call to DialogSelect.

  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.

o 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 item.

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, a
function for updating the document window is called.

If the event is for the modeless dialog or window-modal (sheet) dialog, DialogSelect is called
to handle the event.  DialogSelect calls BeginUpdate, DrawDialog, and EndUpdate to redraw the
dialog's content area.  To restrict the redraw to the update region, an alternative is to call
BeginUpdate, UpdateDialog, and EndUpdate.  (Recall here that update regions BeginUpdate and
EndUpdate are irrelevant on Mac OS X.)

Note that, on Mac OS X, the call to DialogSelect is really only necessary in the case of the
window-modal (sheet) dialog.

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 a
function which draws a window header frame and the current contents of gCurrentString.

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 function for activating/deactivating
the document window is called, otherwise the function for activating/deactivating the modeless
dialog is called.

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 doDrawMessage draws a window header frame in the window, and the current contents of
gMessageString, in either the activated or deactivated mode.

doActivateDialogs

doActivateDialogs performs window activation and deactivation for the modeless dialog and
window-modal (sheet) dialog.

DialogSelect is called to handle the event.  If the modeless or window-modal (sheet) dialog is
becoming active, DialogSelect activates all controls and, on Mac OS 8/9, redraws the
one-pixel-wide modeless dialog frame in the active mode.  If the modeless dialog is going to
the back, DialogSelect deactivates all controls and, on Mac OS 8/9, redraws the one-pixel-wide
modeless dialog frame in the inactive mode.

In the remaining code, if either the modeless dialog or window-modal (sheet) dialog is becoming
active, the menus are adjusted and the global variable used in the sleep parameter of the
WaitNextEvent function is assigned the value returned by GetCaretTime (the cursor-blinking
interval set by the user in the General Controls control panel (Mac OS 8/9) and System
preferences (Mac OS X)).  This is necessary to ensure that null events will always be
generated, and thus doIdle and IdleControls will be called (necessary on Mac OS 8/9 only), at
an interval short enough to ensure insertion point caret blinking at the proper rate.

If if either the modeless dialog or window-modal (sheet) dialog is being deactivated, the sleep
parameter for the WaitNextEvent function is reset to the maximum unsigned long value.

(Recall that changing the value in gSleepTime is irrelevant on Mac OS X because the function
doIdle will not be called when the program is running on Mac OS X.)

doAdjustMenus

Note that, if the program is running on Mac OS X, and a call to IsWindowCollapsed reveals that
the document window has been minimised to the dock, the menu items which invoke the
window-modal (sheet) alert and (sheet) dialog are disabled.

doMenuChoice

doMenuChoice handles menu choices.  If the choice was the Close item in the File menu, and if
the front window is the modeless dialog, a function which hides that modeless dialog is called. 
(In this program, because the document window does not have a close box/button, the Close item
is only enabled when the modeless dialog is the front window.)

doEditMenu

doEditMenu first determines whether the front window is the modeless dialog or window-modal
(sheet) dialog (both of which have an edit text item).  If so, a reference to the dialog is
obtained, following which Dialog Manager functions are called to cut, copy, paste, or clear
text as appropriate.  The Dialog Manager, in conjunction with TextEdit, performs these
operations.

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.

Note that, when the Modal Alert item is chosen, doModalAlerts is called with false is passed in
the function's parameter.  Note also that, when the Movable Modal Alert item is chosen,
doMovableModalAlertonX is called if the program is running on Mac OS X, otherwise doModalAlerts
is called with true passed in the function's parameter.  This latter reflects the fact that, on
Mac OS X, the movable modal alert will be created by a function that is not available on Mac OS
8/9.

doExplicitlyDeactivateDocument

doExplicitlyDeactivateDocument is called at the beginning of those functions which create modal
and movable modal alerts and dialogs.

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

doModalAlerts

doModalAlerts creates, displays, manages, and disposes of the modal alert and, on Mac OS 8/9,
the movable modal alert.

The call to doExplicitlyDeactivateDocument deactivates the document window.

At the next nine lines, values are assigned to the fields of a standard alert parameter
structure.  In sequence: the alert is to be modal or movable modal depending on the value
received in the formal parameter movable; a help button is to be displayed; the event filter
(callback) function used is to be the application-defined event filter (callback) function
pointed to by the universal procedure pointer gEventFilterUPP; the default title for the OK
push button is to be used; a Cancel push button is required, and is to have the default title
for the Cancel button; an Other push button is required, and is to have the title "Other";  the
default push button is to be the first push button (which will thus have the default ring drawn
around it (Mac OS 8/9) or be pulsing blue (Mac OS X) 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 is to be displayed in the alert position
on the parent window screen.  (With regard to the last field, the constant
kWindowDefaultPosition equates to kWindowAlertPositionParentWindowScreen.)

The calls to GetIndString retrieve the specified strings from the specified 'STR#' resource. 
These are passed in the inError and inExplanation parameters in the following call to
StandardAlert.

The call to StandardAlert creates and displays the alert (specifying a Stop alert in the first
parameter), and handles all user interaction (by internally calling ModalDialog), including
dismissing the alert when either the OK, Cancel, or Other button is hit.  The item hit is
returned in StandardAlert's outItemHit parameter.

In a real application, the appropriate action would be taken, based on which push button was
hit, following the call to StandardAlert; however, in this demonstration, the identity of the
push button is simply drawn in the document window.

doMovableModalAlertOnX

doMovableModalAlertOnX creates, displays, manages, and disposes of the movable modal alert when
the program is run on Mac OS X.  (The functions used in doMovableModalAlertOnX to create,
display, and manage the alert are not available on Mac OS 8/9.)

The call to doExplicitlyDeactivateDocument deactivates the document window.

The call to GetStandardAlertDefaultParams initialises a standard CFString alert parameter
structure with default values.  (The defaults are: not movable; no Help button; no Cancel
button; no Other button; alert position on parent window screen.)  The next four lines modify
the defaults by specifying that the alert is to be movable modal, and is to have a Help,
Cancel, and Other, push button.

The two calls to GetIndString retrieve the specified strings from the specified 'STR#'
resource, which are then converted to CFStrings before being passed in the error and
explanation fields in the following call to CreateStandardAlert.  CreateStandardAlert creates
the alert.

The call to RunStandardAlert displays the alert and runs the alert using a ModalDialog loop. 
When a push button is clicked, its item number is returned in the outItemHit parameter

In a real application, the appropriate action would be taken, based on which push button was
hit, following the call to RunStandardAlert; however, in this demonstration, the identity of
the push button is simply drawn in the document window.

doModalDialog

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

The call to doExplicitlyDeactivateDocument deactivates the document window.

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

The call to SetDialogDefaultItem tells the Dialog Manager which is the default push button item
and aliases the Return and Enter keys to 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.

The call to NewMenu creates a new empty menu for a font menu.  A reference to this menu is
passed in the call to CreateStandardFontMenu, which creates a non-hierarchical font menu
containing the names of all resident fonts.  GetDialogItemAsControl gets a reference to the
Font pop-up menu button control, facilitating the calls to SetControlMinimum,
SetControlMaximum, and SetControlData.  The latter sets the menu to be used by the pop-up menu
button control.

With the modal dialog 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 reference 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 reference to the control and GetControlValue is called to get the menu item number of
the menu item chosen, following which an function is called to extract the menu item text and
display it in the window header.

Note that the first parameter in the ModalDialog call is a universal procedure pointer to the
application-defined event filter (callback) 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.

doMovableModalDialog

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

The call to doExplicitlyDeactivateDocument deactivates the document window.

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

The call to SetDialogDefaultItem tells the Dialog Manager which is the default push button item
and aliases the Return and Enter keys to 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 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 item.

The first call to GetDialogItemAsControl gets a reference 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 reference 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.  (This may be required later.)

With the movable modal dialog 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 reference 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 (callback) function.  Note also that all user interaction
relating to the clock control and edit text item 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 item would
possibly be retrieved at this point if the user hit the OK push button.)

doCreateOrShowModelessDialog

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

Accordingly, the first line determines whether the modeless dialog is already open.  If it is
not: the call to GetNewDialog creates the modeless dialog; the call to SetWRefCon assigns the
reference constant kSearchModeless to the dialog object's window object so as to differentiate
this dialog from the window-modal (sheet) dialog; a call to SetDialogDefaultItem causes the
push button to be drawn with the default ring (Mac OS 8/9) or in pulsing blue (Mac OS X); a
call to SetDialogItemText assigns some initial text to the edit text item; a call to
SelectDialogItemText selects the text in the edit text item.  (Note that, if the edit text item
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 function doIdle (Mac OS 8/9).)

If, on the other hand, the modeless dialog has already been opened, the call to ShowWindow
displays the dialog 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.

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 the modeless dialog or the window-modal (sheet) dialog (both of which
contain an edit text item), 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 item.  If DialogSelect returns true, and if the item hit was the OK push button, a
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.  It simply demonstrates retrieval of the text in an edit text item in a
dialog.

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

doHideModelessDialog

doHideModelessDialog hides a modeless dialog.  The call to HideWindow makes the dialog
invisible.  The sleep parameter for the WaitNextEvent function is reset to the maximum possible
long value (relevant only on Mac OS 8/9), because insertion point caret blinking is not
required while the Search dialog is hidden.

eventFilter

eventFilter is the application-defined event filter (callback) function which, in conjunction
with ModalDialog, handles events in the modal alerts, movable modal alert on OS 8/9, modal
dialog and movable modal dialog.

If the program is running on Mac OS 8/9, if the event is an update event, and if that event is
not for the dialog or alert 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.  The call to the window updating
function is not necessary on Mac OS X.

If the event is an autoKey event and the Command key is down, the event is, in effect,
discarded.  This means that, if the user is working within the edit text item in the movable
modal dialog and presses and holds the Command key equivalents for Cut, Copy or Paste,
repeating cut, copy and paste actions will be defeated.  That is, pressing and holding the
Command key equivalent will only result in a single cut, copy, or paste action.  (See also
doEvents, above.)

If the event is neither an update event nor an autoKey event with the Command key down, the
current graphics port is saved and then set to that of the alert or dialog.  The event is then
passed to the standard event filter (callback) function for handling.  If the standard event
filter (callback) function handles the event, it will return true and, in the itemHit
parameter, the number of the item that it handled.  ModalDialog 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
(callback) function is used by all but the movable modal dialog.  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 is the only dialog which requires this tracking
(because it contains an edit text item.)

doPopupMenuChoice, doPlaySound, doDrawMessage, and doCopyPString

doPopupMenuChoice, doPlaySound, doDrawMessage, and doCopyPString are incidental to the
demonstration.  All perform the same duties as the similarly-named functions in the
demonstration program Controls1 (Chapter 7).  doDrawMessage is used in this program to prove
the explicit deactivation of the document window's content area when alerts and dialogs other
than the modeless dialog are invoked.

Sheets.c

Global Variables

gSheetDialogWindowRe will be assigned the window reference of the window-modal (sheet) dialog.

doSheetAlert

doSheetAlert creates, displays and handles a window-modal (sheet) alert.

The call to GetStandardAlertDefaultParams initialises a standard CFString alert parameter
structure with default values.

The two calls to GetIndString retrieve the specified strings from the specified 'STR#'
resource, which are then converted to CFStrings before being passed in the error and
explanation fields in the following call to CreateStandardSheet, which creates the alert.  The
call to ShowSheetWindow displays the sheet.  When the user clicks the OK button, the sheet is
dismissed.

doSheetDialog

doSheetAlert creates and displays a window-modal (sheet) dialog.

The call to GetNewDialog creates the dialog from the specified resource.  The call to
SetWRefCon assigns a value as the dialog window's reference constant.  This is used elsewhere
to differentiate the window-modal (sheet) dialog from the modeless dialog.

The call to SetDialogDefaultItem causes the push button to be drawn with the default ring (Mac
OS 8/9) or in pulsing blue (Mac OS X).  The call to SetDialogItemText assigns some initial text
to the edit text item and the call to SelectDialogItemText selects that text.

The next line assigns a reference to the dialog's window to the global variable
gSheetDialogWindowRef.  This is used in the function doButtonHitInSheetDialog.

The call to ShowSheetWindow displays the sheet.

doButtonHitInSheetDialog

doButtonHitInSearchModeless is called from doKeyDown and doInContent to further process, to
completion, a hit on the OK button in the window-modal (sheet) dialog.  In addition to
retrieving the text in an edit text item, it hides and disposes of the dialog.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Netflix Games expands its catalogue with...
It is a good time to be a Netflix subscriber this month. I presume there's a good show or two, but we are, of course, talking about their gaming service that seems to be picking up steam lately. May is adding five new titles, and there are some... | Read more »
Seven Knights Idle Adventure drafts in a...
Seven Knights Idle Adventure is opening up more stages, passing the 15k mark, and players may find themselves in need of more help to clear these higher stages. Well, the cavalry has arrived with the introduction of the Legendary Hero Iris, as... | Read more »
AFK Arena celebrates five years of 100 m...
Lilith Games is quite the behemoth when it comes to mobile games, with Rise of Kingdom and Dislyte firmly planting them as a bit name. Also up there is AFK Arena, which is celebrating a double whammy of its 5th anniversary, as well as blazing past... | Read more »
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 »

Price Scanner via MacPrices.net

Apple introduces the new M4-powered 11-inch a...
Today, Apple revealed the new 2024 M4 iPad Pro series, boasting a surprisingly thin and light design that pushes the boundaries of portability and performance. Offered in silver and space black... Read more
Apple introduces the new 2024 11-inch and 13-...
Apple has unveiled the revamped 11-inch and brand-new 13-inch iPad Air models, upgraded with the M2 chip. Marking the first time it’s offered in two sizes, the 11-inch iPad Air retains its super-... Read more
Apple discontinues 9th-gen iPad, drops prices...
With today’s introduction of the new 2024 iPad Airs and iPad Pros, Apple has (finally) discontinued the older 9th-generation iPad with a home button. In response, they also dropped prices on 10th-... Read more
Apple AirPods on sale for record-low prices t...
Best Buy has Apple AirPods on sale for record-low prices today starting at only $79. Buy online and choose free shipping or free local store pickup (if available). Sale price for online orders only,... Read more
13-inch M3 MacBook Airs on sale for $100 off...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices, along with Amazon’s, are the lowest currently available for new 13″... Read more
Amazon is offering a $100 discount on every 1...
Amazon has every configuration and color of Apple’s 13″ M3 MacBook Air on sale for $100 off MSRP, now starting at $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD): $999 $100 off... Read more
Sunday Sale: Take $150 off every 15-inch M3 M...
Amazon is now offering a $150 discount on every configuration and color of Apple’s M3-powered 15″ MacBook Airs. Prices start at $1149 for models with 8GB of RAM and 256GB of storage: – 15″ M3 MacBook... Read more
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

Jobs Board

IN6728 Optometrist- *Apple* Valley, CA- Tar...
Date: May 8, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92308 **Requisition ID:** 824398 At Target Optical, we help people see and look great - and Read more
Nurse Anesthetist - *Apple* Hill Surgery Ce...
Nurse Anesthetist - Apple Hill Surgery Center Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Now Read more
LPN-Physician Office Nurse - Orthopedics- *Ap...
LPN-Physician Office Nurse - Orthopedics- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Supervisor/Therapist Rehabilitation Medicine...
Supervisor/Therapist Rehabilitation Medicine - Apple Hill (Outpatient Clinic) - Day Location: York Hospital, York, PA Schedule: Full Time Sign-On Bonus Eligible Read more
BBW Sales Support- *Apple* Blossom Mall - Ba...
BBW Sales Support- APPLE BLOSSOM MALL Brand: Bath & Body Works Location: Winchester, VA, US Location Type: On-site Job ID: 04388 Job Area: Store: Sales and Support Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.