TweetFollow Us on Twitter

Scroll Bar CDEF
Volume Number:5
Issue Number:11
Column Tag:C Workshop

Related Info: Control Manager

Alternate Scroll Bar CDEF

By Alexander S. Colwell, Redondo Beach, CA

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Introduction

Why another CDEF? MacTutor already have several articles relating to the CDEF. Especially relating to is the excellent Designer CDEFs article in April 1989 issue. Having read every single MacTutor issue, I’ve never seen a scroll bar CDEF article containing sample code!

I wanted a scroll bar that has two up and down arrow buttons on both ends of the scroll bar as shown in Figure 1, rather than standard single arrow buttons scroll bar. My primary reason for a dual arrow buttons scroll bar is for large 19-inch screen monitors. I find it’s a real pain to perform simple scrolling function whenever your window is fully zoomed-out. I must pick-up the mouse several times to get the mouse cursor position over the scroll bar’s arrow buttons. Or, I need a large uncluttered desk to navigate the mouse cursor over the scroll bar. Anyway, enough excuses!

Figure 1. CDEF Definition

The scroll bar control definition comprises two sections: control’s messages and control’s color. The messages are described in Inside Macintosh Volume I in Control Manager chapter. I found I had to read the CDEF description in the Control Manager chapter several times before I fully understood it’s implications on certain issues relating to message relationships with the ROM routines. The control’s color is described in the Inside Macintosh Volume V in Control Manager chapter. ( I only had to read this chapter a couple of times relating to the CDEF’s color controls. Either I am getting better or the ROM documentation is getting better. I’m more likely inclined to believe the latter ).

Each of the control messages are described relating to the scroll bar definition. I will not reiterate the same description found in the Control Manager chapter, but I will attempt to describe how the scroll bar definition is related to each of the control messages.

Scroll Bar Layout

Figure 2 shows how the alternate scroll bar layout would appear in the user’s application or desk accessory. This is similar to the Control Manager chapter in Inside Macintosh Volume I description of the standard scroll bar’s parts. The functionality between the standard scroll bar and this alternate scroll bar is identical. The only differences are the appearance of the “up arrow” and “down arrow” control parts.

Figure 2. Entry Point

/* 1 */

pascal long main(varCode, theControl, message, param)
short varCode;   /* Variation ctrl code */
ControlHandle theControl; /* Ctrl hdl */
short message;   /* Ctrl message code   */
long  param;/* Ctrl parameter code */

The scroll bar entry point receives four arguments : varCode, theControl, message, and param. This scroll bar definition does not have any variation. Therefore the varCode argument is nevered used. The “simple button”, “check box”, and “radio button” controls are examples of the variation control code usage.

The theControl variable is the scroll bar’s control handle. This is where the definition keeps all its necessary data structures for various control’s operations.

The message argument informs the scroll bar to perform the necessary control operations. This definition will use all the control messages except autoTrack control message. Each message will be fully described in the following sections.

The param argument is extra information passed with the associated control message. The scroll bar definition code is type-casted the param’s value before using it. For example, the testCntl control message’s param value is “Point” data type while the calcCRgns control message’s param value is “RgnHandle” data type. The usage of the param’s value is described in each of the control message that is used by this scroll bar definition.

drawCntl

The drawCntl control message comprises the largest chunk of code and the most complex portion of the scroll bar definition. The different parts of the scroll bar to be drawn depends on several combination of the CDEF’s param, and ControlRecord’s contrlVis, contrlValue/contrlMin/contrlMax, and contrlHilite variables.

The CDEF’s param variable contains different values for different parts of the scroll bar operations. Note: The param value is type-casted as long word. The actual value is 16-bit low word quantity. This is not clear in the Inside Macintosh I Control Manager chapter but is explained in the Technical Note #196. Each param is described in the following:

param = 0: This indicates that the scroll bar should be completely re-drawned during window’s update or control’s transition from an invisible to visible state.

param = 0xff: This indicates that the scroll bar should transition into unhighlited state. The scroll bar’s “page up” and “page down” and “thumb” parts should be removed from the scroll bar.

param = inPageUp: This indicates that the “page up” region should be re-drawned.

param = inPageDown: This indicates that the “page down” region should be re-drawned.

param = inUpButton: This indicates that the either upper or lower “up arrow” should be highlited or unhighlited. If the contrlHilite value is equal to zero then the “up arrow” should be unhighlited. Otherwise, if the contrlHilite value is equal to non-zero, and if the contrlMin and contrlMax values are not the same value, then it should highlite the “up arrow” button. Note: The altButton variable in the CDEF is used to determined if using the upper or lower arrows for highliting or unhighliting purposes.

param = inDownButton: This indicates that the either upper or lower “down arrow” should be highlited or unhighlited. The highliting rules are the same as the param’s inUpButton case.

testCntl

The testCntl message should check if the scroll bar control is currently visible then it checks if the mouse is within the control’s contrlRect rectangle area by comparing the mouse location specified by the param’s “Point” value.

If the mouse location is within the control’s rectangle area then DSTestControl function is invoked to compare the mouse location with the different parts of the scroll bar : inPageUp, inPageDown, inThumb, both inUpButtons, and both inDownbuttons. If a matching control part is found then it will return the scroll bar’s control part. Otherwise, zero is returned indicating no scroll bar’s part was found. Note: Again, the altButtonvariable is set depending on which of the upper and lower arrow buttons selected for highliting and unhighliting purposes.

calcCRgns

The calcCRgns control message should return the specified scroll bar part’s region. The param’s “RgnHandle” value contains a region handle to be reset to the scroll bar part’s region. However, there are only two cases this control message is invoked.

First case, the whole scroll bar region indicated by the high-order bit of param is set. Note: The param region’s high-order bit should be cleared before operating on the region handle. Otherwise, the CDEF runs a risk of ALA BOMBA country. Technically speaking, the param value should not have high-order bit set in the region handle due to 32-bit mode addressing future implementation. But according to Technical Note #212 the solution for this particular problem is to separate the two cases into calcCntlRgn and calcThumbRgn control messages equivalent to this message for System 7.0 and henceforth versions in 32-bit mode addressing.

The second case is the “thumb” scroll bar part request by TrackControl ROM function. The TrackControl ROM function will invoke the calcCRgns message for the “thumb” outline area to be passed onto the DragGrayRgn ROM function for dragging the “thumb” part of the scroll bar. One extra thing this message should do is set the drag region’s pattern used by the DragGrayRgn routine. I set ltGray pattern into the global DragPattern variable. This is the same pattern used to fill-in the inPageUp and inPageDown control parts.

calcCntlRgn

The calcCntlRgn control message is equivalent to the calcCRgns’s first case.

calcThumbRgn

The calcThumbRgn control message is equivalent to the calcCRgns’s second case.

initCntl

The initCntl control message is where any necessary initialization required by the scroll bar control. Typically, the control definition will allocate one or more data structures to be used during the course of the control’s operations.

