TweetFollow Us on Twitter

MACINTOSH C

Demonstration Program 2

Go to Contents
// 
// Text2.c
// 
//
// This program demonstrates:
//
//   The use of edit text field controls and TextEdit to enter data into the various 
//    fields of a database record.
//
//   The formatting and display of dates, times and numbers.
//
// The program opens a document window in which four edit text fields are displayed.  The
// first field requires text to be entered, the second an integer value, the third a 
// floating point value (that is, a currency value), and the fourth a date.  The user may
// select a field for data entry using the mouse or by cycling between fields using the 
// Tab key.
//
// TENew could have been used to create the four edit text fields; however, edit text
// field controls have been used so as to simplify the appearance aspects of window
// activation and deactivation and the setting and erasing of the keyboard focus frame.
// That said, TextEdit functions are widely used to deal directly with the controls' edit
// text structures.  Amongst other things, this allows the program to limit the number of
// characters that may be entered in each field and to cause the forward-delete key to be
// used to forward-delete characters.  (The forward-delete key is not supported by the 
// edit text field control CDEF.)
//
// The current date and the current time are displayed at the top of the window.
//
// The program utilises the following resources:
//
//   An 'MBAR' resource, and 'MENU' resources for Apple, File, and Edit menus (preload,
//    non-purgeable).
//
//   'CNTL' resources (purgeable) for edit text field controls and primary and secondary
//    group boxes (text title variant).  
//
//   A 'WIND' resource (purgeable) (initially not visible).
//
//   'hrct' and 'hwin' resources (purgeable) for balloon help. 
//
//   A 'SIZE' resource with the acceptSuspendResumeEvents, doesActivateOnFGSwitch, 
//    canBackground and  is32BitCompatible flags set.    
//
// 

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

#include <Appearance.h>
#include <ControlDefinitions.h>
#include <Devices.h>
#include <fp.h>
#include <Sound.h>
#include <ToolUtils.h>

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

#define rMenubar               128
#define mApple                 128
#define  iAbout                1
#define mFile                  129
#define  iQuit                 12
#define mEdit                  130    
#define  iCut                  3
#define  iCopy                 4
#define  iPaste                5
#define  iClear                6
#define  iSelectAll            7
#define rWindow                128
#define cDateAndTimeGroupBox   128
#define cDataEntryGroupBox     129
#define cItemTitleEditText     130
#define cQuantityEditText      131
#define cUnitValueEditText     132
#define cDateEditText          133
#define cLastRecordGroupBox    134
#define cBalloonGroupBox       135
#define kTab                   0x09
#define kDel                   0x7F
#define kReturn                0x0D
#define kMaxCharasItem         20
#define kMaxCharasQuant        9
#define kMaxCharasValue        9
#define kMaxCharasDate         16
#define topLeft(r)             (((Point *) &(r))[0])
#define botRight(r)            (((Point *) &(r))[1])

// ............................................................................. typedefs

typedef struct
{
  ControlHandle  itemControlHdl;
  ControlHandle  quantControlHdl;
  ControlHandle  valueControlHdl;
  ControlHandle  dateControlHdl;
} docStruc, **docStrucHandle;

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

Boolean    gIsColourDevice;
Boolean    gPixelDepth;
Boolean    gDone;
Boolean    gInBackground;
RgnHandle  gCursorRegion;
TEHandle   gCurrentEditStrucHdl;
SInt16     gMaxCharasThisField;
Rect       gItemRect    = { 89 ,91,102, 231 };
Rect       gQuantRect  = { 112 ,91,125,233 };
Rect       gValueRect  = { 135,91,148,233 };
Rect       gDateRect    = { 158,91,171,233 };
Str255     gLastRecordItem;
Str255     gLastRecordQuantity;
Str255     gLastRecordUnitValue;
Str255     gLastRecordTotalValue;
Str255     gLastRecordReviewDate;

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

void      main                     (void);
void      doInitManagers           (void);
void      doGetControls            (WindowPtr);
void      eventLoop                (void);
void      doIdle                   (void);
void      doEvents                 (EventRecord *);
void      doUpdate                 (EventRecord *);
void      doActivate               (EventRecord *);
void      doActivateWindow         (WindowPtr,Boolean);
void      doMenuChoice             (SInt32);
void      doAdjustMenus            (void);
void      doKeyEvent               (SInt8,docStrucHandle);
void      doHandleTabKey           (void);
void      doHandleDelKey           (void);
void      doInContent              (EventRecord *);
void      doChangeCurrentEditRec   (ControlHandle,Boolean,Point,SInt16);
void      doTodaysDate             (void);
void      doAcceptNewRecord        (void);
void      doAcceptValueField       (TEHandle,TEHandle);
void      doAcceptDateField        (TEHandle);
TEHandle  doGetEditTextHandle      (ControlHandle);
void      doDrawWindow             (void);
void      doAdjustCursor           (WindowPtr);
void      doCopyPString            (Str255,Str255);
void      doGetDepthAndDevice      (void);
  
//  main

void  main(void)
{
  Handle          menubarHdl;
  MenuHandle      menuHdl;
  WindowPtr       windowPtr;
  docStrucHandle  docStrucHdl;

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

  doInitManagers();

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

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

  menuHdl = GetMenuHandle(mApple);
  if(menuHdl == NULL)
    ExitToShell();
  else
    AppendResMenu(menuHdl,'DRVR');

  // .................... open window, set Appearance-compliant colour/pattern for window
  
  if(!(windowPtr = GetNewCWindow(rWindow,NULL,(WindowPtr) -1)))
    ExitToShell();

  SetPort(windowPtr);
  TextSize(10);
  
  SetThemeWindowBackground(windowPtr,kThemeBrushDialogBackgroundActive,true);

  // ...... get block for document structure, assign handle to window record refCon field

  if(!(docStrucHdl = (docStrucHandle) NewHandle(sizeof(docStruc))))
    ExitToShell();
  SetWRefCon(windowPtr,(SInt32) docStrucHdl);

  // ...................... get controls, show window, save background colour and pattern

  doGetControls(windowPtr);

  ShowWindow(windowPtr);

  // ......... get pixel depth and whether colour device for certain Appearance functions
  
  doGetDepthAndDevice();

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

  eventLoop();
}

//  doInitManagers

