TweetFollow Us on Twitter

Color Puzzle
Volume Number:4
Issue Number:4
Column Tag:Macintosh II

The Palette Manager & Color Puzzle

By Steven C. Sheets, Contributing Editor

For the next two months, this column is going to be a little different than the previous ones. Normally a new area of Mac // programming is picked each month. That area is discussed, along with it’s implementation and implications, and a sample program is given that demonstrates the concepts in action.

This month’s (much promised) column is on the Palette Manager, while next month’s will be on using the Palette Manager to do Palette Animation. In this article, there will be a explanation of why the Palette Manager is needed and how it works. The basic Palette Manager calls will be explained. Next month, the sample program, PalFun, will be taken apart step by step, explaining the Palette Manager Animation calls and the special effect done using Palette Animation.

Still, every column should have at least one example of code, so presented here is Color Puzzle. It was created back in the days when there was very little truly useful color applications or Desk Accessories. Two Mac-Fanatics wanted to show everyone the real reason they purchase their Mac //s. Their idea of programming was telling this Author that the Color Puzzle was a needed tool. This Author agrees with them!

RGB vs Pixel Space

So far almost all of the drawing explained in this column has been in RGB space. A program picks a specific color, consisting of an 8 bit Red component, an 8 bit Green component and an 8 bit Blue component. The program then draws with this color, using Color Quickdraw commands, to a specific Color Graphics Device (ex. Apple’s Mac // Video Card/Monitor). While most Graphics Devices can display any possible RGB color, most Devices can only display a finite number of colors at any time. This is due to the way the memory of the Mac // Video Devices (ie. Screen) is structured.

Every pixel on the screen has an associated spot in memory. On the older non-Color Macs, this spot in memory was a single bit that designated if the pixel was white or black. On the color Mac //, this spot in memory is a variable size, unsigned integer. The integer contains an index number. That number corresponds to a table of RGB colors (called a Color Look Up Table or CLUT) that the Video card maintains and uses to physically display the screen. If a pixel has a index of 3 in memory, that same pixel is displayed on the Video Card/Monitor using the 3rd color in the Video Card’s CLUT. Changing the pixel index, changes the pixel color on the screen. Color Quickdraw does it’s drawing by manipulation of each pixel’s index.

Obviously the number of colors most card can display is dependent on the amount of memory used for each pixels; 2 to the power of the number of bits per pixels is equal to the number of colors that can be displayed at one time. For example, the initial Apple Video Card has 4 bits per pixels and can only display 16 colors at one time. If someone wants to upgrade the memory on the card using Apple’s Video Expansion Kit to 8 bits per pixel, then the card can display up to 256 colors at one time. 8 Bits per pixel (256 Colors) is currently the most common configuration of Mac // Graphic Cards, though 24 Bit Cards may be just around the corner.

Fig. 1 Our color puzzle in black and white! Pressing the option key brings up the color chooser.

The decision of what colors are to be physically displayed on a card and what RGB values map into which physical color is handled by the Color Manager (not the Quickdraw Manager). When the Mac // is initially booted, the Color Manager normally sets the colors of each Graphics Device to commonly used colors. The Mac //’s default color environment (ie. settings of the CLUT) are sometimes called the “Apple System Colors”. When Color Quickdraw needs to know what index corresponds to the RGB value it wants to draw with, it calls the Color Manager. The Color Manager checks the current status of the Video Card’s CLUT and returns an index value. This is the index of the RGB value closest to the RGB color Color Quickdraw wants to draw with. There may not be a RGB color in the Video Card’s CLUT anywhere close to the requested color. The Color Manager returns the best choise given the current status of the CLUT. For many applications, best choice is good enough. However it is not hard to think of applications that need exact control of the colors used. If the program is an elaborate Drawing or Painting program, the user may want to control the colors himself, allowing more greens for a landscrape, or more flesh tones for a portrait. If the program is a game, the various figures and images may have to be in a specific color. If the program is connected to a video input scanner, the program may want to set the colors of the card to match the colors used by the scanner. The Color Manager allows direct manipulation of each pixel’s colors.

Color Manager vs Palette Manager

After praising the Color Manager for what it can do, the next statement may sound a little strange; NEVER use the Color Manager! Instead use the Palette Manager. The Color Manager would be adequate to use if all programs were written to be the only thing running on a specific system configuration. This is almost never the case. Most programs have to be written to run on any number or size of video cards. Other code segments may be running at the same time that require different colors. Obviously programs under Multifinder needs to share the colors. Even Desk Accessories may need specific colors. Who decides which colors are needed? More importantly, when there is a limited number of bits on the video card, who decided which colors are safe not to include (more than one code segment may want the same color). If video card’s colors change, how does the rest of the system handle this? The Palette Manager is the solution for these problems.

When using the Color Manager, the Manager is manipulating the entire Color Table on a Specific Card (cumbersome). When using the Palette Manager, the Manager is concerned with groups of colors (ie. a Palette) that each specific window needs to display. The Palette Manager calls the Color Manager to select the best choice of colors for each video card (no matter it’s size) that would make all the Palettes happy.

To paraphrase a quote, “You can not make all the palettes happy all the time”. However, a program can make the user happy all the time. Each Palette is associated with a given window. It is logical to give the top most Window (and it’s associated Palette) the highest priority. This is the window the user is currently looking at. If the top most Palette is smaller than the number of colors on a card, other Palettes are used to select the remaining colors. If there are not enough colors for all the Palettes, the top most window has it’s colors selected first.

Using the Palette Manager

There are many ways to create a Palette. The Color Puzzle uses the easiest method to understand. First a Palette Handle is created using NewPalette. NewPalette needs to know the number of entries the Palette will have, the color table it should use to pre-set the colors, and the Usage and Tolerance of the colors. Note: Entries are not really colors at this point as much as there are RGB values that are requested. They are number from 0 (first entry) to N-1 (where there are N number of entries in the Palette).

Color Tables are lists of RGB values that the Mac // uses to set various graphic data structures. When passed to NewPalette, the Palette entries are pre-set using the RGB colors in the table. Once set, the Color Table is not used by the Palette Manager or by that Palette Handle, and can be safely disposed of. If NIL is passed for the color table, the entries in the Palette are set to black. There are no Quickdraw calls or methods to create a color table other than stuffing the values into a handle. Thus NewPalette is normally passed NIL, and the colors are changed after the Palette is created, but before it is attached to a window.

The Colors of the Palette can be set using the SetEntryColor call. SetEntryColor changes the RGB values of a specific entry in a Palette. SetEntryColor is passed the Palette Handle, an index to the entry (0 being the first entry, 1 being the second and so on), and the RGB value to change the entry to. GetEntryColor is the reverse call to retrieve a specific RGB value from an entry. It is passed the Palette Handle, an index to the entry being referenced, and the RGB variable to return the values in.

No matter which method is used to set the Colors of the Entry, always set entry 0 to White (RGB $FFFF,$FFFF,$FFFF) and entry 1 to Black (RGB $0000,$0000,$0000). Do not set any other entries to exactly Black or White. If a program needs an almost black or white shade, use near misses (ex. $0001,$0000,$0000 or $FFFE,$FFFF,$FFFF). To the eye, they will be black or white, but will still be legal to the Palette Manager.

Besides the actual RGB value, each entry has a Usage and Tolerance value associated with it. These values effect exactly how the Palette Manager selects which colors to display in a given instance. There are 4 type of Color Usage; Tolerant, Courteous, Explicit and Animation. Each Usage has a pre-defined constant associated. Each entry’s Usage value must be set to one of these constants. The use of an entry’s Tolerance value is depenent on the Usage setting. Notice that difference between the terms “Tolerance” and “Tolerant”. The Tolerance value is an attribute of an entry, while the Tolerant constant is one of the four type of Usage colors.

A Tolerant Color is used when the window needs to draw a relatively exact RGB Color. How close of a match is needed between the asked for RGB color and the actual color drawn is dependent on the value of Tolerance. A Tolerance of 0 mean the program wants an exact match. If that exact color is not avaliable on the Video Card, then the Palette Manager will change the colors of the card to get that color. If Tolerance is a number, the Palette Manager will check the currently displayed colors on the card. If there is one that is close to the entries RGB value (ie. one where any given difference between the Red, Green or Blue components are less than or more than Tolerance), the Palette Manager will use that color and not reset the card. The majority of the entries in most Palettes have a Usage value of 2 (Tolerant).

A Courteous Color is a place holder. The Tolerance value is ignored. The Palette Manager will not change the colors of a graphic card to get this color. The Manager will deallocate (ie. change that color to a more needed one) other colors first when it is trying to find unused colors. In other words, when talking strictly about Courteous Colors and Color with no usage, the Palette Manager will deallocate RGB colors from a Video Card’s CLUT that are non-usage Colors, before Courteous Colors. Tolerent color will always be deallocated last. Using Courteous Color is also an useful way to store RGB values that the program may want to use (see below).

An Explicit Color is a convenience for programs that want to show what the current color environment is. Instead of having to use the Color Manager to find out the current color environment, a program creates a Palette of colors of usage Explicit (Colors and Tolerance ignored). When drawing with Entry number 0, instead of drawing the RGB value of stored at Entry 0, the color 0 of the Color Device is displayed. This is an ecellent method to show the current CLUT colors. Next Months PalFun has a window that does this. There are a number of Public Domain Desk Accessories that do exactly this. Such tools are invaluable to any programmer who is working with the Palette Manager.

An Animated Color is special tool used for Palette Animation (more next month). For now, realize that when an Animated Color is allocated, that color will only appear on the Window that has the Palette that the color is allocated to. If one Palette allocated a Red Animated Entry (RGB $FFFF,$0000,$F0000), and then another Palette allocated a Red Tolerent Entry (Tolerance 0), another Red would be added to the Video Cards color list instead of using the first colors. When a RGB color is drawn in a window, if that exact color is in the CLUT of the Video Card as an Animated Color, another index will be selected.

Usage and Tolerance are set by NewPalette for the entire Palette or each entries Usage and Tolerance can be set with the SetEntryUsage. SetEntryUsage is passed the Palette Handle, the entry to change, and the Usage and Tolerance values to change the entry to. GetEntryUsage (not used in PalFun) is the reverse call to retrieve a specific Usage and Tolerance values from an entry. It is passed the Palette Handle, the entry to look at, and the Usage and Tolerence variables to return the values in.

One more thing should be mentioned when talking about selecting colors for a Palette. All things being equal, when the Palette Manager wants to set the video colors of a color card (from the current Palette or another Palette, if there are enough colors on the video card), it selects them in a first-come-first-serve order. If there are only enough unalocated colors on the Color Card for half the palette, the first half gets set and the second must must match to the closest colors. If the colors in the Palette were not distributed evenly (ie. All the Oranges first, then then Purples then the Yellow), there would be many shades of the First colors (ie. Orange) and not many shades of the remaining. It is best to distribute the colors evenly over the Palette. Place the best 16 colors first (don’t forget color 0 should be white, and color 1 should be black) so that the window will appears it’s best on a 4 Bit card. If the Palette is the second window, it may get an odd number of color slots given to it. Make the ones given work! Select all the entries so that no matter how many entries are selected, the window will appear at it’s best.

Once the Palette is created using NewPalette, with or without SetEntryColor, SetPalette is used to connect a specific window to the Palette. SetPalette makes a logical connection between the Palette and the Window (ie. This Palette goes with this Window). The call is passed the window pointer, the palette handle, and a boolean flag to indicate if this window needs to be updated whenever the colors change.

To understand the need for an update, imagine what happens when another Window (and it’s Palette) is selected. If there were enough colors on the video card for all windows to get the Colors they need, nothing happens, since the best colors are already selected. If this is not the case (ie. small number available colors on the card and a large number of colors in the window), the Palette Manager changes the video card’s colors to reflect the change in Palette priority. On the video card, RGB values that are used to display some pixels a certain color are suddenly changed. A globe that was a shade of green before, may suddenly be a shade of brown. There still may a different green that would be a better green to draw with, so the window should be redrawn. This way, the window will look it’s best no matter what the current color environment is. Generally all Windows with associated Palettes need to be redrawn when the color selection changes. If the redraw takes too long, or the window has only Animated Colors (more next week on why), then the update flag does not need to be set. Remember this update event is caused by the Palette Manager; a program does not have to have any special code to enact it.

If at any time in the program after the Palette is associated with a window (using SetPalette), an Palette entry’s Color, Usage or Tolerance is changed using SetEntryColor or SetEntryUsage, ActivatePalette (not used in PalFun) needs to be called. This routine is normally called by the Window Manager whenever window status changes (ie. new window comes to front). ActivatePalette is simply passed the window of the Palette that changed, and it will check and handle changing any color on any color cards.

When drawing to a Window that has a Palette associated with it, normal Color Quickdraw commands can be used. This involves setting numerous RGB variables and passing them to Quickdraw calls (ex. Red Globe, Green Globe). Then Color Quickdraw calls the Color Manager to pick a close index. Usually the window already knows which colors to use. The entries in the Palette for each window are the colors that are usually drawn on the windows. PmForeColor and PmBackColor are just like their Color Quickdraw counterparts (RGBForeColor and RGBBackColor); they set the Foreground color and Background color of a Color Port. They are passed the number of some entry in the Palette and set the foreground or background color to the RGB value (ex. Blue Window). This is the only way that an Animated Color or an Explicit Color can be drawn with. Even if the Palette Manager is not used in a program to change the environment, the use of Courteous Colors and the PmForeColor/PmBackColor calls can simplify coding.

Calling NewPalette, SetEntryColor and SetPalette is a good method to use if the RGB entries have to be calculated at run time, and are not known in advance. However there is a simpler method if the colors for a window/Palette are known in advance. Create the Window using a ‘WIND’ resource and the GetWindow call. Also create a resource where the type is ‘pltt’ and the ID number is the same as the ‘WIND’ resource. This ‘pltt’ resource has the Palette information for the Window. When the Window is created in a program, the associate Palette is automatically created and attached to the window. Using this Method with the PmForeColor/PmBackColor calls place the colors of some applications outside the code section for easy editing with ResEdit or some other tool (similar to the reason most programmers place the Text information outside the code section). The format of a ‘pltt’ resource is:

Data Size

Number Colors 2 Bytes (INTEGER)

Internal Data 14 Bytes (set 0)

(for each Color)

Color 6 Bytes (RGB Value/3 INTEGERS)

Usage 2 Bytes (INTEGER)

Tolerance 2 Bytes (INTEGER)

Internal Data 6 Bytes (set 0)

Color Puzzle

The sample code, Color Puzzle, use the Palette Manager to help maintain the colors of each square. It functions like the traditional Puzzle from Apple with some added features. Opening the Desk Accessory with the Option Key down creates a BIG puzzle (for those long phone calls). Clicking on a Square with the Option Key Down will allow the user to change the colors used by the Puzzle. These changes are also saved to disk, so the user will have to live with what he created. Enjoy!

Last Comments

Thanks for all the comments about the various areas/programs discussed in this column. This Author is always open to contacts from other Mac programmers!

PalFun, next month’s sample program, uses most of the Palette Manager calls explained here. It also uses many of the Animation calls that will be covered next month. In the meantime, experiment! To develop a feel for how the Palette Manger works, it is best to manipulate various windows and see how the Palette Manager reacts.

{Color Puzzle DA by Steve Sheets 12/09/87          }
{Desk Accessory to show Puzzle in Color on Mac //.       }
UNIT ColorPuzzleDA;

INTERFACE

 FUNCTION Main (theDCE : DCtlPtr;
 IOPB : ParmBlkPtr;
 driveCall : Integer) : OSErr;

IMPLEMENTATION

 CONST
 DriverOpen = 0;
 DriverPrime = 1;
 DriverControl = 2;
 DriverStatus = 3;
 DriverClose = 4;

 dCtlEnable = 10;

 kLine = 18;

 Edge = 10;
 xSize = 30;
 ySize = 30;
 vOff = -12;

 kxTiles = 4;
 kyTiles = 4;

 optxTiles = 10;
 optyTiles = 10;

 MaxTiles = 10;
 MaxNum = 100;
 RGBMax = 102;

 ResT = ‘RGBs’;

 pmTolerant = $0002;

 HelpWait = 240;
 Flash = 60;

 kWhite = 0;
 kBlack = 1;

 ScrCount = 2000;
 OptScrCount = 10000;

{DA internal variable stored as a single Handle (the Picture, the Window}
{and a Rectange the size of the Picture).}
 TYPE
 BoardData = PACKED ARRAY[1..MaxNum] OF integer;

 PuzzleData = RECORD
 myPal : handle;
 myID, xBig, yBig, numTiles, xTiles, yTiles : integer;
 PuzzleWindow : WindowPtr;
 ColorFlag : Boolean;
 Normal : boolean;
 Board : BoardData;
 END;
 PuzzlePtr = ^PuzzleData;
 PuzzleHandle = ^PuzzlePtr;

 RGBColor = RECORD
 red : INTEGER; { magnitude of red }
 green : INTEGER;{ magnitude of green }
 blue : INTEGER; { magnitude of blue }
 END;

{Format of RGB resource where colors are stored between boots.}
 RGBData = PACKED ARRAY[2..RGBMax] OF RGBColor;
 RGBPtr = ^RGBData;
 RGBHandle = ^RGBPtr;

{Inline Palette Manager & Color Picker calls}

 FUNCTION GetColor (where : Point;
 prompt : Str255;
 inColor : RGBColor;
 VAR outColor : RGBColor) : BOOLEAN;
 INLINE
 $3F3C, $0009, $A82E;

 PROCEDURE PmForeColor (dstEntry : INTEGER);
 INLINE
 $AA97;

 PROCEDURE ActivatePalette (srcWindow : WindowPtr);
 INLINE
 $AA94;

 PROCEDURE PmBackColor (dstEntry : INTEGER);
 INLINE
 $AA98;

 FUNCTION NewPalette (entries : INTEGER;
 srcColors : handle;
 srcUsage, srcTolerance : INTEGER) : handle;
 INLINE
 $AA91;

 PROCEDURE SetPalette (dstWindow : WindowPtr;
 srcPalette : handle;
 cUpdates : BOOLEAN);
 INLINE
 $AA95;

 PROCEDURE DisposePalette (srcPalette : handle);
 INLINE
 $AA93;

{Create a Color Window.}
 FUNCTION NewCWindow (wStorage : Ptr;
 boundsRect : Rect;
 title : Str255;
 visible : BOOLEAN;
 procID : INTEGER;
 behind : WindowPtr;
 goAwayFlag : BOOLEAN;
 refCon : LONGINT) : WindowPtr;
 INLINE
 $AA45;

 PROCEDURE SetEntryColor (dstPalette : Handle;
 dstEntry : INTEGER;
 srcRGB : RGBColor);
 INLINE
 $AA9C;

 PROCEDURE GetEntryColor (srcPalette : Handle;
 srcEntry : INTEGER;
 VAR dstRGB : RGBColor);
 INLINE
 $AA9B;

{Procedure to check if move is legal,  if so, returns move.}
 PROCEDURE DoDir (Dir, xTiles, numTiles : integer;
 VAR UnLegal : boolean;
 VAR CT : integer);
 VAR
 rw : integer;
 BEGIN
 UnLegal := false;
 rw := ((CT - 1) DIV xTiles);
 CASE Dir OF
 1 : 
 BEGIN
 CT := CT - 1;
 IF (((CT - 1) DIV xTiles) <> Rw) OR (CT < 1) THEN
 UnLegal := true;
 END;
 2 : 
 BEGIN
 CT := CT + 1;
 IF (((CT - 1) DIV xTiles) <> Rw) OR (CT > numTiles) THEN
 UnLegal := true;
 END;
 3 : 
 BEGIN
 CT := CT - xTiles;
 IF (CT < 1) THEN
 UnLegal := true;
 END;
 4 : 
 BEGIN
 CT := CT + xTiles;
 IF (CT > numTiles) THEN
 UnLegal := true;
 END;
 OTHERWISE
 UnLegal := true;
 END;
 END;

{DA Open routine:  }
 FUNCTION Open (theDCE : DCtlPtr) : OSErr;
 VAR
 theE : OSErr;
 thePuzzle : PuzzleHandle;
 OldPort : GrafPtr;

{Returns true if the Mac had Color Quickdraw.}
 FUNCTION ColorQDExists : boolean;
 CONST
 ROM85Loc = $28E;
 TwoHighMask = $C000;
 TYPE
 WordPtr = ^INTEGER;
 VAR
 Wd : WordPtr;
 BEGIN
 Wd := POINTER(ROM85Loc);
 ColorQDExists := (BitAnd(Wd^, TwoHighMask) = 0);
 END;

{Is Option Key not Down?}
 FUNCTION IsOptNotDown : BOOLEAN;
 VAR
 theMap : KeyMap;
 BEGIN
 GetKeys(theMap);
 IsOptNotDown := NOT BitTst(@theMap[1], 29);
 END;

{Scrambles the Puzzle info.}
 PROCEDURE ScrambleBoard; {LATER}
 VAR
 count, Dir, CurPos, NewPos, HoldPos, Sc : integer;
 UnLegal : boolean;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 FOR count := 1 TO numTiles DO
 Board[count] := count;

 CurPos := numTiles;
 IF Normal THEN
 sc := ScrCount
 ELSE
 sc := optScrCount;
 FOR count := 1 TO sc DO
 BEGIN
 Dir := (Random MOD 4) + 1;
 REPEAT
 NewPos := CurPos;
 DoDir(Dir, xTiles, numTiles, UnLegal, NewPos);
 IF UnLegal THEN
 BEGIN
 Dir := Dir + 1;
 IF Dir > 4 THEN
 Dir := 1;
 END;
 UNTIL NOT UnLegal;

 HoldPos := Board[CurPos];
 Board[CurPos] := Board[NewPos];
 Board[NewPos] := HoldPos;
 CurPos := NewPos;
 END;
 END;
 END;

{Handle Opening already open windows (ie. either move the DA to the front}
{of the screen or scramble the board).}
 PROCEDURE DAReset;
 VAR
 tmpRect : Rect;
 BEGIN
 thePuzzle := PuzzleHandle(theDCE^.dCtlStorage);
 HLock(theDCE^.dCtlStorage);

 WITH thePuzzle^^ DO
 BEGIN
 IF PuzzleWindow = FrontWindow THEN
 BEGIN
 ScrambleBoard;
 SetPort(PuzzleWindow);
 SetRect(tmpRect, 0, 0, xBig, yBig);
 InvalRect(tmpRect);
 END
 ELSE
 SelectWindow(PuzzleWindow);
 END;
 HUnLock(theDCE^.dCtlStorage);
 END;

{Initialize the DA’s internal data (including creating the Data Handle, 
the Window}
{(Color if needed) and the Rectange the size of the Picture)}
 PROCEDURE DAInit;
 VAR
 tmpRect : Rect;
 insideWindow : WindowPeek;

{Set Puzzle Pal entry to this RGB color}
 PROCEDURE SetPuzzlePal (N, R, G, B : integer);
 VAR
 C : RGBColor;
 BEGIN
 C.red := r;
 C.green := g;
 C.blue := b;
 SetEntryColor(thePuzzle^^.MyPal, n, C);
 END;

{Sets the Colors for Puzzle.}
 PROCEDURE SetPuzzleColor;
 VAR
 count : integer;
 C : RGBColor;
 RGBH : RGBHandle;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 SetPuzzlePal(kWhite, $FFFF, $FFFF, $FFFF);
 SetPuzzlePal(kBlack, 0, 0, 0);

 RGBH := POINTER(GetResource(ResT, MyID));
 IF RGBH = NIL THEN
 BEGIN
 FOR count := 2 TO numTiles DO
 CASE count MOD 6 OF
 0 : 
 SetPuzzlePal(count, $FFFF, 0, 0);
 1 : 
 SetPuzzlePal(count, 0, $FFFF, 0);
 2 : 
 SetPuzzlePal(count, 0, 0, $FFFF);
 3 : 
 SetPuzzlePal(count, $FFFF, $FFFF, 0);
 4 : 
 SetPuzzlePal(count, 0, $FFFF, $FFFF);
 5 : 
 SetPuzzlePal(count, $FFFF, 0, $FFFF);
 OTHERWISE
 END;
 SetPuzzlePal(numTiles + 1, $8888, $8888, $8888);
 SetPuzzlePal(numTiles + 2, $FFFF, 0, $FFFF);
 END
 ELSE
 BEGIN
 FOR count := 2 TO numTiles + 2 DO
 BEGIN
 C := RGBH^^[count];
 SetPuzzlePal(count, C.Red, C.Green, C.Blue);
 END;
 ReleaseResource(POINTER(RGBH));
 END;
 END;
 END;

 BEGIN
 theDCE^.dCtlStorage := NewHandle(SizeOf(PuzzleData));
 HLock(theDCE^.dCtlStorage);
 thePuzzle := PuzzleHandle(theDCE^.dCtlStorage);

 WITH theDCE^, thePuzzle^^ DO
 BEGIN
 myID := theDCE^.dCtlRefNum;
 IF myID > 0 THEN
 myID := -myID;
 myID := $C000 + 32 * (-1 - myID);

 Normal := IsOptNotDown;
 IF Normal THEN
 BEGIN
 xTiles := kxTiles;
 yTiles := kyTiles;
 END
 ELSE
 BEGIN
 myID := myID + 1;

 xTiles := optxTiles;
 yTiles := optyTiles;
 END;
 numTiles := xTiles * yTiles;
 xBig := (xTiles * xSize) + (2 * Edge);
 yBig := (yTiles * ySize) + (2 * Edge);

 ColorFlag := ColorQDExists;

 tmpRect.top := 40;
 tmpRect.left := 40;
 tmpRect.right := tmpRect.left + xBig;
 tmpRect.bottom := tmpRect.top + yBig;

 IF ColorFlag THEN
 BEGIN
 PuzzleWindow := NewCWindow(NIL, tmpRect, ‘Color Puzzle’, true, rDocProc, 
Pointer(-1), True, 0);
 myPal := NewPalette(numTiles + 4, NIL, pmTolerant, 0);
 SetPuzzleColor;
 SetPalette(PuzzleWindow, myPal, true);
 END
 ELSE
 BEGIN
 PuzzleWindow := NewWindow(NIL, tmpRect, ‘B/W Puzzle’, true, rDocProc, 
Pointer(-1), True, 0);
 myPal := NIL;
 END;
 ScrambleBoard;
 insideWindow := WindowPeek(PuzzleWindow);
 insideWindow^.windowKind := dCtlRefNum;
 dCtlWindow := Ptr(PuzzleWindow);
 END;
 HUnLock(theDCE^.dCtlStorage);
 END;

{Main Body of the Open Routine.  If the DA is not open, initialize Puzzle.}
{If there is a puzzle, scamble it.}
 BEGIN
 GetPort(oldPort);
 theE := noErr;

 IF theDCE^.dCtlStorage = NIL THEN
 DAInit
 ELSE
 DAReset;

 Open := theE;
 SetPort(oldPort);
 END;

{DA’s donothing Prime Routine.}
 FUNCTION Prime (theDCE : DCtlPtr;
 IOPB : ParmBlkPtr) : OSErr;
 BEGIN
 Prime := noErr;
 END;

{DA’s Control Routine: Handles Update & Mousedown events.  If the event 
is an}
{Update, draw the Puzzle.  If it is a mousedown in the contents of the 
window,}
{check if the option is down.  If so, reset that Tiles color.  If not, 
see if that}
{is a legal move (and move if it is).  If the event is a keydown, and 
a help key}
{(?,/,h,H,Help) was pressed, display the dedication (who needs help for}
{a Puzzle?).}
 FUNCTION Control (theDCE : DCtlPtr;
 IOPB : ParmBlkPtr) : OSErr;
 CONST
 accEvent = 64;
 accUndo = 68;
 accCut = 70;
 accCopy = 71;
 accPaste = 72;
 accClear = 73;
 VAR
 theEvent : EventRecord;
 thePuzzle : PuzzleHandle;
 aWindow : WindowPtr;
 tmpPat : Pattern;
 oldPort : GrafPtr;

{Given count, return Rect holding count.}
 PROCEDURE GetCountRect (n : integer;
 VAR R : rect);
 VAR
 xn, yn : integer;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 xn := (((n - 1) MOD xTiles) * xSize) + edge;
 yn := (((n - 1) DIV xTiles) * ySize) + edge;
 SetRect(R, xn + 1, yn + 1, xn + xSize, yn + ySize);
 END;
 END;

{Given count, ColorFlag & Rect, draw Tile there.}
 PROCEDURE DrawTile (N : integer;
 VAR R : rect);
 VAR
 S : str255;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 IF (N = numTiles) AND (NOT ColorFlag) THEN
 BEGIN
 EraseRect(R);
 StuffHex(@tmpPat, ‘8800220088002200’);
 FillRect(R, tmpPat);
 END
 ELSE
 BEGIN
 IF ColorFlag THEN
 PmBackColor(N + 1);

 EraseRect(R);

 IF (N <> numTiles) THEN
 BEGIN
 NumToString(N, S);
 MoveTo(R.left + ((xSize - StringWidth(S)) DIV 2), R.bottom + vOff);
 DrawString(S);
 END;
 END;
 END;
 END;

{Draws the board.}
 PROCEDURE DrawBoard;
 VAR
 count, yn, xn : integer;
 tmpRect : rect;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 IF ColorFlag THEN
 PmForeColor(numTiles + 2)
 ELSE
 BEGIN
 StuffHex(@tmpPat, ‘DD77DD77DD77DD77’);
 PenPat(tmpPat);
 END;
 SetRect(tmpRect, 0, 0, xBig, edge);
 PaintRect(tmpRect);
 SetRect(tmpRect, 0, 0, edge, yBig);
 PaintRect(tmpRect);
 SetRect(tmpRect, xBig - edge + 1, 0, xBig, yBig);
 PaintRect(tmpRect);
 SetRect(tmpRect, 0, yBig - edge + 1, xBig, yBig);
 PaintRect(tmpRect);

 IF ColorFlag THEN
 PmForeColor(kBlack)
 ELSE
 BEGIN
 StuffHex(@tmpPat, ‘FFFFFFFFFFFFFFFFFFF’);
 PenPat(tmpPat);
 StuffHex(@tmpPat, ‘0000000000000000’);
 BackPat(tmpPat);
 END;
 yn := (yTiles * ySize);
 xn := (xTiles * xSize);
 FOR count := 0 TO xTiles DO
 BEGIN
 MoveTo(Edge, Edge + (count * ySize));
 Line(xn, 0);
 END;
 FOR count := 0 TO yTiles DO
 BEGIN
 MoveTo(Edge + (count * xSize), Edge);
 Line(0, yn);
 END;

 TextFace([shadow]);
 FOR count := 1 TO numTiles DO
 BEGIN
 GetCountRect(count, tmpRect);
 DrawTile(Board[count], tmpRect)
 END;
 TextFace([]);
 END;
 END;

{Handles the Move.}
 PROCEDURE DoMove (T : integer);
 VAR
 CanMove, UnLegal : boolean;
 tmpRect : Rect;
 CT, temp, nn, Rw, Dir : integer;
 Buf : ARRAY[1..MaxTiles] OF integer;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 CanMove := false;
 Rw := ((T - 1) DIV xTiles);

 Dir := 0;
 REPEAT
 UnLegal := false;
 Dir := Dir + 1;
 nn := 0;
 CT := T;
 REPEAT
 nn := nn + 1;
 Buf[nn] := CT;
 IF Board[CT] = numTiles THEN
 BEGIN
 IF nn = 1 THEN
 UnLegal := true
 ELSE
 CanMove := true;
 END
 ELSE
 DoDir(Dir, xTiles, numTiles, UnLegal, CT);
 UNTIL CanMove OR UnLegal;
 UNTIL CanMove OR (Dir >= 4);

 IF CanMove THEN
 BEGIN
 TextFace([shadow]);
 FOR temp := nn DOWNTO 2 DO
 BEGIN
 Board[Buf[temp]] := Board[Buf[temp - 1]];
 GetCountRect(Buf[temp], tmpRect);
 DrawTile(Board[Buf[temp]], tmpRect)
 END;
 Board[Buf[1]] := numTiles;
 GetCountRect(Buf[1], tmpRect);
 DrawTile(Board[Buf[1]], tmpRect);
 TextFace([]);

 nn := 0;
 REPEAT
 nn := nn + 1;
 UnLegal := (Board[nn] <> nn);
 UNTIL (nn = numTiles) OR UnLegal;
 IF NOT UnLegal THEN
 BEGIN
 SetRect(tmpRect, 0, 0, xBig, yBig);
 IF Normal THEN
 temp := Flash
 ELSE
 temp := Flash DIV 2;
 FOR nn := 1 TO temp DO
 InvertRect(tmpRect);
 SysBeep(1);
 END;
 END;
 END;
 END;

{Save new Color settings to resource}
 PROCEDURE SaveColor (T : integer;
 C : RGBColor);
 VAR
 RGBH : RGBHandle;
 temp : integer;
 BEGIN
 RGBH := POINTER(GetResource(ResT, thePuzzle^^.MyID));
 IF RGBH <> NIL THEN
 BEGIN
 RGBH^^[T] := C;

 ChangedResource(handle(RGBH));
 WriteResource(handle(RGBH));
 ReleaseResource(handle(RGBH));
 END;
 END;

{Handles changing the Color.}
 PROCEDURE DoColor (T : integer);
 VAR
 P : point;
 tmpRect : Rect;
 N : integer;
 C, NewC : RGBColor;
 BEGIN
 WITH thePuzzle^^ DO
 IF (T >= 1) AND (T <= numTiles + 1) THEN
 BEGIN
 P.v := 0;
 P.h := 0;
 IF T = numTiles + 1 THEN
 N := numTiles + 2
 ELSE
 N := Board[T] + 1;
 GetEntryColor(myPal, N, C);
 IF GetColor(P, ‘Pick the Color for this tile:’, C, NewC) THEN
 BEGIN
 SetEntryColor(myPal, N, NewC);
 SaveColor(N, NewC);
 ActivatePalette(PuzzleWindow);
 SetRect(tmpRect, 0, 0, xBig, yBig);
 InvalRect(tmpRect);
 END;
 END;
 END;

{Is the Option key down?}
 FUNCTION OptDown : boolean;
 BEGIN
 OptDown := (BitAnd(optionKey, theEvent.modifiers) <> 0);
 END;

{Handles a Mouse Down.}
 PROCEDURE DoMouse (P : point);
 VAR
 R : Rect;
 C, N : integer;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 GlobalToLocal(P);
 SetRect(R, 0, 0, xBig, yBig);
 IF PtInRect(P, R) THEN
 BEGIN
 N := numTiles + 1;
 C := 0;
 REPEAT
 C := C + 1;
 GetCountRect(C, R);
 IF PtInRect(P, R) THEN
 N := C;
 UNTIL (N <= numTiles) OR (C = numTiles);

 IF OptDown THEN
 BEGIN
 IF ColorFlag THEN
 DoColor(N);
 END
 ELSE IF (N <= numTiles) THEN
 DoMove(N);
 END;
 END;
 END;

{Handles a Key Down (ie. Help).}
 PROCEDURE DoKey;
 VAR
 tempVirtual, v, dv, c : integer;
 tempChar : char;
 tempRect : rect;
 ll : longint;
 count : integer;
 tmpPat : Pattern;

 PROCEDURE ColorBurst (S : str255);
 VAR
 ch : char;
 nn : integer;
 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 MoveTo((xBig - StringWidth(S)) DIV 2, v);
 v := dv + v;
 IF ColorFlag THEN
 FOR nn := 1 TO Length(S) DO
 BEGIN
 ch := S[nn];
 PmForeColor(C);
 c := c + 1;
 IF c = (numTiles + 2) THEN
 C := 2;
 DrawChar(ch);
 END
 ELSE
 DrawString(S);
 END;
 END;

 BEGIN
 WITH thePuzzle^^ DO
 BEGIN
 tempChar := Chr(theEvent.message MOD 256);
 tempVirtual := (theEvent.message DIV 256) MOD 256;
 IF (tempVirtual = $72) OR (tempChar IN [‘?’, ‘/’, ‘H’, ‘h’]) THEN
 BEGIN
 SetRect(tempRect, 0, 0, xBig, yBig);
 IF ColorFlag THEN
 BEGIN
 FOR count := 2 TO NumTiles DO
 BEGIN
 PmBackColor(count);
 EraseRect(tempRect);
 InsetRect(tempRect, 1, 1);
 END;
 PmBackColor(kWhite);
 EraseRect(tempRect);
 END
 ELSE
 BEGIN
 StuffHex(@tmpPat, ‘FFFFFFFFFFFFFFFFFFF’);
 PenPat(tmpPat);
 StuffHex(@tmpPat, ‘0000000000000000’);
 BackPat(tmpPat);
 FOR count := 2 TO NumTiles DO
 BEGIN
 IF (count MOD 2 = 0) THEN
 PaintRect(tempRect)
 ELSE
 EraseRect(tempRect);
 InsetRect(tempRect, 1, 1);
 END;
 EraseRect(tempRect);
 END;

 dv := kLine;
 v := tempRect.top + dv;
 C := 2;

 ColorBurst(‘Color Puzzle 1.0’);
 ColorBurst(‘by’);
 ColorBurst(‘Steve Sheets ‘);
 ColorBurst(‘dedicated to’);
 ColorBurst(‘Fred Bockman’);
 ColorBurst(‘Steve Levinthal ‘);
 Delay(HelpWait, ll);
 SetRect(tempRect, 0, 0, xBig, yBig);
 IF ColorFlag THEN
 PmBackColor(kWhite);
 EraseRect(tempRect);
 InvalRect(tempRect);
 END
 END;
 END;

 BEGIN
 Control := noErr;

 GetPort(oldPort);
 HLock(theDCE^.dCtlStorage);
 thePuzzle := PuzzleHandle(theDCE^.dCtlStorage);
 SetPort(thePuzzle^^.PuzzleWindow);

 CASE IOPB^.csCode OF
 accEvent : {We got an event.}
 BEGIN
 BlockMove(IOPB^.ioMisc, @theEvent, SizeOf(theEvent));
 CASE theEvent.what OF
 updateEvt : 
 BEGIN
 BeginUpdate(WindowPtr(theEvent.message));
 SetPort(WindowPtr(theEvent.message));
 DrawBoard;
 EndUpdate(WindowPtr(theEvent.message));
 END;
 mouseDown : 
 IF FindWindow(theEvent.where, awindow) IN [inSysWindow, inContent] THEN
 IF aWindow = thePuzzle^^.PuzzleWindow THEN
 DoMouse(theEvent.where);
 keyDown, autoKey : 
 DoKey;
 OTHERWISE
 END;   {End of event CASE statement}
 END;
 accUndo, accCut, accCopy, accPaste, accClear : 
 SysBeep(1);
 OTHERWISE
 END;

 HUnLock(Handle(thePuzzle));
 SetPort(oldPort);
 END;

{DA’s donothing Status Routine.}
 FUNCTION Status (theDCE : DCtlPtr;
 IOPB : ParmBlkPtr) : OSErr;
 BEGIN
 Status := noErr;
 END;

{DA’s Close Routine: Dispose of the Palette, the Window Ptr & the}
{Data Handle.}
 FUNCTION Close (theDCE : DCtlPtr;
 IOPB : ParmBlkPtr) : OSErr;
 VAR
 thePuzzle : PuzzleHandle;
 BEGIN
 Close := noErr;

 HLock(theDCE^.dCtlStorage);
 thePuzzle := PuzzleHandle(theDCE^.dCtlStorage);
 WITH thePuzzle^^ DO
 BEGIN
 IF myPal <> NIL THEN
 DisposePalette(myPal);
 DisposeWindow(PuzzleWindow);
 END;
 HUnLock(theDCE^.dCtlStorage);

 IF theDCE^.dCtlRefNum < 0 THEN
 HPurge(Handle(theDCE^.dCtlDriver));

 theDCE^.dCtlWindow := NIL;
 DisposHandle(theDCE^.dCtlStorage);
 theDCE^.dCtlStorage := NIL;
 END;

{Standard LSP Desk Accessory Main Routine}
 FUNCTION Main;
 BEGIN
 CASE driveCall OF
 DriverOpen : 
 Main := Open(theDCE);
 DriverPrime : 
 Main := Prime(theDCE, IOPB);
 DriverControl : 
 BEGIN
 BitClr(@theDCE^.dCtlFlags, 15 - dCtlEnable);
 Main := Control(theDCE, IOPB);
 BitSet(@theDCE^.dCtlFlags, 15 - dCtlEnable);
 END;
 DriverStatus : 
 Main := Status(theDCE, IOPB);
 DriverClose : 
 Main := Close(theDCE, IOPB);
 END;
 END;

END.
/*--------------------------------------------

   ColorPuzzle.r -  Resources for the Color Puzzle DA
   used to store the Palette RGB values between boots.
   
   Steve Sheets 2/3/88
   All rights reserved.

----------------------------------------------*/

#include “Types.r”

data ‘RGBs’ (-16000) {
 $”43D8 95AE FFFF FFFF 8659 9785 4ECA 8BFF”  
 $”06E2 FFFF FFFF 0000 FFFF 0000 FFFF 0000"        
 $”FFFF FFFF FFFF 04E9 0EAE 0000 0000 FFFF”        
 $”0000 FFFF 0000 FFFF 80C7 061A FFFF 0000"        
 $”FFFF 22D4 827A D4FF FFFF 24D3 77A3 A426"        
 $”60C4 FFFF C0FF 6091 0001 8888 8888 8888"        
 $”5282 2638 FFFF”                                
};

data ‘RGBs’ (-15999) {
 $”A5B9 8160 07AB FFFF 038B 0580 FFFF 04D5"        
 $”8295 FFFF 0001 FD8F FFFF 051B FFFF 882A”        
 $”0961 FFFF 0854 828F FFFF 051F FB98 FFFF”        
 $”075A FFFF 7CF0 051B FFFF 0282 0768 FFFF”        
 $”023D 8533 FFFF 046E FAB5 8666 0CCD FFFF”       
 $”FFFF 68F6 68F6 FFFF 6ABA B7C3 FC9B 6556"       
 $”FFFF ACFC 63C2 FFFF 6C10 668D FFFF 6316"       
 $”B628 FFFF 63D7 FFFF FFFF 6556 FFFF B60E”       
 $”6B90 FFFF 714E B0BE FFFF 6661 FFFF F73D”        
 $”66A3 FFFF ADC3 668D 0062 E01F FFFF 8564"        
 $”1979 FFFF FFFF 542D A5B9 8160 07AB FFFF”        
 $”038B 0580 FFFF 04D5 8295 FFFF 0001 FD8F”        
 $”FFFF 051B FFFF 882A 0961 FFFF 0854 828F”        
 $”FFFF 051F FB98 FFFF 075A FFFF 7CF0 051B”       
 $”FFFF 0282 0768 FFFF 023D 8533 FFFF 046E”       
 $”FAB5 8666 0CCD FFFF FFFF 68F6 68F6 FFFF”       
 $”6ABA B7C3 FC9B 6556 FFFF ACFC 63C2 FFFF”     
 $”6C10 668D FFFF 6316 B628 FFFF 63D7 FFFF”     
 $”FFFF 6556 FFFF B60E 6B90 FFFF 714E B0BE”      
 $”FFFF 6661 FFFF F73D 66A3 FFFF ADC3 668D”      
 $”0062 E01F FFFF 8564 1979 FFFF FFFF 542D”     
 $”A5B9 8160 07AB FFFF 038B 0580 FFFF 04D5"      
 $”8295 FFFF 0001 FD8F FFFF 051B FFFF 882A”       
 $”0961 FFFF 0854 828F FFFF 051F FB98 FFFF”      
 $”075A FFFF 7CF0 051B FFFF 0282 0768 FFFF”       
 $”023D 8533 FFFF 046E FAB5 8666 0CCD FFFF”    
 $”FFFF 68F6 68F6 FFFF 6ABA B7C3 FC9B 6556"      
 $”FFFF ACFC 63C2 FFFF 6C10 668D FFFF 6316"      
 $”B628 FFFF 63D7 FFFF FFFF 6556 FFFF B60E”       
 $”6B90 FFFF 714E B0BE FFFF 6661 FFFF F73D”       
 $”66A3 FFFF ADC3 668D FFFF FFFF FFFF FFFF”      
 $”FFFF FFFF FFFF FFFF FFFF 4482 B1D9 0000"      
 $”0000 FFFF 0000 FFFF 0000 FFFF FFFF 0000"      
 $”FFFF 0000 FFFF 0000 FFFF FFFF FFFF 0000"       
 $”0000 0000 0000 FFFF 0000 FFFF 0000 FFFF”       
 $”FFFF 0000 FFFF 0000 FFFF 0000 FFFF FFFF”      
 $”FFFF 0000 0000 0000 0000 FFFF 0000 FFFF”       
 $”0000 8888 8888 8888 1303 9828 FFFF”          
};
 
AAPL
$567.34
Apple Inc.
+42.59
MSFT
$39.37
Microsoft Corpora
-0.32
GOOG
$527.22
Google Inc.
+0.28

MacTech Search:
Community Search:

Software Updates via MacUpdate

Ember 1.5.1 - Versatile digital scrapboo...
Ember (formerly LittleSnapper) is your digital scrapbook of things that inspire you: websites, photos, apps or other things. Just drag in images that you want to keep, organize them into relevant... Read more
Cyberduck 4.4.4 - FTP and SFTP browser....
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
TechTool Pro 7.0.3 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
MacFamilyTree 7.1.6 - Create and explore...
MacFamilyTree gives genealogy a facelift: it's modern, interactive, incredibly fast, and easy to use. We're convinced that generations of chroniclers would have loved to trade in their genealogy... Read more
EtreCheck 1.9.9 - For troubleshooting yo...
EtreCheck is a simple little app to display the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support... Read more
TeamViewer 9.0.28116 - Establish remote...
TeamViewer gives you remote control of any computer or Mac over the Internet within seconds, or can be used for online meetings. Find out why more than 200 million users trust TeamViewer! Free for... Read more
Viber 4.1.0 - Send messages and make cal...
Viber lets you send free messages and make free calls to other Viber users, on any device and network, in any country! Viber syncs your contacts, messages and call history with your mobile device,... Read more
Apple iOS 7.1.1 - The latest version of...
The latest version of iOS can be downloaded through iTunes. Apple iOS 7 brings an all-new design and all-new features. Simplicity Simplicity is often equated with minimalism. Yet true simplicity is... Read more
1Password 4.3 - Powerful password manage...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
Lens Blur 1.3.0 - True out-of-focus boke...
Let Lens Blur transform your existing photo into true SLR-quality out-of-focus bokeh effect! Everyone needs a gorgeous personalized background for a social profile, blog, Web/UI design, presentation... Read more

Latest Forum Discussions

See All

Galaxy Conquerors Review
Galaxy Conquerors Review By Jennifer Allen on April 24th, 2014 Our Rating: :: RETRO SHOOTINGUniversal App - Designed for iPhone and iPad Old school shooting is fun but inaccurate in Galaxy Conquerors.   | Read more »
Yomi Review
Yomi Review By Rob Thomas on April 24th, 2014 Our Rating: :: C-C-C-COMBO BREAKERiPad Only App - Designed for the iPad Round One – Fight! No quarters required for this iOS adaptation of a tabletop adaptation of the arcade fighting... | Read more »
Injustice: Gods Among Us Updated with Ne...
Injustice: Gods Among Us Updated with New Characters, Leaderboards, Gear, and Online Multiplayer Posted by Rob Rich on April 24th, 2014 [ | Read more »
Spin It Review
Spin It Review By Jordan Minor on April 24th, 2014 Our Rating: :: SPIN ME RIGHT ROUNDUniversal App - Designed for iPhone and iPad Spin It has a fine puzzle game model, but its execution lacks energy.   | Read more »
Productivity App NoteSuite is Having its...
Productivity App NoteSuite is Having its Biggest Sale Ever, Just for One Week Posted by Rob Rich on April 24th, 2014 [ permalink ] | Read more »
Wayward Souls Review
Wayward Souls Review By Carter Dotson on April 24th, 2014 Our Rating: :: CARRY ON, WAYWARD SONUniversal App - Designed for iPhone and iPad Wayward Souls is a roguelike-inspired action-RPG that sets a high bar for other games to... | Read more »
The Sandbox Gets Update, Receives New Ca...
The Sandbox Gets Update, Receives New Campaign and New Elements Posted by Tre Lawrence on April 24th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Football Management Simulator One For El...
Football Management Simulator One For Eleven Released Worldwide Today for iOS Posted by Simon Reed on April 24th, 2014 [ permalink ] Free-To-Play football management title One For E | Read more »
Leo’s Fortune Review
Leo’s Fortune Review By Jordan Minor on April 24th, 2014 Our Rating: :: FORTUNATE SONUniversal App - Designed for iPhone and iPad Leo’s Fortune delivers a platforming experience as creative and refined as any console game.   | Read more »
Suited Up (Games)
Suited Up 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Suited Up is a difficult, one-touch platformer that requires players to visualize each jump. The controls in Suited Up are simple,... | Read more »

Price Scanner via MacPrices.net

16GB 1st generation iPad mini available for $...
Radio Shack has a select number of refurbished 1st generation 16GB WiFi iPad minis available for $199.99 on their online store. Choose free shipping or free ship-to-store. We expect these to sell out... Read more
13-inch 2.5GHz MacBook Pro on sale for $100 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $1099 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
iPad Sales “Lull” A Reality Correction Of Unm...
I have lots of time for Jean-Louis Gassée, the former Apple Computer executive (1981 to 1990) who succeeded Steve Jobs as head of Macintosh development when the latter was dismissed in 1985. Mr.... Read more
Apple Makes OS X Betas Available To All – Wit...
Apple’s OS X Beta Seed Program, which lets you install the latest pre-release builds, try it out, and submit your feedback, is now open to anyone who wants to sign on rather than to developers and... Read more
Apple Releases iOS 7.1.1 Update
The latest iOS 7.1.1 update contains improvements, bug fixes and security updates, including: • Further improvements to Touch ID fingerprint recognition • Fixes a bug that could impact keyboard... Read more
Logitech Announces Thinner, Lighter, More Fle...
Logitech has announced an update to its Ultrathin for iPad Air, iPad mini and iPad mini with Retina display, improving the flexibility and design of its award-winning predecessor with an even thinner... Read more
Logitech Introduces Hinge, Big Bang and Turna...
Logitech has announced expansion of its tablet product line with three new cases – the Logitech Hinge, the Logitech Big Bang and the Logitech Turnaround – each for the iPad Air, iPad mini and iPad... Read more
WaterField’s Rough Rider Leather Messenger Ba...
WaterField Designs have announced the new 15-inch size of their popular Rough Rider leather messenger bag, a vintage-looking bag that combines Old West charm and ruggedness with distinctly modern... Read more
New Mac Pro on sale, save $100 on the 4-Core...
J&R has the new 4-Core Mac Pro in stock today and on sale for $2899 including free shipping plus NY sales tax only. Their price is $100 off MSRP, and it’s the lowest price available for this... Read more
Apple refurbished iMacs available for up to $...
The Apple Store has Apple Certified Refurbished 2013 iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. - 27″ 3.4GHz iMac – $1699... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Inc. Research Data Specialist - Appl...
…of Worldwide Market Research & Intelligence. The team is responsible for conducting Apple branded consumer market research. It is also responsible for analyzing data Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.