This scroll bar will allocate DS handle to be used for the scroll bar’s operation saved into the contrlData variable of the ControlRecord. During the initialization, the black and light gray pattern are initialized. The light gray pattern is used in the “upPage” and “downPage” regions of the scroll bar, and for the “thumb” drag region area. The DS’s hasColor variable is initialized indicating if the monitor has color by using the SysEnvirons’s hasColorQD variable. The scroll bar definition uses this variable to determine if will need to perform color drawing of the scroll bar parts. Finally, the contrlAction variable is initialized to -1L for the TrackControl’s actionProc parameter “thumb” tracking.

The DSInitControl routine will be invoked to initialized the DS data structure. It’s primary job is to compute the size of the “thumb” rectangle area and create the polygon handle equivalent to the “up arrow” and “down arrow” buttons.

dispCntl

The dispCntl control message informs the scroll bar control to release all it’s internal data structures within the controlData handle. This scroll bar will release the polygon handles and the DS handle to the memory manager.

posCntl

The postCntl control message informs the scroll bar definition to re-compute the new “thumb” position and re-draw the scroll bar with the new “thumb” position. The param’s “Point” value contains the local-coordinates point position within the scroll bar’s contrlRect rectangle area. The scroll bar definition will look at the h part of the point for horizontal scroll bar, and use v part of the point for vertical scroll bar orientation.

thumbCntl

The thumbCntl control message informs the scroll bar definition to compute the “thumb” dragging rectangle area. The param value contains a pointer to a data structure described in DragGrayRgn in Window Manager chapter. Its will briefly describe it here:

/* 2 */

struct {         /* Dragging region*/
 Rect limitRect; /* Limit rect scrl*/
 Rect slopRect;  /* Slop rect scrl */
 short axis;     /* Draw axis ctrl */
};

The scroll bar definition will set the axis variable to hAxisOnly constant for horizontal scroll bar or vAxisOnly constant for vertical scroll bar. The limitRect variable is the rectangle area comprising the “upPage” and “downPage” rectangle areas. And, the slopRect variable is the slop area allowed for the mouse to move outside the limit rectangle area.

The slopRect rectangle area require special calculation base on the current mouse position within the “thumb”. Before setting up the limit rectangle area, the limitRect.left and limitRect.top contain the current mouse position. This is saved into temporary mouse point variable to be used in the slop rectangle area calculation. The problem is that the slop rectangle area cannot be the same as the limit rectangle area. Or else, the “thumb” dragging outline will go over the “up arrow” and “down arrow” regions. Hence, the slop rectangle area must be adjusted where the mouse position within the “thumb” rectangle area.

dragCntl

The dragCntl control message informs the scroll bar that the control or the “thumb” is going to be dragged since, the scroll bar has no custom dragging requirements. It returns zero value to inform the Control Manager to use the default dragging method.

autoTrack

The autoTrack control message is not used by the scroll bar definition. Since the initCntl control message initializes the ControlRecord’s contrlAction to -1L value. This will cause the TrackControl call the default control tracking mechanism. Since the dragCntl message always return zero value this control message is never invoked. Note: I had always been confused on the purpose of the dragCntl and autoTrack control message combinations. Perhaps, someone could explain this in Apple’s Technical Note series someday.

Color descriptions

The scroll bar CDEF uses the GetAuxCtl ROM routine to determine how to color different parts of the scroll bar. The CDEF uses four different RGB colors for the control’s frame, body, text, and thumb parts.

The control’s frame color is the outline parts of the scroll bar, arrows, up & down page regions, and thumb. The control’s body color is the inside parts of the arrows, and up & down page regions. The control’s thumb color is the inside part of the thumb. The text color is not used in this scroll bar definition. Note: Standard control buttons uses the control’s text color value.

Accessing the scroll bar’s colors is very easy. The GetAuxCtl ROM call is used to retrieve the scroll bar’s colors. The calling proto-type definition is as follows:

Boolean
  GetAuxCtl(ControlHandle theControl,
       AuxCtlHndl &acHndl);

The function will return TRUE indicator if the scroll bar’s theControl control handle has it’s own copy of the color data set. Otherwise, FALSE indicates the scroll bar using default color data set. The acHndl auxiliary control handle will return the scroll bar’s color data set. To access the frame, body, and thumb RGB colors are shown in the following:

/* 3 */

(*(*acHndl)->acCTable)->
                ctTable[cFrameColor].rgb

(*(*acHndl)->acCTable)->
                ctTable[cBodyColor].rgb

(*(*acHndl)->acCTable)->
                ctTable[cThumbColor].rgb

I recommend reading Inside Macintosh V’s Control Manager chapter on more details relating to the control’s color displays. There are two main color routines relating to the controls : GetAuxCtl and SetCtlColor.

Other CDEF Descriptions

The scroll bar definition uses a weird technique handling black & white and color situations. I defined DSDrawObject to draw various control’s part onto the window. This generic routine simplifies the scroll bar definition without worrying if drawing black & white or color. And, the DSDrawObject routine is coupled with series of macro definitions to perform various drawing operations for the scroll bar.

Finally, I used floating-point to perform various calculations to position the “thumb” properly based on the control’s contrlValue, contrlMin, and contrlMax variables. I could have used fix-integer arithmetic, but I was too lazy to bother with it.

Scroll Bar Demonstration

The scroll bar demonstration is a simple text editor application using new THINK C 4.0 Object Library. It’s not great American word processor, but it is used to illustrate the Alternate Scroll Bar CDEF.

Wrapping Things Up

I did not realize how difficult writing a scroll bar definition was until writing this CDEF example. I am not for sure this is a good alternative scroll bar interface, but it was fun writing it. I believe Apple’s Human Interface Guidelines are excellent set of rules to follow. So how does this scroll bar definition fit into their scheme of things? Probably none. However, several of my associates at work want a scroll bar definition that varies the size of the “thumb” relative to how much visible text (or contents) versus hidden text, but I said “It’s almost impossible, since the CDEF does not have enough information to determine how to vary the ‘thumb’ size.”. Anyway, until then onward to other Mac programming!

/*
 *
 *      Source   - Alternate.c
 *      Author   - Alexander S. Colwell,
 *                 Copyright (C) 1989
 *      Purpose  - This application will demostrate the
 *                 AlternateCDEF scroll bar using THINK
 *                 C 4.0 Object Library.
 * 
 */

#include <Global.h>          /* Global variables      */
#include <CApplication.h>    /* Application defs      */
#include <Commands.h>        /* Command handler defs  */
#include <CBartender.h>      /* Menu handler defs     */
#include <CDecorator.h>      /* Window handler defs   */
#include <CDesktop.h>        /* Window layer hdler def*/
#include <CDocument.h>       /* Document handler defs */
#include <CEditText.h>       /* Text edit handler defs*/
#include <CScrollPane.h>     /* Scrolling pane defs   */