void  doInitManagers(void)
{
  MaxApplZone();
  MoreMasters();

  InitGraf(&qd.thePort);
  InitFonts();
  InitWindows();
  InitMenus();
  TEInit();
  InitDialogs(NULL);
  InitCursor();

  FlushEvents(everyEvent,0);

  RegisterAppearanceClient();
}

//  doGetControls

void  doGetControls(WindowPtr windowPtr)
{
  ControlHandle        controlHdl,lastRecordControlHdl;
  docStrucHandle       docStrucHdl;
  Boolean              booleanData = true;
  ControlFontStyleRec  controlFontStyleStruc;

  CreateRootControl(windowPtr,&controlHdl);

  docStrucHdl = (docStrucHandle) (GetWRefCon(windowPtr));

  if(!(controlHdl  = GetNewControl(cDateAndTimeGroupBox,windowPtr)))
    ExitToShell();
  if(!(controlHdl = GetNewControl(cDataEntryGroupBox,windowPtr)))
    ExitToShell();
  if(!((*docStrucHdl)->itemControlHdl = GetNewControl(cItemTitleEditText,windowPtr)))
    ExitToShell();
  if(!((*docStrucHdl)->quantControlHdl = GetNewControl(cQuantityEditText,windowPtr)))
    ExitToShell();
  if(!((*docStrucHdl)->valueControlHdl = GetNewControl(cUnitValueEditText,windowPtr)))
    ExitToShell();
  if(!((*docStrucHdl)->dateControlHdl = GetNewControl(cDateEditText,windowPtr)))
    ExitToShell();
  if(!(lastRecordControlHdl  = GetNewControl(cLastRecordGroupBox,windowPtr)))
    ExitToShell();
  if(!(controlHdl  = GetNewControl(cBalloonGroupBox,windowPtr)))
    ExitToShell();

  controlFontStyleStruc.flags = kControlUseFontMask;
  controlFontStyleStruc.font = kControlFontSmallSystemFont;
  SetControlFontStyle((*docStrucHdl)->itemControlHdl,&controlFontStyleStruc);
  SetControlFontStyle((*docStrucHdl)->quantControlHdl,&controlFontStyleStruc);
  SetControlFontStyle((*docStrucHdl)->valueControlHdl,&controlFontStyleStruc);
  SetControlFontStyle((*docStrucHdl)->dateControlHdl,&controlFontStyleStruc);
  controlFontStyleStruc.font = kControlFontSmallBoldSystemFont;
  SetControlFontStyle(lastRecordControlHdl,&controlFontStyleStruc);

  SetKeyboardFocus(windowPtr,(*docStrucHdl)->itemControlHdl,kControlEditTextPart);
  gCurrentEditStrucHdl = doGetEditTextHandle((*docStrucHdl)->itemControlHdl);
  gMaxCharasThisField = kMaxCharasItem;
}

//  eventLoop

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

  gDone = false;
  gCursorRegion = NewRgn();
  sleepTime = LMGetCaretTime();

  while(!gDone)
  {
    gotEvent = WaitNextEvent(everyEvent,&eventStructure,sleepTime,gCursorRegion);

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

//  doIdle

void  doIdle(void)
{
  static UInt32    oldRawSeconds;
  UInt32           rawSeconds;
  Str255           timeString;
  Rect             eraseRect;

  IdleControls(FrontWindow());

  GetDateTime(&rawSeconds);

  if(rawSeconds > oldRawSeconds) 
  {
    TimeString(rawSeconds,true,timeString,NULL);
    MoveTo(268,39);
    SetRect(&eraseRect,268,29,323,39);
    EraseRect(&eraseRect);
    DrawString(timeString);
    oldRawSeconds = rawSeconds;
  }
}

//  doEvent

void  doEvents(EventRecord *eventStrucPtr)
{
  WindowPtr        windowPtr;
  docStrucHandle   docStrucHdl;
  SInt16           partCode;
  SInt8            charCode;

  windowPtr = FrontWindow();
  docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);

  switch(eventStrucPtr->what)
  {
    case mouseDown:
      partCode = FindWindow(eventStrucPtr->where,&windowPtr);
  
      switch(partCode)
      {
        case inMenuBar:
          doAdjustMenus();
          doMenuChoice(MenuSelect(eventStrucPtr->where));
          break;

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

        case inDrag:
          DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
          doAdjustCursor(windowPtr);
          break;

        case inGoAway:
          if(TrackGoAway(windowPtr,eventStrucPtr->where))
            gDone = true;
          break;
      }
      break;

    case keyDown:
    case autoKey:
      charCode = eventStrucPtr->message & charCodeMask;
      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        doAdjustMenus();
        doMenuChoice(MenuEvent(eventStrucPtr));
      }
      else
        doKeyEvent(charCode,docStrucHdl);
      break;

    case updateEvt:
      doUpdate(eventStrucPtr);
      break;

    case activateEvt:
      doActivate(eventStrucPtr);
      break;

    case osEvt:
      switch((eventStrucPtr->message >> 24) & 0x000000FF)
      {
        case suspendResumeMessage:
          gInBackground = (eventStrucPtr->message & resumeFlag) == 0;
          if(!gInBackground)
            SetCursor(&qd.arrow);
          doActivateWindow(FrontWindow(),!gInBackground);
          break;
          
        case mouseMovedMessage:
          doAdjustCursor(FrontWindow());
          break;
      }
      break;
  }
}

//  doUpdate

void  doUpdate(EventRecord *eventStrucPtr)
{
  WindowPtr       windowPtr;
  docStrucHandle  docStrucHdl;
  GrafPtr         oldPort;

  windowPtr = (WindowPtr) eventStrucPtr->message;
  docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);

  GetPort(&oldPort);
  SetPort(windowPtr);

  BeginUpdate((WindowPtr) eventStrucPtr->message);
  UpdateControls(windowPtr,windowPtr->visRgn);
  doDrawWindow();
  EndUpdate((WindowPtr) eventStrucPtr->message);

  SetPort(oldPort);
}

//  doActivate

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

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

//  doActivateWindow

void  doActivateWindow(WindowPtr windowPtr,Boolean becomingActive)
{
  ControlHandle controlHdl;

  GetRootControl(windowPtr,&controlHdl);

  if(becomingActive)
  {
    ActivateControl(controlHdl);
    doDrawWindow();
  }
  else
  {
    DeactivateControl(controlHdl);
    doDrawWindow();
  }
}