struct CAltDemoApp : CApplication {/* Appl object     */
 void    CreateDocument(void);/* Creat new doc method */
 };

struct CAltDemoDoc : CDocument {/* Document object    */
 void    NewFile(void);      /* Net (bogus) fil method*/
 };

struct CAltDemoPane : CEditText {/* Text pane obj     */
 void    IEditPane(CView *anEnclosure,
                   CBureaucrat *aSupervisor);
 };

#define altWIND 500          /* WIND template res ID  */

                             /* Define external refs  */
extern  CApplication *gApplication;/* Appl object     */
extern  CDecorator   *gDecorator;/* Window object     */
extern  CDesktop     *gDesktop;  /* Desktop object    */
extern  CBartender   *gBartender;/* Menu object       */

void main()
 {
  gApplication = new(CAltDemoApp);/* Creat appln object*/
  gApplication->IApplication(4,4096L,2048L);/* Init it */
  gApplication->Run();       /* Startup application    */
  gApplication->Exit();      /* Return to da “Finder”  */
 }

void CAltDemoApp::CreateDocument()
 {
  CAltDemoDoc *theDocument;  /* New document obj      */

  theDocument = new(CAltDemoDoc);/* Create doc object */
  theDocument->IDocument(this,FALSE);/* Init doc obj  */
  theDocument->NewFile();    /* Create (bogus) doc    */
 }

void CAltDemoDoc::NewFile(void)
 {
  CScrollPane  *theScrollPane;/* Scroll pane object   */
  CAltDemoPane *theMainPane; /* Main pane object      */

  itsWindow = new(CWindow); /* Create window object   */
  itsWindow->IWindow(altWIND,FALSE,gDesktop,this);

                            /* Create scrolling object*/
  theScrollPane = new(CScrollPane);
  theScrollPane->IScrollPane(itsWindow,this,10,10,0,0,
              sizELASTIC,sizELASTIC, TRUE,TRUE,TRUE);
  theScrollPane->FitToEnclFrame(TRUE, TRUE);
  theMainPane = new(CAltDemoPane);
  itsMainPane = theMainPane;
  itsGopher = theMainPane;
  theMainPane->IEditPane(theScrollPane,this);
   theScrollPane->InstallPanorama(theMainPane);

  itsWindow->Select();       /* Select our window now!*/
 }

void CAltDemoPane::IEditPane(CView *anEnclosure,
                             CBureaucrat *aSupervisor)
 {
  Rect    margin;            /* Margin rect area      */

                             /* Setup text edit stuff */
  CEditText::IEditText(anEnclosure,aSupervisor,1,1,0,0,
                       sizELASTIC,sizELASTIC,432);
  FitToEnclosure(TRUE,TRUE);
  SetRect(&margin,2,2,-2,-2);
  ChangeSize(&margin,FALSE);
 }

/*
 *
 *     Source  - AlternateCDEF.c
 *     Author  - Alexander S. Colwell,
 *               Copyright (C) 1988, 1989
 *     Purpose - This is a dual-arrow scroll bar control
 *               definition procedure. It is similiar to
 *               the standard scroll bar except this has
 *               two arrow indicators on both ends.
 */

#include <QuickDraw.h>       /* QuickDraw defs        */
#include <Color.h>           /* Color defs            */
#include <WindowMgr.h>       /* Window Manager defs   */
#include <ControlMgr.h>      /* Control Manager defs  */
#include <ToolBoxUtil.h>     /* Tool Box Utilities    */
#include <ColorToolBox.h>    /* Color Tool Box defs   */

typedef struct {          /* Dual Control          */
   short        hasColor;    /* Has color monitor flag*/
   short        altButton;   /* Using alternate button*/
   Rect         thumb;       /* Thumb rectangle area  */
   Rect         cThumb;      /* Current thmb rect area*/
   PolyHandle   up;          /* Up button handle      */
   PolyHandle   down;        /* Down button handle    */
   short        bLen;        /* Button length         */
   short        hBLen;       /* Half button length    */
   short        sLen;        /* Scroll bar length     */
   double       tFactor;     /* Thumb factor          */
   short        hFactor;     /* Horizontal factor     */
   short        vFactor;     /* Vertical factor       */
   ControlHandle cHdl;       /* Ctrl hdl to reference */
   long         blackPat[2]; /* Black pattern         */
   long         ltGrayPat[2];/* Light gray pattern    */
   } DS;
typedef DS      *DSPTR;
typedef DSPTR   *DSHDL;

typedef struct {         /* Thumb Info            */
   Rect         limitRect;   /* Limit rect scrolling  */
   Rect         slopRect;    /* Slop rect scrolling   */
   short        axis;        /* Drag axis control     */
   } THUMB;
typedef THUMB   *THUMBPTR;
                             /* Misc definitions      */
#define NIL     (0L)         /* NIL pointer           */
#define abs(a)  (a<0?-a:a)   /* Absolute macro func   */
#define min(a,b) (a<b?a:b)   /* Minumim macro function*/
#define max(a,b) (a<b?b:a)   /* Maximum macro function*/

                             /* Trap definitions      */
#define SysEnvironsTrap 0xa090/* System Enviroment    */
#define UnknownTrap     0xa89f/* Unknown instruction  */

                             /* System 7.0 CDEF msgs  */
#define calcCntlRgn  10      /* Calculate ctnl region */
#define calcThumbRgn 11      /* Calculate “thumb” rgn */
                             /* Control’s macro procs */
#define DSFrameHUpBtn()                                \
        DSDrawHBtn(dPtr,dPtr->up,FALSE)
#define DSFrameHDownBtn()                              \
        DSDrawHBtn(dPtr,dPtr->down,FALSE)
#define DSFrameLUpBtn()                                \
        DSDrawLBtn(dPtr,dPtr->up,FALSE)
#define DSFrameLDownBtn()                              \
        DSDrawLBtn(dPtr,dPtr->down,FALSE)
#define DSFillHUpBtn()                                 \
        DSDrawHBtn(dPtr,dPtr->up,TRUE)
#define DSFillHDownBtn()                               \
        DSDrawHBtn(dPtr,dPtr->down,TRUE)
#define DSFillLUpBtn()                                 \
        DSDrawLBtn(dPtr,dPtr->up,TRUE)
#define DSFillLDownBtn()                               \
        DSDrawLBtn(dPtr,dPtr->down,TRUE)

#define DSFrameBody(a)                                 \
        DSDrawObject(dPtr->cHdl,DSGetForeGround,       \
                     DSSetForeGround,DSFrameRect,      \
                     cFrameColor,a)
#define DSClearBody(a)                                 \
        DSDrawObject(dPtr->cHdl,DSGetBackGround,       \
                     DSSetBackGround,DSEraseRect,      \
                     cBodyColor,a)
#define DSFillBody(a)                                  \
        DSDrawObject(dPtr->cHdl,DSGetBackGround,       \
        DSSetBackGround,DSFillRect,cBodyColor,a,       \
        dPtr->ltGrayPat)
#define DSFrameThumb(a)                                \
        DSDrawObject(dPtr->cHdl,DSGetForeGround,       \
                     DSSetForeGround,DSFrameRect,      \
                     cFrameColor,a)
#define DSFillThumb(a)                                 \
        DSDrawObject(dPtr->cHdl,DSGetBackGround,       \
                     DSSetBackGround,DSEraseRect,      \
                     cThumbColor,a)
#define DSFrameArrow(a)                                \
        DSDrawObject(dPtr->cHdl,DSGetForeGround,       \
                     DSSetForeGround,DSFramePoly,      \
                     cFrameColor,a)
#define DSClearArrow(a)                                \
        DSDrawObject(dPtr->cHdl,DSGetBackGround,       \
                     DSSetBackGround,DSErasePoly,      \
                     cBodyColor,a)
#define DSFillArrow(a)                                 \
        DSDrawObject(dPtr->cHdl,DSGetForeGround,       \
                     DSSetForeGround,DSFillPoly,       \
                     cFrameColor,a,dPtr->blackPat)
                             /* Define forward refs   */
void    DSInitControl(),DSDrawThumb(),DSPositionThumb(),
        DSSetupThumb(),DSDrawHBtn(),DSDrawLBtn(),
        DSGetBackGround(),DSGetForeGround(),
        DSSetBackGround(),DSSetForeGround(),
        DSFrameButtons(),DSEraseRect(),DSFrameRect(),
        DSFillRect(),DSErasePoly(),DSFramePoly(),
        DSFillPoly(),DSDrawObject();
long    DSTestControl();

pascal long     main(varCode,theControl,message,param)
 short         varCode;      /* Variable control code */
 ControlHandle theControl;   /* Control handle        */
 short         message;      /* Control message       */
 long          param;        /* Control parameter     */
 {
  ControlPtr   cPtr;         /* Working control ptr   */
  DSHDL        dHdl;         /* Working dual ctrl hdl */
  DSPTR        dPtr = NIL;   /* Working dual ctrl ptr */
  Rect         wRect;        /* Working scroll area   */
  SysEnvRec    sysEnv;       /* Working system envt   */
  long         status = 0;   /* Working status flag   */
      
  HLock(theControl);         /* Lock down the ctrl hdl*/
  cPtr = *theControl;        /* Set control pointer   */
  if (message != initCntl) { /* Check if already init */
   if (cPtr->contrlData) {   /* Check if valid handle */
    HLock(cPtr->contrlData); /* Lock it down for work */
    dPtr = *((DSHDL)cPtr->contrlData);/* Set dual ptr */
   }
  }
  switch(message) {          /* Process specified msg */
   case drawCntl:            /* Draw the control      */
    if (dPtr) {              /* Check if it’s valid   */
     if (cPtr->contrlVis) {  /* Check if it’s visible */
      PenNormal();           /* Set to normal pen     */
      switch(LoWord(param)) {/* Switch on control part*/
       case 0:               /* Re-draw scroll bar    */
        DSInitControl(dPtr,cPtr);/* Re-init it        */
        DSFrameBody(&cPtr->contrlRect);/* Init scroll */
        DSFrameButtons(dPtr);/* Frame the buttons     */
        DSFrameHUpBtn();
        DSFrameHDownBtn();
        DSFrameLUpBtn();
        DSFrameLDownBtn();
        DSDrawThumb(dPtr,theControl); break;
       case 129:             /* Value/Min/Max changed */
        DSDrawThumb(dPtr,theControl); break;
       case 0xff:            /* Control to be inactive*/
        DSSetScrollRgn(dPtr,&wRect);
        DSClearBody(&wRect); break;
       case inPageUp:        /* Hilite scroll bar     */
       case inPageDown:
        DSDrawThumb(dPtr,theControl); break;
       case inUpButton:      /* Hilite high up button */
        if (dPtr->altButton) {/* Check if alt button  */
         if (cPtr->contrlHilite == 0 ||
             cPtr->contrlMin == cPtr->contrlMax)
          DSFrameLUpBtn();
         else
          DSFillLUpBtn();
        }
        else {
         if (cPtr->contrlHilite == 0 ||
             cPtr->contrlMin == cPtr->contrlMax)
          DSFrameHUpBtn();
         else
          DSFillHUpBtn();
        }
        break;
       case inDownButton:    /* Hilite high down buttn*/
        if (dPtr->altButton) {/* Check if alt button  */
         if (cPtr->contrlHilite == 0 ||
             cPtr->contrlMin == cPtr->contrlMax)
          DSFrameLDownBtn();
         else
          DSFillLDownBtn();
        }
        else {
         if (cPtr->contrlHilite == 0 ||
             cPtr->contrlMin == cPtr->contrlMax)
          DSFrameHDownBtn();
         else
          DSFillHDownBtn();
        }
      }
     }
    }
    break;
   case testCntl:            /* Test the control      */
    if (dPtr)                /* Check if ptr valid    */
     if (cPtr->contrlHilite != -1)/* Check if active  */
      if (cPtr->contrlMin != cPtr->contrlMax)
       if (PtInRect(param,&cPtr->contrlRect))
        status = DSTestControl(dPtr,param);/* Find it */
    break;
   case calcCRgns:           /* Calculate ctrl region */
    if (dPtr) {              /* Check if pointer valid*/
     if (!(param & 0x80000000L))/* Check if whole ctrl*/
      RectRgn((Handle)(param & 0x7fffffffL),
              &cPtr->contrlRect);
     else {                  /* Want thumb’s region   */
                             /* Setup thumb’s area    */
      RectRgn((Handle)(param & 0x7fffffffL),
              &dPtr->cThumb);
                             /* Setup drag pattern    */
      BlockMove(dPtr->ltGrayPat,DragPattern,8L);
     }
    }
    break;
   case calcCntlRgn:         /* Calculate cntl region */
    if (dPtr)                /* Check if ptr valid    */
     RectRgn((Handle)(param),&cPtr->contrlRect);
     break;
   case calcThumbRgn:        /* Calculate “thumb” rgn */
    if (dPtr) {              /* Check if pointer valid*/
                             /* Setup thumb’s region  */
     RectRgn((Handle)(param),&dPtr->cThumb);
                             /* Setup drag pattern    */
     BlockMove(dPtr->ltGrayPat,DragPattern,8L);
    }
    break;
   case initCntl:            /* Initialized control   */
                             /* Allocate data handle  */
    if (dHdl = (DSHDL)NewHandle(sizeof(DS))) {
     HLock(dHdl);            /* Lock it down for init */
     dPtr = *dHdl;           /* Set dual control ptr  */
     dPtr->cHdl = theControl;/* Save it for reference */
     dPtr->up = dPtr->down = NIL;/* Init poly handles */
     dPtr->blackPat[0] = 0xffffffffL;/* Init patterns */
     dPtr->blackPat[1] = 0xffffffffL;
     dPtr->ltGrayPat[0] = 0x88228822L;
     dPtr->ltGrayPat[1] = 0x88228822L;
     dPtr->hasColor = FALSE; /* Set to black & white  */
     dPtr->altButton = FALSE;/* Not using alt button  */
                             /* Check SysEnvirons OK  */
     if ((long)NGetTrapAddress(SysEnvironsTrap,OSTrap)!=
         (long)NGetTrapAddress(UnknownTrap,ToolTrap)) {
      SysEnvirons(1,&sysEnv);/* Get system enviroment */
      dPtr->hasColor = sysEnv.hasColorQD;/* Save color*/
     }
     DSInitControl(dPtr,cPtr);/* Init control’s stuff */
     cPtr->contrlAction = (ProcPtr)(-1L);
     cPtr->contrlData = (Handle)dHdl;/* Save data hdl */
    }
    break;
   case dispCntl:            /* Dispose the control   */
    if (dPtr) {              /* Check if pointer valid*/
     if (dPtr->up)           /* Kill the polys        */
      KillPoly(dPtr->up);
     if (dPtr->down)
      KillPoly(dPtr->down);
     HUnlock(cPtr->contrlData);/* Unlock it now       */
     DisposHandle(cPtr->contrlData);/* Return it      */
    }
    cPtr->contrlData = NIL;  /* Clear it              */
    break;
   case posCntl:             /* Re-position control   */
    if (dPtr)                /* Check if pointer valid*/
     DSPositionThumb(dPtr,theControl,param);
    break;
   case thumbCntl:           /* Calculate for dragging*/
    if (dPtr)                /* Check if pointer valid*/
     DSSetupThumb(dPtr,param);/* Setup for dragging   */
    break;
   case dragCntl:            /* Drag the control      */
    status = 0;              /* Only drag thumb!      */
    break;
   case autoTrack:           /* Execute ctrl’s action */
    break;
  }
  if (cPtr->contrlData)      /* Check if valid pointer*/
   HUnlock(cPtr->contrlData);/* Unlock for memory mgr */
  HUnlock(theControl);       /* Unlock control handle */
  return(status);            /* Return status code    */
 }