//  doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  SInt16  menuID, menuItem;
  Str255  itemName;
  SInt16  daDriverRefNum;

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

  if(menuID == 0)
    return;

  switch(menuID)
  {
    case mApple:
      if(menuItem == iAbout)
        SysBeep(10);
      else
      {
        GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
        daDriverRefNum = OpenDeskAcc(itemName);
      }
      break;

    case mFile:
      if(menuItem == iQuit)
        gDone = true;
      break;
      
    case mEdit:
      switch(menuItem)
      {
        case iCut:
          TECut(gCurrentEditStrucHdl);
          break;

        case iCopy:
          TECopy(gCurrentEditStrucHdl);
          break;

        case iPaste:
          TEPaste(gCurrentEditStrucHdl);
          break;

        case iClear:
          TEDelete(gCurrentEditStrucHdl);
          break;

        case iSelectAll:
          TESetSelect(0,(*gCurrentEditStrucHdl)->teLength,gCurrentEditStrucHdl);
          break;
      }
      break;
  }

  HiliteMenu(0);
}

//  doAdjustMenus

void  doAdjustMenus(void)
{
  MenuHandle  fileMenuHdl, editMenuHdl;
  
  fileMenuHdl = GetMenuHandle(mFile);
  editMenuHdl = GetMenuHandle(mEdit);

  if((*gCurrentEditStrucHdl)->selStart < (*gCurrentEditStrucHdl)->selEnd)
  {
    EnableItem(editMenuHdl,iCut);
    EnableItem(editMenuHdl,iCopy);
    EnableItem(editMenuHdl,iClear);
  }
  else
  {
    DisableItem(editMenuHdl,iCut);
    DisableItem(editMenuHdl,iCopy);
    DisableItem(editMenuHdl,iClear);
  }

  if(TEGetScrapLength() > 0)
    EnableItem(editMenuHdl,iPaste);
  else
    DisableItem(editMenuHdl,iPaste);

  if((*gCurrentEditStrucHdl)->teLength > 0)
    EnableItem(editMenuHdl,iSelectAll);
  else
    DisableItem(editMenuHdl,iSelectAll);

  DrawMenuBar();
}

//  doKeyEvent

void  doKeyEvent(SInt8 charCode,docStrucHandle docStrucHdl)
{
  if(charCode == kTab)
    doHandleTabKey();
  else if(charCode == kDel)
    doHandleDelKey();
  else if(charCode == kReturn)
    doAcceptNewRecord();  
  else
  {
    if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl) ||
       gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
    {
      if(!((charCode >= '0' && charCode <= '9') || charCode == '.' || 
            charCode == '-' ||(charCode < 0x20)))
      {
        SysBeep(10);
        return;
      }
    }

    if(((*gCurrentEditStrucHdl)->teLength < gMaxCharasThisField) || (charCode < 0x20))
      TEKey(charCode,gCurrentEditStrucHdl);
    else
      SysBeep(10);
  }
}

//  doHandleTabKey

void  doHandleTabKey(void)
{
  WindowPtr        windowPtr;
  docStrucHandle   docStrucHdl;
  ControlHandle    oldControlHdl;
  Point            dummy;
  
  windowPtr = FrontWindow();
  docStrucHdl = (docStrucHandle) (GetWRefCon(windowPtr));

  GetKeyboardFocus(windowPtr,&oldControlHdl);  

  if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->itemControlHdl))
    doChangeCurrentEditRec((*docStrucHdl)->quantControlHdl,false,dummy,kMaxCharasQuant);
  else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl))
    doChangeCurrentEditRec((*docStrucHdl)->valueControlHdl,false,dummy,kMaxCharasValue);
  else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
    doChangeCurrentEditRec((*docStrucHdl)->dateControlHdl,false,dummy,kMaxCharasDate);
  else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->dateControlHdl))
    doChangeCurrentEditRec((*docStrucHdl)->itemControlHdl,false,dummy,kMaxCharasItem);

  Draw1Control(oldControlHdl);

  doAdjustCursor(windowPtr);
}

//  doHandleDelKey

void  doHandleDelKey(void)
{
  SInt16  selectionLength;

  selectionLength = (*gCurrentEditStrucHdl)->selEnd - (*gCurrentEditStrucHdl)->selStart;
  if(selectionLength == 0)
    (*gCurrentEditStrucHdl)->selEnd += 1;
  TEDelete(gCurrentEditStrucHdl);
}

//  doInContent

void  doInContent(EventRecord *eventStrucPtr)
{
  WindowPtr        windowPtr;
  docStrucHandle   docStrucHdl;
  Boolean          shiftKeyPosition;
  ControlHandle    oldControlHdl, controlHdl;

  windowPtr = FrontWindow();
  docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);
  GetKeyboardFocus(windowPtr,&oldControlHdl);  
  shiftKeyPosition = (eventStrucPtr->modifiers & shiftKey) != 0;

  SetPort(windowPtr);
  GlobalToLocal(&eventStrucPtr->where);

  if(FindControl(eventStrucPtr->where,windowPtr,&controlHdl))
  {
    if(controlHdl == (*docStrucHdl)->itemControlHdl)
    {
      if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->itemControlHdl))
        TEClick(eventStrucPtr->where,shiftKeyPosition,
                doGetEditTextHandle((*docStrucHdl)->itemControlHdl));
      else
      {
        doChangeCurrentEditRec((*docStrucHdl)->itemControlHdl,true,
                                eventStrucPtr->where,kMaxCharasItem);
      }
    }
    else if(controlHdl == (*docStrucHdl)->quantControlHdl)
    {
      if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl))
        TEClick(eventStrucPtr->where,shiftKeyPosition,
                doGetEditTextHandle((*docStrucHdl)->quantControlHdl));
      else
        doChangeCurrentEditRec((*docStrucHdl)->quantControlHdl,true,eventStrucPtr->where,
                               kMaxCharasQuant);
    }
    else if(controlHdl == (*docStrucHdl)->valueControlHdl)
    {
      if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
        TEClick(eventStrucPtr->where,shiftKeyPosition,
                doGetEditTextHandle((*docStrucHdl)->valueControlHdl));
      else
        doChangeCurrentEditRec((*docStrucHdl)->valueControlHdl,true,eventStrucPtr->where,
                               kMaxCharasValue);
    }
    else if(controlHdl == (*docStrucHdl)->dateControlHdl)
    {
      if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->dateControlHdl))
        TEClick(eventStrucPtr->where,shiftKeyPosition,
                doGetEditTextHandle((*docStrucHdl)->dateControlHdl));
      else
        doChangeCurrentEditRec((*docStrucHdl)->dateControlHdl,true,eventStrucPtr->where,
                               kMaxCharasDate);
    }
  }

  Draw1Control(oldControlHdl);
  doAdjustCursor(windowPtr);
}