void    DSInitControl(dPtr,cPtr)
 DSPTR        dPtr;          /* Dual control pointer  */
 ControlPtr   cPtr;          /* Control pointer       */
 {
   PolyHandle pHdl;          /* Working poly handle   */
   short      bLen;          /* Working button length */
   short      hBLen;         /* Working 1/2 button len*/
   short      hLen;          /* Working horizontal len*/
   short      vLen;          /* Working vertical len  */
   short      tmp1,tmp2;     /* Working tmp variables */
   Rect       cRect;         /* Working ctrl rect area*/

   cRect = cPtr->contrlRect; /* Set scroll bar area   */
   InsetRect(&cRect,1,1);    /* Shrink it by one-pixel*/
                             /* Set horz & vert lens  */
   hLen = abs(cRect.right - cRect.left) + 1;
   vLen = abs(cRect.bottom - cRect.top) + 1;
   
   if (hLen > vLen) {        /* Check if horz longer  */
    dPtr->bLen = vLen;       /* Set button length     */
    dPtr->sLen = hLen + 1;   /* Set scroll bar length */
    dPtr->hFactor = 1;       /* Set horizontal factor */
    dPtr->vFactor = 0;       /* Set vertical factor   */
   }
   else {                    /* Nope, must be vertical*/
    dPtr->bLen = hLen;       /* Set button length     */
    dPtr->sLen = vLen + 1;   /* Set scroll bar length */
    dPtr->hFactor = 0;       /* Set horizontal factor */
    dPtr->vFactor = 1;       /* Set vertical factor   */
   }
   bLen = dPtr->bLen;        /* Set button length     */
   hBLen = dPtr->hBLen = bLen / 2;/* Set 1/2 buttn len*/
   dPtr->thumb.top = dPtr->thumb.left = 0;/* Init pt  */
   if (dPtr->hFactor) {      /* Check if horz position*/
    dPtr->thumb.bottom = bLen - 1;
    dPtr->thumb.right = hBLen + hBLen / 2;
   }
   else {                    /* Nope, vert position   */
    dPtr->thumb.bottom = hBLen + hBLen / 2;
    dPtr->thumb.right = bLen - 1;
   }
   tmp1 = hBLen - 1;         /* Set tmp calculations  */
   tmp2 = hBLen - 2;
                             /* Create up poly handle */
   if (pHdl = OpenPoly()) {  /* Check if got poly hdl */
    if (dPtr->hFactor) {     /* Check horz position   */
     MoveTo(0,tmp1);
     LineTo(tmp2,tmp2 * 2 + 1);
     LineTo(tmp2,1);
     LineTo(0,tmp1);
    }
    else {                   /* Nope, vert position   */
     MoveTo(tmp1,0);
     LineTo(1,tmp2);
     LineTo(tmp2 * 2 + 1,tmp2);
     LineTo(tmp1,0);
    }
    ClosePoly();             /* Close the poly handle */
   }
   if (dPtr->up)             /* Check if old poly hdl */
    KillPoly(dPtr->up);      /* Release this poly hdl */
   dPtr->up = pHdl;          /* Set up poly handle    */
                             /* Create down poly hdl  */
   if (pHdl = OpenPoly()) {  /* Check if got poly hdl */
    if (dPtr->hFactor) {     /* Check horz position   */
     MoveTo(tmp2,tmp1);
     LineTo(0,tmp2 * 2 + 1);
     LineTo(0,1);
     LineTo(tmp2,tmp1);
     OffsetPoly(pHdl,hBLen,0);
    }
    else {                   /* Nope,  vert position  */
     MoveTo(1,0);
     LineTo(tmp2 * 2 + 1,0);
     LineTo(tmp1,tmp1);
     LineTo(1,0);
     OffsetPoly(pHdl,0,hBLen);
    }
    ClosePoly();             /* Close the poly handle */
   }
   if (dPtr->down)           /* Check if old poly hdl */
    KillPoly(dPtr->down);    /* Release this poly hdl */
   dPtr->down = pHdl;        /* Set down poly handle  */
  }
   
void    DSCalcThumb(dPtr,cPtr)
 DSPTR       dPtr;           /* Dual control pointer  */
 ControlPtr  cPtr;           /* Control pointer       */
 {
   double    tmp1,tmp2;      /* Working tmp registers */
   short     offset;         /* Working pixel offset  */
   Rect      wRect;          /* Working scroll area   */
   
                             /* Make sure this is min */
   cPtr->contrlMin = min(cPtr->contrlMin, cPtr->contrlMax);
      
                             /* Make sure this is max */
   cPtr->contrlMax = max(cPtr->contrlMin, cPtr->contrlMax);
                            
                             /* Make it min<value<max */
   cPtr->contrlValue = min(cPtr->contrlMax,
           max(cPtr->contrlMin, cPtr->contrlValue));
                                  
   DSSetScrollRgn(dPtr,&wRect);/* Set scroll region   */
                             /* Init thumb factor calc*/
   tmp1 = max(abs(wRect.bottom - wRect.top) * dPtr->vFactor,
              abs(wRect.right - wRect.left) * dPtr->hFactor)
                  - dPtr->bLen + dPtr->hBLen - 2;
   tmp2 = abs(cPtr->contrlMax - cPtr->contrlMin);
   
   dPtr->tFactor = tmp1 / tmp2;/* Set relative factor */
   tmp1 = cPtr->contrlValue - /*Set thumb pixel offset*/
          cPtr->contrlMin;
   tmp2 = tmp1 * dPtr->tFactor;
   offset = tmp2;
   dPtr->cThumb = dPtr->thumb;/* Set thumb rect area  */
   OffsetRect(&dPtr->cThumb, wRect.left + offset * dPtr->hFactor, wRect.top 
+ offset * dPtr->vFactor);
  }

void    DSDrawThumb(dPtr,cHdl)
 DSPTR         dPtr;         /* Dual control pointer  */
 ControlHandle cHdl;         /* Control handle        */
 {
  Rect         tRect;        /* Working thumb area    */
  ControlPtr   cPtr = *cHdl; /* Working control ptr   */
     
  DSSetScrollRgn(dPtr,&tRect);/* Set scroll region    */
  if (cPtr->contrlHilite != 255 &&/* Check if show it */
      cPtr->contrlMax != cPtr->contrlMin) {
  DSCalcThumb(dPtr,cPtr);   /* Re-calculate thumb    */
   ForeColor((long)(blackColor));/* Make it’s b & w   */
   BackColor((long)(whiteColor));
   DSFillBody(&tRect);       /* Fill in scroll bar    */
   tRect = dPtr->cThumb;     /* Set thumb rect area   */
   DSFrameThumb(&tRect);     /* Frame thumb           */
   InsetRect(&tRect,1,1);    /* Inset by one pixel    */
   DSFillThumb(&tRect);      /* Clear inside of thumb */
  }
  else                       /* Nope, don’t want it   */
   DSClearBody(&tRect);      /* Clr scroll region     */
 }
   
void    DSPositionThumb(dPtr,cHdl,pt)
 DSPTR         dPtr;         /* Dual control pointer  */
 ControlHandle cHdl;         /* Control handle        */
 Point         pt;           /* Pt position of thumb  */
 {
  double       offset;       /* Working value offset  */

  if (dPtr->hFactor)         /* Check if horizontal   */
   offset = pt.h;            /* Use horizontal offset */
  else                       /* Nope, it’s vertical   */
   offset = pt.v;            /* Use vertical offset   */
  offset = offset / dPtr->tFactor;/* Reset ctrl value */
  (*cHdl)->contrlValue += offset;
  DSDrawThumb(dPtr,cHdl);    /* Draw da thumb, again! */
 }
   
void    DSSetupThumb(dPtr,thumbPtr)
 DSPTR    dPtr;              /* Dual control pointer  */
 THUMBPTR thumbPtr;          /* Thumb’s info pointer  */
 {
  Point   msePt;             /* Working mouse point   */
      
  msePt.h = thumbPtr->limitRect.left;/* Save mse down */
  msePt.v = thumbPtr->limitRect.top;
  DSSetScrollRgn(dPtr,&thumbPtr->limitRect);/*Set limt*/
  if (dPtr->hFactor) {       /* Check if horz scroll  */
                             /* Adjust it for mse     */
   thumbPtr->limitRect.left += msePt.h - dPtr->cThumb.left;
thumbPtr->limitRect.right -= dPtr->cThumb.right - msePt.h - 1;
                             /* Set slop rect area    */
   thumbPtr->slopRect.top = thumbPtr->limitRect.top - 16;
   thumbPtr->slopRect.bottom = thumbPtr->limitRect.bottom + 16;
   thumbPtr->slopRect.left = -32000;
   thumbPtr->slopRect.right = 32000;
   thumbPtr->axis = hAxisOnly;/* Set axis dragging dir*/
  }
  else {                     /* Nope,  vert scroll bar*/
                             /* Adjust it for mse     */
   thumbPtr->limitRect.top += msePt.v - dPtr->cThumb.top;
  thumbPtr->limitRect.bottom -= dPtr->cThumb.bottom - msePt.v - 1;
                             /* Set slop rect area    */
   thumbPtr->slopRect.left = thumbPtr->limitRect.left - 16;
   thumbPtr->slopRect.right = thumbPtr->limitRect.right + 16;
   thumbPtr->slopRect.top = -32000;
   thumbPtr->slopRect.bottom = 32000;
   thumbPtr->axis = vAxisOnly;/* Set axis dragging dir*/
  }
 }
   
void    DSDrawHBtn(dPtr,btn,fill)

 DSPTR       dPtr;           /* Dual control pointer  */
 PolyHandle  btn;            /* Poly button handle    */
 short       fill;           /* Fill flag indicator   */
   
 {
                             /* Offset where button   */
  OffsetPoly(btn,(*dPtr->cHdl)->contrlRect.left + 1,
                 (*dPtr->cHdl)->contrlRect.top + 1);
  if (fill)                  /* Check if filling arrow*/
   DSFillArrow(btn);         /* Fill in arrow button  */
  else                       /* Nope, not clearing it */
   DSClearArrow(btn);        /* Clear the arrow button*/
  DSFrameArrow(btn);         /* Frame the arrow button*/
                             /* Restore the button    */
  OffsetPoly(btn,-(*dPtr->cHdl)->contrlRect.left - 1,
                 -(*dPtr->cHdl)->contrlRect.top - 1);
 }

void    DSDrawLBtn(dPtr,btn,fill)
 DSPTR       dPtr;           /* Dual control pointer  */
 PolyHandle  btn;            /* Poly button handle    */
 short       fill;           /* Fill flag indicator   */
 {
  short    tmp1,tmp2;        /* Working tmp variables */
  short    offset;           /* Working offset        */
      
  offset = dPtr->sLen - dPtr->bLen - 1;/* Set offset  */
                             /* Offset where button   */
  OffsetPoly(btn,tmp1 = (*dPtr->cHdl)->contrlRect.left + 
       dPtr->hFactor * offset + 1,tmp2 = (*dPtr->cHdl)->contrlRect.top 
+ dPtr->vFactor * offset + 1);
  if (fill)                 /* Check if filling arrow */
   DSFillArrow(btn);        /* Fill in arrow button   */
  else                      /* Nope, not clearing it  */
   DSClearArrow(btn);       /* Clear the arrow button */
  DSFrameArrow(btn);        /* Frame the arrow button */
  OffsetPoly(btn,-tmp1,-tmp2);/* Restore the button   */
 }