//  doChangeCurrentEditRec

void  doChangeCurrentEditRec(ControlHandle newControlHdl,Boolean teClickFlag,
                             Point mouseXY,SInt16 maxCharas)
{
  ClearKeyboardFocus(FrontWindow());
  SetKeyboardFocus(FrontWindow(),newControlHdl,kControlEditTextPart);

  gCurrentEditStrucHdl = doGetEditTextHandle(newControlHdl);

  if(teClickFlag)
    TEClick(mouseXY,false,doGetEditTextHandle(newControlHdl));

  TESetSelect(0,32767,gCurrentEditStrucHdl);

  gMaxCharasThisField = maxCharas;
}

//  doTodaysDate

void  doTodaysDate(void)
{
  UInt32  rawSeconds;
  Str255  dateString;

  GetDateTime(&rawSeconds);
  DateString(rawSeconds,longDate,dateString,NULL);
  MoveTo(59,39);
  DrawString(dateString);
}

//  doAcceptNewRecord

void  doAcceptNewRecord(void)
{
  WindowPtr       windowPtr;
  docStrucHandle  docStrucHdl;
  TEHandle        itemEditHdl, quantEditHdl, valueEditHdl, dateEditHdl;
  Rect            theRect;
  Point           dummy;

  windowPtr = FrontWindow();
  docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);

  itemEditHdl    = doGetEditTextHandle((*docStrucHdl)->itemControlHdl);
  quantEditHdl  = doGetEditTextHandle((*docStrucHdl)->quantControlHdl);
  valueEditHdl  = doGetEditTextHandle((*docStrucHdl)->valueControlHdl);
  dateEditHdl    = doGetEditTextHandle((*docStrucHdl)->dateControlHdl);

  if((*itemEditHdl)->teLength   == 0 || (*quantEditHdl)->teLength == 0 ||
     (*valueEditHdl)->teLength == 0  || (*dateEditHdl)->teLength   == 0)
  {
    SysBeep(10);
    return;
  }

  GetDialogItemText((*itemEditHdl)->hText,gLastRecordItem);
  GetDialogItemText((*quantEditHdl)->hText,gLastRecordQuantity);
  doAcceptValueField(valueEditHdl,quantEditHdl);
  doAcceptDateField(dateEditHdl);

  SetRect(&theRect,144,198,310,300);
  InvalRect(&theRect);

  TESetSelect(0,32767,itemEditHdl);
  TEDelete(itemEditHdl);

  TESetSelect(0,32767,quantEditHdl);
  TEDelete(quantEditHdl);

  TESetSelect(0,32767,valueEditHdl);
  TEDelete(valueEditHdl);

  TESetSelect(0,32767,dateEditHdl);
  TEDelete(dateEditHdl);

  gCurrentEditStrucHdl = itemEditHdl;
  doChangeCurrentEditRec((*docStrucHdl)->itemControlHdl,false,dummy,kMaxCharasItem);
}

//  doAcceptValueField

void  doAcceptValueField(TEHandle valueEditHdl,TEHandle quantEditHdl)
{
  Handle            itl4ResourceHdl;
  SInt32            numpartsOffset;
  SInt32            numpartsLength;
  NumberParts       *numpartsTablePtr;
  Str255            formatString = "\p'$'###,###,###.00;'Valueless';'Valueless'";
  NumFormatString   formatStringRec;
  Str255            inputNumString;
  Str255            formattedNumString;
  extended80        value80Bit;
  Str255            quantityString;
  SInt32            quantity;
  FormatResultType  result;
#if TARGET_CPU_PPC
  double            valueDouble;
#endif

  GetIntlResourceTable(smSystemScript,iuNumberPartsTable,&itl4ResourceHdl,&numpartsOffset,
                       &numpartsLength);
  numpartsTablePtr = (NumberPartsPtr) ((SInt32) *itl4ResourceHdl + numpartsOffset);

  StringToFormatRec(formatString,numpartsTablePtr,&formatStringRec);

  GetDialogItemText((*valueEditHdl)->hText,inputNumString);

  StringToExtended(inputNumString,&formatStringRec,numpartsTablePtr,&value80Bit);
  ExtendedToString(&value80Bit,&formatStringRec,numpartsTablePtr,formattedNumString);

  doCopyPString(formattedNumString,gLastRecordUnitValue);

  GetDialogItemText((*quantEditHdl)->hText,quantityString);
  StringToNum(quantityString,&quantity);

#if TARGET_CPU_68K
value80Bit = value80Bit * quantity;
#endif
#if TARGET_CPU_PPC
  valueDouble = x80tod(&value80Bit);
  valueDouble = valueDouble * quantity;
  dtox80(&valueDouble,&value80Bit);
#endif

  result = ExtendedToString(&value80Bit,&formatStringRec,numpartsTablePtr,
                            formattedNumString);

  if(result == fFormatOverflow)
    doCopyPString("\p(Too large to display)",gLastRecordTotalValue);
  else
    doCopyPString(formattedNumString,gLastRecordTotalValue);
}

//  doAcceptDateField

void  doAcceptDateField(TEHandle dateEditHdl)
{
  DateCacheRecord  dateCacheRec;
  Ptr              textPtr;
  SInt32           textLength, lengthUsed;
  LongDateRec      longDateTimeRec;
  LongDateTime     longDateTimeValue;
  Str255           dateString;

  InitDateCache(&dateCacheRec);
  textPtr = (*(*dateEditHdl)->hText);
  textLength = (*dateEditHdl)->teLength;

  HLock((*dateEditHdl)->hText);
  StringToDate(textPtr,textLength,&dateCacheRec,&lengthUsed,&longDateTimeRec);
  HUnlock((*dateEditHdl)->hText);
  
  LongDateToSeconds(&longDateTimeRec,&longDateTimeValue);
  longDateTimeValue += 15724800;
  LongDateString(&longDateTimeValue,longDate,dateString,NULL);
  doCopyPString(dateString,gLastRecordReviewDate);
}

//  doGetEditTextHandle