void    DSFrameButtons(dPtr)
 DSPTR       dPtr;           /* Dual control pointer  */
 {
  Rect       bRect;          /* Working box rect area */
  short      offset;         /* Working low button    */
      
  bRect.left = bRect.top = 0;/* Setup rect area       */
  bRect.right = bRect.bottom = dPtr->bLen + 1;
                             /* Offset high button box*/
  OffsetRect(&bRect,(*dPtr->cHdl)->contrlRect.left,
                    (*dPtr->cHdl)->contrlRect.top);
  DSClearBody(&bRect);       /* Clear the body part   */
  DSFrameBody(&bRect);       /* Frame high button box */
                             /* Set low button offset */
  offset = dPtr->sLen - dPtr->bLen - 1;
  OffsetRect(&bRect,dPtr->hFactor * offset,
                    dPtr->vFactor * offset);
  DSClearBody(&bRect);       /* Clear the body part   */
  DSFrameBody(&bRect);       /* Frame low button box  */
 }

long    DSTestControl(dPtr,pt)
 DSPTR       dPtr;           /* Dual control pointer  */
 Point       pt;             /* Point position        */
 {
  Rect       cRect;          /* Working control rect  */
  Rect       tRect;          /* Working temp rect area*/
  Rect       bRect;          /* Working button rect   */
  short      offset;         /* Working offset        */
  short      point;          /* Working pt in region  */
  long       status = 0;     /* Working status flag   */
      
  cRect = (*dPtr->cHdl)->contrlRect;/* Set ctrl rect  */
  bRect = dPtr->thumb;       /* Set button rect area  */
  if (dPtr->hFactor)         /* Check if horz button  */
   bRect.right = dPtr->hBLen;/* Adjust for horz button*/
  else
   bRect.bottom = dPtr->hBLen;/* Adjust for vert buttn*/
  tRect = bRect;             /* Set the temp rect area*/
  OffsetRect(&tRect,cRect.left,cRect.top);
  if (PtInRect(pt,&tRect)) { /* Check if high up buttn*/
   status = inUpButton;      /* Set high up button    */
   dPtr->altButton = FALSE;  /* Not using alt button  */
  }
  if (!status) {             /* Check if prev part    */
                             /* Adjust for down button*/
   OffsetRect(&tRect,dPtr->hFactor * dPtr->hBLen,
                     dPtr->vFactor * dPtr->hBLen);
   if (PtInRect(pt,&tRect)) {/* Check if high down    */
    status = inDownButton;   /* Set high down button  */
   dPtr->altButton = FALSE;  /* Not using alt button  */
   }
  }
  if (!status) {             /* Check if prev part    */
   tRect = bRect;            /* Set the temp rect area*/
   offset = dPtr->sLen - dPtr->bLen;
                             /* Offset where low up   */
   OffsetRect(&tRect,cRect.left + dPtr->hFactor*offset,
                     cRect.top + dPtr->vFactor*offset);
   if (PtInRect(pt,&tRect)) {/* Check if low up button*/
    status = inUpButton;     /* Set low up button     */
    dPtr->altButton = TRUE; /* Using alt button       */
   }
  }
  if (!status) {             /* Check if prev part    */
                             /* Offset where low down */
   OffsetRect(&tRect,dPtr->hFactor * dPtr->hBLen,
                     dPtr->vFactor * dPtr->hBLen);
   if (PtInRect(pt,&tRect)) {/* Check if the low down */
    status = inDownButton;  /* Set low down button    */
    dPtr->altButton = TRUE; /* Using alt button       */
   }

  }
  if (!status) {             /* Check if prev part    */
   if (PtInRect(pt,&dPtr->cThumb))/* Check if thumb   */
    status = inThumb;        /* Set thumb part        */
  }
  if (!status) {             /* Check if prev part    */
                             /* Set relative point    */
   point = pt.h * dPtr->hFactor + pt.v * dPtr->vFactor;
                             /* Set relative offset   */
   offset = dPtr->cThumb.left * dPtr->hFactor + 
            dPtr->cThumb.top * dPtr->vFactor;
   if (point > offset)       /* Check if in down page */
    status = inPageDown;     /* Set down page region  */
   else
    status = inPageUp;       /* Set up page region    */
  }
  return(status);            /* Return status part    */
 }
   
DSSetScrollRgn(dPtr,scrollRgn)
  DSPTR   dPtr;              /* Dual control pointer  */
  Rect    *scrollRgn;        /* Scrolling region area */
  {
   *scrollRgn = (*dPtr->cHdl)->contrlRect;/* Set area */
   InsetRect(scrollRgn,1,1);/* Shrink it a bit        */
   if (dPtr->hFactor) {     /* Check if horizontal bar*/
    scrollRgn->left += dPtr->bLen;/* Adjust rect area */
    scrollRgn->right -= dPtr->bLen;
   }
   else {                   /* It’s a vert scroll bar */
    scrollRgn->top += dPtr->bLen;/* Adjust rect area  */
    scrollRgn->bottom -= dPtr->bLen;
   }
  }
   
void    DSGetBackGround(color) 
 RGBColor *color; { GetBackColor(color); }
void    DSGetForeGround(color) 
 RGBColor *color; { GetForeColor(color); }
void    DSSetBackGround(color) 
 RGBColor *color; { RGBBackColor(color); }
void    DSSetForeGround(color) 
 RGBColor *color; { RGBForeColor(color); }
   
void    DSEraseRect(rect) 
 Rect *rect; { EraseRect(rect); }
void    DSFrameRect(rect) 
 Rect *rect; { FrameRect(rect); }
void    DSFillRect(rect,pattern) 
 Rect *rect; Pattern *pattern; {FillRect(rect,pattern);}
void    DSErasePoly(poly) 
 PolyHandle poly; { ErasePoly(poly); }
void    DSFramePoly(poly) 
 PolyHandle poly; { FramePoly(poly); }
void    DSFillPoly(poly,pattern) 
 PolyHandle poly; Pattern *pattern;
 { FillPoly(poly,pattern); }

void    DSDrawObject(cHdl,getGround,setGround,
                     object,color,arg1,arg2)
 ControlHandle cHdl;         /* Control handle        */
 ProcPtr       getGround;    /* Get back/fore grd proc*/
 ProcPtr       setGround;    /* Set back/fore grd proc*/
 ProcPtr       object;       /* Draw object proc      */
 short         color;        /* Color index           */
 long          arg1,arg2;    /* Argument’s parameters */
 {
  AuxCtlHndl   acHdl = NIL;  /* Working aux color hdl */
  RGBColor     oldColor;     /* Working old color     */
  RGBColor     newColor;     /* Working new color     */
                             /* Check if has color    */
  if ((*((DSHDL)((*cHdl)->contrlData)))->hasColor) {
   GetAuxCtl(cHdl,&acHdl);   /* Get control color info*/
   if (acHdl) {              /* Check if really got it*/
    (*getGround)(&oldColor); /* Get back-ground color */
                             /* Get object’s color    */
    newColor =(*(*acHdl)->acCTable)->ctTable[color].rgb;
    (*setGround)(&newColor); /* Set control obj color */
   }
  }
  (*object)(arg1,arg2);      /* Draw the object       */
  if (acHdl)                 /* Check if have aux hdl */
   (*setGround)(&oldColor);  /* Restore back-grd color*/
 }

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Apple GarageBand 10.1.4 - Complete recor...
The new GarageBand is a whole music creation studio right inside your Mac -- complete with keyboard, synths, orchestral and percussion instruments, presets for guitar and voice, an entirely... Read more
Alfred 3.2.1 - Quick launcher for apps a...
Alfred is an award-winning productivity application for OS X. Alfred saves you time when you search for files online or on your Mac. Be more productive with hotkeys, keywords, and file actions at... Read more
Adobe Lightroom 6.8 - Import, develop, a...
Adobe Lightroom is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Lightroom 6 is also available for purchase as a... Read more
Backblaze 4.2.0.990 - Online backup serv...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
OmniPlan Pro 3.6 - Professional-grade pr...
With OmniPlan Pro, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success... Read more
OmniPlan 3.6 - Robust project management...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Little Snitch 3.7.1 - Alerts you about o...
Little Snitch gives you control over your private outgoing data. Track background activity As soon as your computer connects to the Internet, applications often have permission to send any... Read more
iMazing 2.1.3 - Complete iOS device mana...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
AppDelete 4.3.1 - $7.99
AppDelete is an uninstaller that will remove not only applications but also widgets, preference panes, plugins, and screensavers along with their associated files. Without AppDelete these associated... Read more
FileZilla 3.23.0.2 - Fast and reliable F...
FileZilla (ported from Windows) is a fast and reliable FTP client and server with lots of useful features and an intuitive interface. Version 3.23.0.2: Bug Fixes and Minor Changes Speed up icon... Read more

Latest Forum Discussions

See All

Galaxy on Fire 3 and four other fantasti...
Galaxy on Fire 3 - Manticore brings the series back for another round of daring space battles. It's familiar territory for folks who are familiar with the franchise. If you've beaten the game and are looking to broaden your horizons, might we... | Read more »
The best apps for your holiday gift exch...
What's that, you say? You still haven't started your holiday shopping? Don't beat yourself up over it -- a lot of people have been putting it off, too. It's become easier and easier to procrastinate gift shopping thanks to a number of apps that... | Read more »
Toca Hair Salon 3 (Education)
Toca Hair Salon 3 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Winter comes to Darkwood as Seekers Note...
MyTona, based in the chilly Siberian city of Yakutsk, has brought a little festive fun to its hidden object game Seekers Notes: Hidden Mystery. The Christmas update introduces some new inhabitants to players, and with them a chance to win plenty of... | Read more »
Bully: Anniversary Edition (Games)
Bully: Anniversary Edition 1.03.1 Device: iOS Universal Category: Games Price: $6.99, Version: 1.03.1 (iTunes) Description: *** PLEASE NOTE: This game is officially supported on the following devices: iPhone 5 and newer, iPod Touch... | Read more »
PINE GROVE (Games)
PINE GROVE 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: A pine grove where there are no footsteps of people due to continuous missing cases. The case is still unsolved and nothing has... | Read more »
Niantic teases new Pokémon announcement...
After rumors started swirling yesterday, it turns out there is an official Pokémon GO update on its way. We’ll find out what’s in store for us and our growing Pokémon collections tomorrow during the Starbucks event, but Niantic will be revealing... | Read more »
3 reasons why Nicki Minaj: The Empire is...
Nicki Minaj is as business-savvy as she is musically talented and she’s proved that by launching her own game. Designed by Glu, purveyors of other fine celebrity games like cult favorite Kim Kardashian: Hollywood, Nicki Minaj: The Empire launched... | Read more »
Clash of Clans is getting its own animat...
Riding on its unending wave of fame and success, Clash of Clans is getting an animated web series based on its Clash-A-Rama animated shorts.As opposed to the current shorts' 60 second run time, the new and improved Clash-A-Rama will be comprised of... | Read more »
Leaks hint at Pokémon GO and Starbucks C...
Leaked images from a hub for Starbucks employees suggests that a big Pokémon GO event with the coffee giant could begin this very week. The images appeared on Reddit and hint at some exciting new things to come for Niantic's smash hit game. | Read more »

Price Scanner via MacPrices.net

12-inch Retina MacBooks, Apple refurbished, n...
Apple has restocked a full line of Certified Refurbished 2016 12″ Retina MacBooks, now available for $200-$260 off MSRP. Refurbished 2015 models are available starting at $929. Apple will include a... Read more
Holiday sale: 12-inch Retina MacBook for $100...
B&H has 12″ Retina MacBooks on sale for $100 off MSRP as part of their Holiday sale. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1199 $100... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 13″ 1.6GHz/8GB/128GB MacBook Air: $849 $... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more
Apple’s Education discount saves up to $300 o...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free: -... Read more
Back in stock: Apple refurbished Mac minis fr...
Apple has Certified Refurbished Mac minis available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz Mac mini: $419 $80 off MSRP - 2.6GHz Mac... Read more
Twenty-Five Years Of Apple Laptops – A person...
Among many other things, the often tumultuous 16th year of the new century marked the 25th anniversary of Apple laptop computers, not counting the optimistically named 16-pound Mac Portable of 1989.... Read more
Landlordy iOS App Adds Support For Appliances...
Riga, Latvia based E-protect SIA is releasing major update (version 1.8) to its Landlordy app for managing rental business financials on the go. Landlordy is iPhone and iPad app designed for self-... Read more
Holiday sale, Apple iMacs for up to $200 off...
B&H Photo has 21″ and 27″ Apple iMacs on sale for up to $200 off MSRP including free shipping plus NY sales tax only: - 27″ 3.3GHz iMac 5K: $2099 $200 off MSRP - 27″ 3.2GHz/1TB Fusion iMac 5K: $... Read more
Holiday sale: Mac minis for $50 to $100 off M...
B&H Photo has Mac minis on sale for up to $100 off MSRP free shipping plus NY sales tax only: - 1.4GHz Mac mini: $449 $50 off MSRP - 2.6GHz Mac mini: $629 $70 off MSRP - 2.8GHz Mac mini: $899 $... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- Trumbul...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions- Philade...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- San Ant...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Products Tester Needed - Apple (Unit...
…we therefore look forward to put out products to quality test for durability. Apple leads the digital music revolution with its iPods and iTunes online store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.