TEHandle  doGetEditTextHandle(ControlHandle controlHdl)
{
  TEHandle  textEditHdl;

  GetControlData(controlHdl,kControlNoPart,kControlEditTextTEHandleTag,
                 sizeof(textEditHdl),(Ptr) &textEditHdl,NULL);

  return textEditHdl;
}

//  doDrawWindow

void  doDrawWindow(void)
{
  Rect  theRect;
  
  SetRect(&theRect,144,198,310,300);
  EraseRect(&theRect);
  
  if(!gInBackground)
    SetThemeTextColor(kThemeTextColorModelessDialogActive,gPixelDepth,gIsColourDevice);
  else
    SetThemeTextColor(kThemeTextColorModelessDialogInactive,gPixelDepth,gIsColourDevice);

  doTodaysDate();

  MoveTo(32,39);
  DrawString("\pDate:");
  MoveTo(239,39);
  DrawString("\pTime:");

  MoveTo(34,99);
  DrawString("\pItem Title:");
  MoveTo(41,122);
  DrawString("\pQuantity:");
  MoveTo(32,145);
  DrawString("\pUnit Value:");
  MoveTo(61,168);
  DrawString("\pDate:");

  MoveTo(240,99);
  DrawString("\pEg: Barometers");
  MoveTo(240,122);
  DrawString("\pEg: 34");
  MoveTo(240,145);
  DrawString("\pEg: 135.58");
  MoveTo(240,168);
  DrawString("\pEg: 24 Jul 95");

  MoveTo(92,214);
  DrawString("\pItem Title:");
  MoveTo(99,234);
  DrawString("\pQuantity:");
  MoveTo(90,254);
  DrawString("\pUnit Value:");
  MoveTo(87,274);
  DrawString("\pTotal Value:");
  MoveTo(81,294);
  DrawString("\pReview Date:");

  MoveTo(112,349);
  DrawString("\pBalloon help is available");

  MoveTo(147,214);
  DrawString(gLastRecordItem);
  MoveTo(147,234);
  DrawString(gLastRecordQuantity);
  MoveTo(147,254);
  DrawString(gLastRecordUnitValue);
  MoveTo(147,274);
  DrawString(gLastRecordTotalValue);
  MoveTo(147,294);
  DrawString(gLastRecordReviewDate);
}

//  doAdjustCursor

void  doAdjustCursor(WindowPtr windowPtr)
{
  GrafPtr          oldPort;
  docStrucHandle   docStrucHdl;
  RgnHandle        arrowRegion,iBeamRegion;
  Rect             iBeamRect;
  Point            mouseXY;

  GetPort(&oldPort);
  SetPort(windowPtr);
    
  docStrucHdl = (docStrucHandle) GetWRefCon(windowPtr);

  arrowRegion = NewRgn();
  iBeamRegion = NewRgn();
    
  SetRectRgn(arrowRegion,-32768,-32768,32766,32766);
  
  if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->itemControlHdl))
    iBeamRect = gItemRect;
  else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->quantControlHdl))
    iBeamRect = gQuantRect;
  else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->valueControlHdl))
    iBeamRect = gValueRect;
  else if(gCurrentEditStrucHdl == doGetEditTextHandle((*docStrucHdl)->dateControlHdl))
    iBeamRect = gDateRect;

  LocalToGlobal(&topLeft(iBeamRect));
  LocalToGlobal(&botRight(iBeamRect));  

  RectRgn(iBeamRegion,&iBeamRect);
  DiffRgn(arrowRegion,iBeamRegion,arrowRegion);
  
  GetMouse(&mouseXY);
  LocalToGlobal(&mouseXY);

  if(PtInRgn(mouseXY,iBeamRegion))
  {
    SetCursor(*(GetCursor(iBeamCursor)));
    CopyRgn(iBeamRegion,gCursorRegion);
  }
  else
  {
    SetCursor(&qd.arrow);
    CopyRgn(arrowRegion,gCursorRegion);
  }

  DisposeRgn(arrowRegion);
  DisposeRgn(iBeamRegion);

  SetPort(oldPort);
}

//  doCopyPString

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

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

//  doGetDepthAndDevice

void doGetDepthAndDevice(void)
{
  GDHandle  deviceHdl;

  deviceHdl = LMGetMainDevice();
  gPixelDepth = (*(*deviceHdl)->gdPMap)->pixelSize;
  if(BitTst(&(*deviceHdl)->gdFlags,gdDevType))
    gIsColourDevice = true;
}

// 

Demonstration Program 2 Comments

When this program is run, the user should enter data in the four edit text fields, using
the tab key or mouse clicks to select the required field and pressing the Return key when
data has been entered in all fields.

In order to observe number formatting effects, the user should occasionally enter very
large numbers and negative numbers in the Value field.  In order to observe the effects
of date string parsing and formatting, the user should enter dates in a variety of
formats, for example: "2 Mar 95", "2/3/95", "March 2 1995", "2 3 95", etc.

#define

The constants beginning with c represent resource IDs for group box and edit text field
controls.  kTab, kDel, and kReturn represent the character codes generated by the tab,
forward-delete, and return keys.  The following four constants are used to limit the
number of characters that can be entered in a particular edit text field.

#typedef

The DocStruc data type will be used for a document structure, which will be attached 
to the single window opened by the program.  The four fields of this structure will be 
assigned handles to separate edit structures.


Global Variables

gIsColourDevice and gPixelDepth will be used by the Appearance Manager function 
SetThemeTextColor.  gCursorRegion relates to the cursorRgn parameter of the WaitNextEvent 
function.

gCurrentEditStrucHdl will be assigned the handle to the edit structure for the currently
active edit text field.  gMaxCharasThisField will be assigned a value representing the
maximum number of characters allowed to be entered in the currently active edit text
field.  The four Rect variables will be used by the cursor shape changing function to
establish the I-Beam cursor region for the currently active edit text field.  The four
Str255 variables will be assigned the strings to be drawn in the "last Record Entered"
group box when the Return key is pressed.

main

SetThemeWindowBackground sets an Appearance-compliant colour/pattern for the window's
content area.  This means that the content area will be automatically repainted with that
colour/pattern when required with no further assistance from the application.

doGetControls creates the controls for the window, following which the window is
displayed and the background colour and pattern are saved.

doGetControls

doGetControls creates the window's controls.

Firstly, a root control is created for the window.  The edit text field and group box
controls are then created, their handles being assigned to the relevant field of the
window's document structure.

At the next block, SetControlFontStyle is used to set the font for the edit text field
controls to the small system font and the font for the "Last Record Entered" group box to
the small emphasized system font.

At the last block, SetKeyboardFocus is called to set the keyboard focus to the first edit
text field control, the associated edit structure is made the current edit structure, and
the global variable which will limit the number of characters that may be entered in this
edit text field is assigned the appropriate value.

eventLoop

When a NULL event is received, the application-defined function doIdle is called. 
Because IdleControls will be called in the idle function to blink the insertion point
caret, WaitNextEvent's sleep parameter is assigned the value returned by a call to
LMGetCaretTime

doIdle

doIdle is called when WaitNextEvent returns a null event.  doIdle blinks the insertion
point caret and draws the current time in the top right of the window.

IdleControls is called to ensure that the caret blinks regularly in the edit text field
control with keyboard focus.

GetDateTime retrieves the "raw" seconds value, as known to the system.  (This is the
number of seconds since 1 Jan 1904.)  If that value is greater than the value retrieved
the last time doIdle was called, TimeString converts the raw seconds value to a string
containing the time formatted according to flags in the numeric format ('itl0') resource. 
(Since NULL is specified in the resource handle parameter, the appropriate 'itl0'
resource for the current script system is used.)  This string is then drawn in the window
and the retrieved raw seconds value is assigned to the static variable oldRawSeconds for
use next time doIdle is called.

doEvents

doEvents handles initial event processing.  

In the case of a mouse-down event in the content region of the window (when it is the
front window), the application-defined function doInContent is called.

In the case of a non-Command key equivalent key-down event, the application-defined
function doKeyEvent is called.

doUpdate and doActivateWindow

doUpdate handles update events.  Between the usual calls to BeginUpdate and EndUpdate,
the contents of the window are re-drawn.

doActivateWindow activates or deactivates the window's contents.  GetRootControl gets a
handle to the window's root control.  This is used in the following lines to either
activate or deactivate all of the controls in the window.  In addition, the
application-defined function doDrawWindow is called to draw all the non-control text in
the window in either the normal or dimmed state, as appropriate.

doMenuChoice

doMenuChoice handles Apple, File, and Edit menu choices.  In the case of choices from the
Edit menu, the appropriate TextEdit function is called.

doAdjustMenus

doAdjustMenus adjusts the menus.

If there is a selection range in the current edit structure, the Cut, Copy, and Clear
items are enabled, otherwise they are disabled.  If there is any text in the TextEdit
private scrap (the call to TEGetScrapLength), the Paste item is enabled, otherwise it is
disabled.  If there is any text in the currently activate edit text field, Select All is
enabled, otherwise it is disabled.

doKeyEvent

doKeyEvent handles key-down and auto-key events which are not Command key equivalents.

If the character code is that generated by the tab key or the del key, handling is passed
to other application-defined functions.  If the Return key was pressed, control is passed
to an application-defined function which accepts, formats, and displays the entered data
and deletes all text from the edit text fields.

The following occurs if the character code makes it to the else block.  Firstly, if the
active edit text field is the Quantity or Unit Value field, and if the character code is
not a numeric character, the minus character, or the period character, the system alert
sound is played and the function returns.  TEKey is called provided that the maximum
number of characters allowable in the currently active edit text field will not be
exceeded or the character is one of the non-printing characters.  If the number of
characters entered is at the limit and a printing character key was pressed, the
character is not accepted and the system alert sound is played.  This arrangement ensures
that, if the number of characters in the edit structure is at the maximum allowed, the
arrow and delete keys, unlike the printing character keys, will not be ignored and will
have their usual effect.

doHandleTabKey

doHandleTabKey handles the tab key.  Its purpose is to cycle around the edit text fields
in response to tab key presses, defeating keyboard focus on the currently active edit
text field and setting keyboard focus on the next edit text field in the sequence.

The first two lines retrieve a handle to the document structure for the window.  The call
to GetKeyboardFocus gets a handle to the control with keyboard focus.  This will be used
in the call to Draw1Control at the bottom of the function.

The central block determines which is the current edit structure (and thus the current
edit text field) and calls the application-defined function that changes the active edit
text field.  This call passes the handle to the next edit text field control in the
sequence, together with the maximum number of characters allowed in that field.

The call to Draw1Control on the "old" edit text field control ensures that the insertion
point caret will be erased in that field.  The call to doAdjustCursor is required in
order to change the rectangle within which the cursor changes to the I-beam shape.

doHandleDelKey

doHandleDelKey handles the forward-delete key, which is not supported by TextEdit.  The
first line gets the current selection length.  If the selection length is zero (that is,
an insertion point caret is being displayed), the selection is set to include the
character to the right of the insertion point.  TEDelete deletes the current selection
range from the text.

doInContent

doInContent handles mouse-down events in the content region of the window.

The second and third lines get a handle to the window's document structure. .  The call
to GetKeyboardFocus gets a handle to the control with keyboard focus.  (This will be used
in the call to Draw1Control at the bottom of the function.)  The next line gets the
position of shift key at the time of the mouse-down.  (TEClick's behaviour depends on the
position of the shift key.)

GlobalToLocal converts the global coordinates of the mouse-down to the local coordinates
required by FindControl and TEClick.

If FindControl reports an enabled item under the mouse, and if that item is the Item
Title edit text field control, and if that control has the keyboard focus, TEClick is
called to take control until the mouse button is released.  (Note that the shift key
position is passed in the second parameter.)  If the Item Title edit text field control
does not have the keyboard focus, the application-defined function doChangeCurrentEditRec
is called to change the keyboard focus to that control.  The same basic procedure is
followed in the case of mouse-downs within the other three edit text field controls.

The call to Draw1Control on the "old" edit text field control ensures that the insertion
point caret will be erased in that field.  The call to doAdjustCursor is required in
order to change the rectangle within which the cursor changes to the I-beam shape.

doChangeCurrentEditRec

doChangeCurrentEditRec is called by both doHandleTabKey and doInContent to change 
the edit text field control with keyboard focus (and thus the currently active edit 
structure).

SetKeyboardFocus sets the keyboard focus to the specified edit text field control.  The 
next line makes the edit structure associated with that control the current edit 
structure.

If this function was called by doInContent (teClick = true), TEClick is called to tell
TextEdit that the mouse-down has occurred in the newly-activated edit structure.  Note
that the extend parameter is set to false, telling TextEdit, regardless of the position
of the shift key, that the user is not extending a selection.

TESetSelect ensures that, if there are any characters in the edit structure, they will be
initially highlighted.  The last line assigns the appropriate value to the global
variable which controls the maximum allowable number of characters in the active edit
text field.

doTodaysDate

doTodaysDate draws the date at the top of the window.

GetDateTime gets the raw seconds value, as known to the system.  DateString converts the
raw seconds value to a string containing a date formatted in long date format according
to flags in the numeric format ('itl0') resource.  (Since NULL is specified in the
resource handle parameter, the appropriate 'itl0' resource for the current script system
is used.)  This string is then drawn in the window.

doAcceptNewRecord

doAcceptNewRecord is called when the Return key is pressed.  Assuming each edit text
field contains at least one character of text, it calls other application-defined
functions to format (where necessary) and display strings in the "Last Record Entered"
group box area, and prepares the edit text fields to accept new data.

The first two lines get a handle to the window's document structure.  The next block
copies the handles to the four edit structures to four local variables.

At the next block, if any one of the edit text fields does not contain any text, the
system alert sound is played and the function returns.

The two calls to GetDialogItemText get the text in the "Item Title" and "Quantity" edit
text fields into two global variables.  (GetDialogItemText is usually used to get the
text from an editable edit text item in a dialog box.  It works here because the first
parameter required by GetDialogItemText is a handle to the hText field of an edit
structure.)  No special formatting of these two strings is required.

The call to InvalRect causes an update event to be generated.  As will be seen, this
causes the strings created by the preceding block to be drwan in the "Last Record
Entered" group box area.

The next two lines call two application defined functions to format and display strings
derived from the information in the "Unit Value" and "Date" edit text fields.

The next 10 lines delete the text from all edit text fields.  The last three lines change
the keyboard focus back to the "Item Title" edit text field.

doAcceptValueField

doAcceptValueField is called by doAcceptNewRecord to get the string from the "Value" edit
structure, convert it to floating point number, convert that number to a formatted number
string, draw that string, get the string in the "Quantity" edit structure, convert that
string to an integer, multiply the floating point number by the integer to arrive at the
"Total Value" value, convert the result to a formatted number string, and draw that
string .

A pointer to a number parts table is required by the functions that convert between
floating point numbers and strings.  Accordingly, the first three lines get the required
pointer.

StringToFormatRec converts the number format specification string into the internal
numeric representation required by the functions that convert between floating point
numbers and strings.

With that preparation attended to, GetDialogItemText gets the "Value" edit text field
text into a Pascal string.  StringToExtended converts that string into a floating point
number of type extended (80 bits).  ExtendedToString converts that number back to a
string, formatted according to the internal numeric representation of the number format
specification string.  doCopyPString copies that string to a global variable for
subsequent drawing in the window.

The intention now is to multiply the quantity by the unit value to arrive at a total
value.  However, conditional compilation is required here to account for the fact that
the PowerPC Floating Point Unit does not support Motorola's 80-bit extended type.

If the program is being compiled as 680x0 code, the value in the extended80 variable
(unit value) is multiplied by the quantity and the result (total value) is stored in the
extended80 variable.  If the program is being compiled as PowerPC code, the extended80
value is converted to a value  of type double before the multiplication occurs.  The
result of the multiplication is assigned to the variable of type double.  This is then
converted to an extended80.

The extended80 value is then passed in the first parameter of ExtendedToString for
conversion to a formatted string.  If ExtendedToString does not return fFormatOverflow,
the formatted string is copied to a global variable for subsequent drawing in the window.

doAcceptDateField

doAcceptDateField is called by doAcceptNewRecord to create a long date-time structure
from the string in the "Date" edit structure, add six months to the date, format the date
as a string (long date format), and draw that string in the structure panel.

The function which creates the long date-time structure takes an initialised date cache
structure as a parameter.  Accordingly, the first step is to initialise the specified
date cache structure.

The next two lines get a pointer to the text in the "Date" edit structure and the length
of that text.  These are passed as parameters in the StringToDate call, which parses the
input string and fills in the relevant fields of the long date-time structure.

LongDateToSeconds converts the long date-time structure to a long date-time value.  The
next line adds six months worth of seconds to the long date-time value.  The modified
long date-time value is then passed as a parameter to LongDateString.  LongDateString
converts the long date-time value to a long format date string formatted according to the
specified international resource.  (In this case, NULL is passed as the international
resource parameter, meaning that the appropriate 'itl1' resource for the current script
system is used.)

The formatted date string is copied to a global variable for subsequent drawing in the
window.

doGetEditTextHandle

doGetEditTextHandle returns the handle to the edit structure associated with the
specified edit text control.
doDrawWindow

doDrawWindow draws the non-control text content of the window.  The text will be drawn
normal or dimmed depending on whether the application is in the foreground or background.

doAdjustCursor

doAdjustCursor is the cursor adjustment function.  It is similar to the cursor adjustment
functions in previous demonstration programs except that the rectangle in which the
cursor is required to change to the I-beam cursor shape is changed to accord with that of
the edit text field with keyboard focus.
Prior to the version issued with Mac OS 8.5 and later, the text backgound colour in 
the edit text control would often corrupt after cut and paste operations using the 
Edit menu (though not when using the Command-key equivalents).  If you experience 
this problem when running the demonstration under a version of the Mac OS earlier 
than mac OS 8.5, proceed as follows:

Add this data type:

  typedef struct
  {
    RGBColor      backColour;
    PixPatHandle  backPixelPattern;
    Pattern       backBitPattern;
    } backColourPattern;

Add this global variable:

  backColourPattern gBackColourPattern;

Add these function prototypes:

  void doSaveBackground     (backColourPattern *);
  void doRestoreBackground  (backColourPattern *);
  void doSetBackgroundWhite (void);

Add these functions:

  //  doSaveBackground

  void  doSaveBackground(backColourPattern *gBackColourPattern)
  {
    GrafPtr  currentPort;

    GetPort(¤tPort);

    GetBackColor(&gBackColourPattern->backColour);
    gBackColourPattern->backPixelPattern  = NULL;

    if((**((CGrafPtr) currentPort)->bkPixPat).patType != 0)
      gBackColourPattern->backPixelPattern = ((CGrafPtr) currentPort)->bkPixPat;
    else
      gBackColourPattern->backBitPattern = 
                       *(PatPtr) (*(**((CGrafPtr) currentPort)->bkPixPat).patData);
  }

  //  doRestoreBackground

  void  doRestoreBackground(backColourPattern *gBackColourPattern)
  {
    RGBBackColor(&gBackColourPattern->backColour);

    if(gBackColourPattern->backPixelPattern)
    BackPixPat(gBackColourPattern->backPixelPattern);
    else
      BackPat(&gBackColourPattern->backBitPattern);
  }

  //  doSetBackgroundWhite

  void  doSetBackgroundWhite(void)
  {
    RGBColor  whiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
  
    RGBBackColor(&whiteColour);
    BackPat(&qd.white);
  }

// 

Add this call:

  doSaveBackground(&gBackColourPattern);

in the main function, after the call to ShowWindow.

Add this call:

  doRestoreBackground(&gBackColourPattern);

in doIdle, after call to IdleControls,
in doMenuChoice, just before the last break statement,
in doKeyEvent, just before the last closing brace,
in doIncontent, just before the last closing brace, and
in doChangeCurrentEditRec, as the first line.

Add this line:

  doSetBackgroundWhite();

in doMenuChoice, immediately before switch(menuItem),
in doKeyEvent, as the first line, and
in doInContent, as the first line.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links... | Read more »
Price of Glory unleashes its 1.4 Alpha u...
As much as we all probably dislike Maths as a subject, we do have to hand it to geometry for giving us the good old Hexgrid, home of some of the best strategy games. One such example, Price of Glory, has dropped its 1.4 Alpha update, stocked full... | Read more »
The SLC 2025 kicks off this month to cro...
Ever since the Solo Leveling: Arise Championship 2025 was announced, I have been looking forward to it. The promotional clip they released a month or two back showed crowds going absolutely nuts for the previous competitions, so imagine the... | Read more »
Dive into some early Magicpunk fun as Cr...
Excellent news for fans of steampunk and magic; the Precursor Test for Magicpunk MMORPG Crystal of Atlan opens today. This rather fancy way of saying beta test will remain open until March 5th and is available for PC - boo - and Android devices -... | Read more »
Prepare to get your mind melted as Evang...
If you are a fan of sci-fi shooters and incredibly weird, mind-bending anime series, then you are in for a treat, as Goddess of Victory: Nikke is gearing up for its second collaboration with Evangelion. We were also treated to an upcoming... | Read more »
Square Enix gives with one hand and slap...
We have something of a mixed bag coming over from Square Enix HQ today. Two of their mobile games are revelling in life with new events keeping them alive, whilst another has been thrown onto the ever-growing discard pile Square is building. I... | Read more »
Let the world burn as you have some fest...
It is time to leave the world burning once again as you take a much-needed break from that whole “hero” lark and enjoy some celebrations in Genshin Impact. Version 5.4, Moonlight Amidst Dreams, will see you in Inazuma to attend the Mikawa Flower... | Read more »
Full Moon Over the Abyssal Sea lands on...
Aether Gazer has announced its latest major update, and it is one of the loveliest event names I have ever heard. Full Moon Over the Abyssal Sea is an amazing name, and it comes loaded with two side stories, a new S-grade Modifier, and some fancy... | Read more »
Open your own eatery for all the forest...
Very important question; when you read the title Zoo Restaurant, do you also immediately think of running a restaurant in which you cook Zoo animals as the course? I will just assume yes. Anyway, come June 23rd we will all be able to start up our... | Read more »
Crystal of Atlan opens registration for...
Nuverse was prominently featured in the last month for all the wrong reasons with the USA TikTok debacle, but now it is putting all that behind it and preparing for the Crystal of Atlan beta test. Taking place between February 18th and March 5th,... | Read more »

Price Scanner via MacPrices.net

AT&T is offering a 65% discount on the ne...
AT&T is offering the new iPhone 16e for up to 65% off their monthly finance fee with 36-months of service. No trade-in is required. Discount is applied via monthly bill credits over the 36 month... Read more
Use this code to get a free iPhone 13 at Visi...
For a limited time, use code SWEETDEAL to get a free 128GB iPhone 13 Visible, Verizon’s low-cost wireless cell service, Visible. Deal is valid when you purchase the Visible+ annual plan. Free... Read more
M4 Mac minis on sale for $50-$80 off MSRP at...
B&H Photo has M4 Mac minis in stock and on sale right now for $50 to $80 off Apple’s MSRP, each including free 1-2 day shipping to most US addresses: – M4 Mac mini (16GB/256GB): $549, $50 off... Read more
Buy an iPhone 16 at Boost Mobile and get one...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering one year of free Unlimited service with the purchase of any iPhone 16. Purchase the iPhone at standard MSRP, and then choose... Read more
Get an iPhone 15 for only $299 at Boost Mobil...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering the 128GB iPhone 15 for $299.99 including service with their Unlimited Premium plan (50GB of premium data, $60/month), or $20... Read more
Unreal Mobile is offering $100 off any new iP...
Unreal Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering a $100 discount on any new iPhone with service. This includes new iPhone 16 models as well as iPhone 15, 14, 13, and SE... Read more
Apple drops prices on clearance iPhone 14 mod...
With today’s introduction of the new iPhone 16e, Apple has discontinued the iPhone 14, 14 Pro, and SE. In response, Apple has dropped prices on unlocked, Certified Refurbished, iPhone 14 models to a... Read more
B&H has 16-inch M4 Max MacBook Pros on sa...
B&H Photo is offering a $360-$410 discount on new 16-inch MacBook Pros with M4 Max CPUs right now. B&H offers free 1-2 day shipping to most US addresses: – 16″ M4 Max MacBook Pro (36GB/1TB/... Read more
Amazon is offering a $100 discount on the M4...
Amazon has the M4 Pro Mac mini discounted $100 off MSRP right now. Shipping is free. Their price is the lowest currently available for this popular mini: – Mac mini M4 Pro (24GB/512GB): $1299, $100... Read more
B&H continues to offer $150-$220 discount...
B&H Photo has 14-inch M4 MacBook Pros on sale for $150-$220 off MSRP. B&H offers free 1-2 day shipping to most US addresses: – 14″ M4 MacBook Pro (16GB/512GB): $1449, $150 off MSRP – 14″ M4... Read more

Jobs Board

All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.